Skip to content

Commit

Permalink
iwlwifi: mvm: Add FW paging mechanism for the UMAC on PCI
Browse files Browse the repository at this point in the history
Family 8000 products has 2 embedded processors, the first
known as LMAC (lower MAC) and implements the functionality from
previous products, the second one is known as UMAC (upper MAC)
and is used mainly for driver offloads as well as new features.
The UMAC is typically “less” real-time than the LMAC and is used
for higher level controls.
The UMAC's code/data size is estimated to be in the mega-byte arena,
taking into account the code it needs to replace in the driver and
the set of new features.

In order to allow the UMAC to execute code that is bigger than its code
memory, we allow the UMAC embedded processor to page out code pages on
DRAM.

When the device is master on the bus(PCI) the driver saves the UMAC's
image pages in blocks of 32K in the DRAM and sends the layout of the
pages to the FW. The FW can load / unload the pages on its own.

The driver can support up to 1 MB of pages.

Add paging mechanism for the UMAC on PCI in order to allow the program
to use a larger virtual space while using less physical memory on the
device.

Signed-off-by: Eran Harary <eran.harary@intel.com>
Signed-off-by: Matti Gottlieb <matti.gottlieb@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
  • Loading branch information
Matti Gottlieb authored and Emmanuel Grumbach committed Aug 4, 2015
1 parent 75118fd commit a6c4fb4
Show file tree
Hide file tree
Showing 8 changed files with 378 additions and 4 deletions.
32 changes: 31 additions & 1 deletion drivers/net/wireless/iwlwifi/iwl-drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -573,10 +573,11 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
size_t len = ucode_raw->size;
const u8 *data;
u32 tlv_len;
u32 usniffer_img;
enum iwl_ucode_tlv_type tlv_type;
const u8 *tlv_data;
char buildstr[25];
u32 build;
u32 build, paging_mem_size;
int num_of_cpus;
bool usniffer_images = false;
bool usniffer_req = false;
Expand Down Expand Up @@ -955,6 +956,35 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
IWL_UCODE_REGULAR_USNIFFER,
tlv_len);
break;
case IWL_UCODE_TLV_PAGING:
if (tlv_len != sizeof(u32))
goto invalid_tlv_len;
paging_mem_size = le32_to_cpup((__le32 *)tlv_data);

IWL_DEBUG_FW(drv,
"Paging: paging enabled (size = %u bytes)\n",
paging_mem_size);

if (paging_mem_size > MAX_PAGING_IMAGE_SIZE) {
IWL_ERR(drv,
"Paging: driver supports up to %lu bytes for paging image\n",
MAX_PAGING_IMAGE_SIZE);
return -EINVAL;
}

if (paging_mem_size & (FW_PAGING_SIZE - 1)) {
IWL_ERR(drv,
"Paging: image isn't multiple %lu\n",
FW_PAGING_SIZE);
return -EINVAL;
}

