diff options
Diffstat (limited to 'drivers/net/wireless/rsi/rsi_91x_hal.c')
| -rw-r--r-- | drivers/net/wireless/rsi/rsi_91x_hal.c | 264 |
1 files changed, 217 insertions, 47 deletions
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 182b06629371..7d26314a3e76 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2014 Redpine Signals Inc. * * Permission to use, copy, modify, and/or distribute this software for any @@ -31,6 +31,13 @@ static struct ta_metadata metadata_flash_content[] = { }; +static struct ta_metadata metadata[] = {{"pmemdata_dummy", 0x00000000}, + {"rsi/rs9116_wlan.rps", 0x00000000}, + {"rsi/rs9116_wlan_bt_classic.rps", 0x00000000}, + {"rsi/pmemdata_dummy", 0x00000000}, + {"rsi/rs9116_wlan_bt_classic.rps", 0x00000000} +}; + int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; @@ -100,6 +107,9 @@ int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) mgmt_desc->frame_type = TX_DOT11_MGMT; mgmt_desc->header_len = MIN_802_11_HDR_LEN; mgmt_desc->xtend_desc_size = header_size - FRAME_DESC_SZ; + + if (ieee80211_is_probe_req(wh->frame_control)) + mgmt_desc->frame_info = cpu_to_le16(RSI_INSERT_SEQ_IN_FW); mgmt_desc->frame_info |= cpu_to_le16(RATE_INFO_ENABLE); if (is_broadcast_ether_addr(wh->addr1)) mgmt_desc->frame_info |= cpu_to_le16(RSI_BROADCAST_PKT); @@ -152,12 +162,16 @@ int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) u8 header_size; u8 vap_id = 0; u8 dword_align_bytes; + bool tx_eapol; u16 seq_num; info = IEEE80211_SKB_CB(skb); vif = info->control.vif; tx_params = (struct skb_info *)info->driver_data; + tx_eapol = IEEE80211_SKB_CB(skb)->control.flags & + IEEE80211_TX_CTRL_PORT_CTRL_PROTO; + header_size = FRAME_DESC_SZ + sizeof(struct rsi_xtended_desc); if (header_size > skb_headroom(skb)) { rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); @@ -193,7 +207,7 @@ int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) wh->frame_control |= cpu_to_le16(RSI_SET_PS_ENABLE); if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) && - (common->secinfo.security_enable)) { + tx_params->have_key) { if (rsi_is_cipher_wep(common)) ieee80211_size += 4; else @@ -204,22 +218,24 @@ int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) RSI_WIFI_DATA_Q); data_desc->header_len = ieee80211_size; - if (common->min_rate != RSI_RATE_AUTO) { + if (common->rate_config[common->band].fixed_enabled) { /* Send fixed rate */ + u16 fixed_rate = common->rate_config[common->band].fixed_hw_rate; + data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE); - data_desc->rate_info = cpu_to_le16(common->min_rate); + data_desc->rate_info = cpu_to_le16(fixed_rate); if (conf_is_ht40(&common->priv->hw->conf)) data_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE); - if ((common->vif_info[0].sgi) && (common->min_rate & 0x100)) { + if (common->vif_info[0].sgi && (fixed_rate & 0x100)) { /* Only MCS rates */ data_desc->rate_info |= cpu_to_le16(ENABLE_SHORTGI_RATE); } } - if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { + if (tx_eapol) { rsi_dbg(INFO_ZONE, "*** Tx EAPOL ***\n"); data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE); @@ -238,7 +254,8 @@ int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) rsi_set_len_qno(&data_desc->len_qno, (skb->len - FRAME_DESC_SZ), RSI_WIFI_MGMT_Q); - if ((skb->len - header_size) == EAPOL4_PACKET_LEN) { + if (((skb->len - header_size) == EAPOL4_PACKET_LEN) || + ((skb->len - header_size) == EAPOL4_PACKET_LEN - 2)) { data_desc->misc_flags |= RSI_DESC_REQUIRE_CFM_TO_HOST; xtend_desc->confirm_frame_type = EAPOL4_CONFIRM; @@ -282,7 +299,6 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) struct rsi_hw *adapter = common->priv; struct ieee80211_vif *vif; struct ieee80211_tx_info *info; - struct ieee80211_bss_conf *bss; int status = -EINVAL; if (!skb) @@ -294,11 +310,10 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) if (!info->control.vif) goto err; vif = info->control.vif; - bss = &vif->bss_conf; if (((vif->type == NL80211_IFTYPE_STATION) || (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && - (!bss->assoc)) + (!vif->cfg.assoc)) goto err; status = rsi_send_pkt_to_bus(common, skb); @@ -323,7 +338,6 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; - struct ieee80211_bss_conf *bss; struct ieee80211_hdr *wh; struct ieee80211_tx_info *info; struct skb_info *tx_params; @@ -348,13 +362,13 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, return status; } - bss = &info->control.vif->bss_conf; wh = (struct ieee80211_hdr *)&skb->data[header_size]; mgmt_desc = (struct rsi_mgmt_desc *)skb->data; xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ]; /* Indicate to firmware to give cfm for probe */ - if (ieee80211_is_probe_req(wh->frame_control) && !bss->assoc) { + if (ieee80211_is_probe_req(wh->frame_control) && + !info->control.vif->cfg.assoc) { rsi_dbg(INFO_ZONE, "%s: blocking mgmt queue\n", __func__); mgmt_desc->misc_flags = RSI_DESC_REQUIRE_CFM_TO_HOST; @@ -410,7 +424,7 @@ out: int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) { - struct rsi_hw *adapter = (struct rsi_hw *)common->priv; + struct rsi_hw *adapter = common->priv; struct rsi_data_desc *bcn_frm; struct ieee80211_hw *hw = common->priv->hw; struct ieee80211_conf *conf = &hw->conf; @@ -431,7 +445,7 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) return -EINVAL; mac_bcn = ieee80211_beacon_get_tim(adapter->hw, vif, - &tim_offset, NULL); + &tim_offset, NULL, 0); if (!mac_bcn) { rsi_dbg(ERR_ZONE, "Failed to get beacon from mac80211\n"); return -EINVAL; @@ -459,9 +473,9 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) } if (common->band == NL80211_BAND_2GHZ) - bcn_frm->bbp_info |= cpu_to_le16(RSI_RATE_1); + bcn_frm->rate_info |= cpu_to_le16(RSI_RATE_1); else - bcn_frm->bbp_info |= cpu_to_le16(RSI_RATE_6); + bcn_frm->rate_info |= cpu_to_le16(RSI_RATE_6); if (mac_bcn->data[tim_offset + 2] == 0) bcn_frm->frame_info |= cpu_to_le16(RSI_DATA_DESC_DTIM_BEACON); @@ -476,10 +490,10 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) static void bl_cmd_timeout(struct timer_list *t) { - struct rsi_hw *adapter = from_timer(adapter, t, bl_cmd_timer); + struct rsi_hw *adapter = timer_container_of(adapter, t, bl_cmd_timer); adapter->blcmd_timer_expired = true; - del_timer(&adapter->bl_cmd_timer); + timer_delete(&adapter->bl_cmd_timer); } static int bl_start_cmd_timer(struct rsi_hw *adapter, u32 timeout) @@ -497,7 +511,7 @@ static int bl_stop_cmd_timer(struct rsi_hw *adapter) { adapter->blcmd_timer_expired = false; if (timer_pending(&adapter->bl_cmd_timer)) - del_timer(&adapter->bl_cmd_timer); + timer_delete(&adapter->bl_cmd_timer); return 0; } @@ -612,6 +626,7 @@ static int bl_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp, char *str) bl_start_cmd_timer(adapter, timeout); status = bl_write_cmd(adapter, cmd, exp_resp, ®out_val); if (status < 0) { + bl_stop_cmd_timer(adapter); rsi_dbg(ERR_ZONE, "%s: Command %s (%0x) writing failed..\n", __func__, str, cmd); @@ -727,10 +742,9 @@ static int ping_pong_write(struct rsi_hw *adapter, u8 cmd, u8 *addr, u32 size) } status = bl_cmd(adapter, cmd_req, cmd_resp, str); - if (status) { - bl_stop_cmd_timer(adapter); + if (status) return status; - } + return 0; } @@ -818,30 +832,27 @@ static int auto_fw_upgrade(struct rsi_hw *adapter, u8 *flash_content, status = bl_cmd(adapter, EOF_REACHED, FW_LOADING_SUCCESSFUL, "EOF_REACHED"); - if (status) { - bl_stop_cmd_timer(adapter); + if (status) return status; - } + rsi_dbg(INFO_ZONE, "FW loading is done and FW is running..\n"); return 0; } -static int rsi_load_firmware(struct rsi_hw *adapter) +static int rsi_hal_prepare_fwload(struct rsi_hw *adapter) { - struct rsi_common *common = adapter->priv; struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; - const struct firmware *fw_entry = NULL; - u32 regout_val = 0, content_size; - u16 tmp_regout_val = 0; - struct ta_metadata *metadata_p; + u32 regout_val = 0; int status; bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT); while (!adapter->blcmd_timer_expired) { status = hif_ops->master_reg_read(adapter, SWBL_REGOUT, - ®out_val, 2); + ®out_val, + RSI_COMMON_REG_SIZE); if (status < 0) { + bl_stop_cmd_timer(adapter); rsi_dbg(ERR_ZONE, "%s: REGOUT read failed\n", __func__); return status; @@ -862,15 +873,28 @@ static int rsi_load_firmware(struct rsi_hw *adapter) (regout_val & 0xff)); status = hif_ops->master_reg_write(adapter, SWBL_REGOUT, - (REGOUT_INVALID | REGOUT_INVALID << 8), - 2); - if (status < 0) { + (REGOUT_INVALID | + REGOUT_INVALID << 8), + RSI_COMMON_REG_SIZE); + if (status < 0) rsi_dbg(ERR_ZONE, "%s: REGOUT writing failed..\n", __func__); - return status; - } - mdelay(1); + else + rsi_dbg(INFO_ZONE, + "===> Device is ready to load firmware <===\n"); - status = bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS, + return status; +} + +static int rsi_load_9113_firmware(struct rsi_hw *adapter) +{ + struct rsi_common *common = adapter->priv; + const struct firmware *fw_entry = NULL; + u32 content_size; + u16 tmp_regout_val = 0; + struct ta_metadata *metadata_p; + int status; + + status = bl_cmd(adapter, AUTO_READ_MODE, CMD_PASS, "AUTO_READ_CMD"); if (status < 0) return status; @@ -899,13 +923,15 @@ static int rsi_load_firmware(struct rsi_hw *adapter) /* Get the firmware version */ common->lmac_ver.ver.info.fw_ver[0] = - fw_entry->data[LMAC_VER_OFFSET] & 0xFF; + fw_entry->data[LMAC_VER_OFFSET_9113] & 0xFF; common->lmac_ver.ver.info.fw_ver[1] = - fw_entry->data[LMAC_VER_OFFSET + 1] & 0xFF; - common->lmac_ver.major = fw_entry->data[LMAC_VER_OFFSET + 2] & 0xFF; + fw_entry->data[LMAC_VER_OFFSET_9113 + 1] & 0xFF; + common->lmac_ver.major = + fw_entry->data[LMAC_VER_OFFSET_9113 + 2] & 0xFF; common->lmac_ver.release_num = - fw_entry->data[LMAC_VER_OFFSET + 3] & 0xFF; - common->lmac_ver.minor = fw_entry->data[LMAC_VER_OFFSET + 4] & 0xFF; + fw_entry->data[LMAC_VER_OFFSET_9113 + 3] & 0xFF; + common->lmac_ver.minor = + fw_entry->data[LMAC_VER_OFFSET_9113 + 4] & 0xFF; common->lmac_ver.patch_num = 0; rsi_print_version(common); @@ -958,7 +984,7 @@ fw_upgrade: } rsi_dbg(ERR_ZONE, "Firmware upgrade failed\n"); - status = bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS, + status = bl_cmd(adapter, AUTO_READ_MODE, CMD_PASS, "AUTO_READ_MODE"); if (status) goto fail; @@ -974,19 +1000,163 @@ fail: return status; } +static int rsi_load_9116_firmware(struct rsi_hw *adapter) +{ + struct rsi_common *common = adapter->priv; + struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; + const struct firmware *fw_entry; + struct ta_metadata *metadata_p; + u8 *ta_firmware, *fw_p; + struct bootload_ds bootload_ds; + u32 instructions_sz, base_address; + u16 block_size = adapter->block_size; + u32 dest, len; + int status, cnt; + + rsi_dbg(INIT_ZONE, "***** Load 9116 TA Instructions *****\n"); + + if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) { + status = bl_cmd(adapter, POLLING_MODE, CMD_PASS, + "POLLING_MODE"); + if (status < 0) + return status; + } + + status = hif_ops->master_reg_write(adapter, MEM_ACCESS_CTRL_FROM_HOST, + RAM_384K_ACCESS_FROM_TA, + RSI_9116_REG_SIZE); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s: Unable to access full RAM memory\n", + __func__); + return status; + } + + metadata_p = &metadata[adapter->priv->coex_mode]; + rsi_dbg(INIT_ZONE, "%s: loading file %s\n", __func__, metadata_p->name); + status = request_firmware(&fw_entry, metadata_p->name, adapter->device); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s: Failed to open file %s\n", + __func__, metadata_p->name); + return status; + } + + ta_firmware = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); + if (!ta_firmware) { + status = -ENOMEM; + goto fail_release_fw; + } + fw_p = ta_firmware; + instructions_sz = fw_entry->size; + rsi_dbg(INFO_ZONE, "FW Length = %d bytes\n", instructions_sz); + + common->lmac_ver.major = ta_firmware[LMAC_VER_OFFSET_9116]; + common->lmac_ver.minor = ta_firmware[LMAC_VER_OFFSET_9116 + 1]; + common->lmac_ver.release_num = ta_firmware[LMAC_VER_OFFSET_9116 + 2]; + common->lmac_ver.patch_num = ta_firmware[LMAC_VER_OFFSET_9116 + 3]; + common->lmac_ver.ver.info.fw_ver[0] = + ta_firmware[LMAC_VER_OFFSET_9116 + 4]; + + if (instructions_sz % FW_ALIGN_SIZE) + instructions_sz += + (FW_ALIGN_SIZE - (instructions_sz % FW_ALIGN_SIZE)); + rsi_dbg(INFO_ZONE, "instructions_sz : %d\n", instructions_sz); + + if (*(u16 *)fw_p == RSI_9116_FW_MAGIC_WORD) { + memcpy(&bootload_ds, fw_p, sizeof(struct bootload_ds)); + fw_p += le16_to_cpu(bootload_ds.offset); + rsi_dbg(INFO_ZONE, "FW start = %x\n", *(u32 *)fw_p); + + cnt = 0; + do { + rsi_dbg(ERR_ZONE, "%s: Loading chunk %d\n", + __func__, cnt); + + dest = le32_to_cpu(bootload_ds.bl_entry[cnt].dst_addr); + len = le32_to_cpu(bootload_ds.bl_entry[cnt].control) & + RSI_BL_CTRL_LEN_MASK; + rsi_dbg(INFO_ZONE, "length %d destination %x\n", + len, dest); + + status = hif_ops->load_data_master_write(adapter, dest, + len, + block_size, + fw_p); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "Failed to load chunk %d\n", cnt); + break; + } + fw_p += len; + if (le32_to_cpu(bootload_ds.bl_entry[cnt].control) & + RSI_BL_CTRL_LAST_ENTRY) + break; + cnt++; + } while (1); + } else { + base_address = metadata_p->address; + status = hif_ops->load_data_master_write(adapter, + base_address, + instructions_sz, + block_size, + ta_firmware); + } + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Unable to load %s blk\n", + __func__, metadata_p->name); + goto fail_free_fw; + } + + rsi_dbg(INIT_ZONE, "%s: Successfully loaded %s instructions\n", + __func__, metadata_p->name); + + if (adapter->rsi_host_intf == RSI_HOST_INTF_SDIO) { + if (hif_ops->ta_reset(adapter)) + rsi_dbg(ERR_ZONE, "Unable to put ta in reset\n"); + } else { + if (bl_cmd(adapter, JUMP_TO_ZERO_PC, + CMD_PASS, "JUMP_TO_ZERO") < 0) + rsi_dbg(INFO_ZONE, "Jump to zero command failed\n"); + else + rsi_dbg(INFO_ZONE, "Jump to zero command successful\n"); + } + +fail_free_fw: + kfree(ta_firmware); +fail_release_fw: + release_firmware(fw_entry); + + return status; +} + int rsi_hal_device_init(struct rsi_hw *adapter) { struct rsi_common *common = adapter->priv; + int status; switch (adapter->device_model) { case RSI_DEV_9113: - if (rsi_load_firmware(adapter)) { + status = rsi_hal_prepare_fwload(adapter); + if (status < 0) + return status; + if (rsi_load_9113_firmware(adapter)) { rsi_dbg(ERR_ZONE, "%s: Failed to load TA instructions\n", __func__); return -EINVAL; } break; + case RSI_DEV_9116: + status = rsi_hal_prepare_fwload(adapter); + if (status < 0) + return status; + if (rsi_load_9116_firmware(adapter)) { + rsi_dbg(ERR_ZONE, + "%s: Failed to load firmware to 9116 device\n", + __func__); + return -EINVAL; + } + break; default: return -EINVAL; } |