drv->fw.img[IWL_UCODE_REGULAR].paging_mem_size =
paging_mem_size;
usniffer_img = IWL_UCODE_REGULAR_USNIFFER;
drv->fw.img[usniffer_img].paging_mem_size =
paging_mem_size;
break;
case IWL_UCODE_TLV_SDIO_ADMA_ADDR:
if (tlv_len != sizeof(u32))
goto invalid_tlv_len;
Expand Down
4 changes: 3 additions & 1 deletion drivers/net/wireless/iwlwifi/iwl-fw-file.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_API_CHANGES_SET = 29,
IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30,
IWL_UCODE_TLV_N_SCAN_CHANNELS = 31,
IWL_UCODE_TLV_PAGING = 32,
IWL_UCODE_TLV_SEC_RT_USNIFFER = 34,
IWL_UCODE_TLV_SDIO_ADMA_ADDR = 35,
IWL_UCODE_TLV_FW_VERSION = 36,
Expand Down Expand Up @@ -343,8 +344,9 @@ enum iwl_ucode_tlv_capa {
* For 16.0 uCode and above, there is no differentiation between sections,
* just an offset to the HW address.
*/
#define IWL_UCODE_SECTION_MAX 12
#define IWL_UCODE_SECTION_MAX 16
#define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC
#define PAGING_SEPARATOR_SECTION 0xAAAABBBB

/* uCode version contains 4 values: Major/Minor/API/Serial */
#define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24)
Expand Down
40 changes: 40 additions & 0 deletions drivers/net/wireless/iwlwifi/iwl-fw.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,53 @@ struct fw_desc {
struct fw_img {
struct fw_desc sec[IWL_UCODE_SECTION_MAX];
bool is_dual_cpus;
u32 paging_mem_size;
};

struct iwl_sf_region {
u32 addr;
u32 size;
};

/*
* Block paging calculations
*/
#define PAGE_2_EXP_SIZE 12 /* 4K == 2^12 */
#define FW_PAGING_SIZE BIT(PAGE_2_EXP_SIZE) /* page size is 4KB */
#define PAGE_PER_GROUP_2_EXP_SIZE 3
/* 8 pages per group */
#define NUM_OF_PAGE_PER_GROUP BIT(PAGE_PER_GROUP_2_EXP_SIZE)
/* don't change, support only 32KB size */
#define PAGING_BLOCK_SIZE (NUM_OF_PAGE_PER_GROUP * FW_PAGING_SIZE)
/* 32K == 2^15 */
#define BLOCK_2_EXP_SIZE (PAGE_2_EXP_SIZE + PAGE_PER_GROUP_2_EXP_SIZE)

/*
* Image paging calculations
*/
#define BLOCK_PER_IMAGE_2_EXP_SIZE 5
/* 2^5 == 32 blocks per image */
#define NUM_OF_BLOCK_PER_IMAGE BIT(BLOCK_PER_IMAGE_2_EXP_SIZE)
/* maximum image size 1024KB */
#define MAX_PAGING_IMAGE_SIZE (NUM_OF_BLOCK_PER_IMAGE * PAGING_BLOCK_SIZE)

#define PAGING_CMD_IS_SECURED BIT(9)
#define PAGING_CMD_IS_ENABLED BIT(8)
#define PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS 0
#define PAGING_TLV_SECURE_MASK 1

/**
* struct iwl_fw_paging
* @fw_paging_phys: page phy pointer
* @fw_paging_block: pointer to the allocated block
* @fw_paging_size: page size
*/
struct iwl_fw_paging {
dma_addr_t fw_paging_phys;
struct page *fw_paging_block;
u32 fw_paging_size;
};

/**
* struct iwl_fw_cscheme_list - a cipher scheme list
* @size: a number of entries
Expand Down
24 changes: 24 additions & 0 deletions drivers/net/wireless/iwlwifi/mvm/fw-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ enum {

LQ_CMD = 0x4e,

/* paging block to FW cpu2 */
FW_PAGING_BLOCK_CMD = 0x4f,

/* Scan offload */
SCAN_OFFLOAD_REQUEST_CMD = 0x51,
SCAN_OFFLOAD_ABORT_CMD = 0x52,
Expand Down Expand Up @@ -370,6 +373,27 @@ struct iwl_nvm_access_cmd {
u8 data[];
} __packed; /* NVM_ACCESS_CMD_API_S_VER_2 */

#define NUM_OF_FW_PAGING_BLOCKS 33 /* 32 for data and 1 block for CSS */

/*
* struct iwl_fw_paging_cmd - paging layout
*
* (FW_PAGING_BLOCK_CMD = 0x4f)
*
* Send to FW the paging layout in the driver.
*
* @flags: various flags for the command
* @block_size: the block size in powers of 2
* @block_num: number of blocks specified in the command.
* @device_phy_addr: virtual addresses from device side
*/
struct iwl_fw_paging_cmd {
__le32 flags;
__le32 block_size;
__le32 block_num;
__le32 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS];
} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_1 */

/**
* struct iwl_nvm_access_resp_ver2 - response to NVM_ACCESS_CMD
* @offset: offset in bytes into the section
Expand Down
Loading

0 comments on commit a6c4fb4

Please sign in to comment.