summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c11
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c12
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h3
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c73
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h13
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c46
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c11
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h3
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c6
-rw-r--r--drivers/net/wireless/ath/ath6kl/bmi.h3
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c6
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.c16
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h36
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_pipe.c32
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c90
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c17
-rw-r--r--drivers/net/wireless/ath/ath6kl/usb.c7
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c72
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_mac.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h10
-rw-r--r--drivers/net/wireless/ath/ath9k/spectral.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c34
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c58
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c42
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c22
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c6
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h26
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c21
-rw-r--r--drivers/net/wireless/b43/main.c149
-rw-r--r--drivers/net/wireless/b43/main.h1
-rw-r--r--drivers/net/wireless/b43/phy_lcn.c35
-rw-r--r--drivers/net/wireless/b43/phy_n.c1113
-rw-r--r--drivers/net/wireless/b43/phy_n.h15
-rw-r--r--drivers/net/wireless/b43/radio_2057.c420
-rw-r--r--drivers/net/wireless/b43/radio_2057.h10
-rw-r--r--drivers/net/wireless/b43/tables_nphy.c176
-rw-r--r--drivers/net/wireless/b43/xmit.c7
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/Makefile1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c23
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/chip.c28
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd.h5
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c196
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h74
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c13
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c274
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/feature.c136
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/feature.h86
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/firmware.c5
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/firmware.h5
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c100
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h4
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c49
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c958
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.c37
-rw-r--r--drivers/net/wireless/brcm80211/include/brcm_hw_ids.h60
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig25
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-8000.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-config.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-modparams.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h21
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex.c193
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex_legacy.c119
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c104
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h67
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c15
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c383
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h52
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c24
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.c89
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tt.c12
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c10
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c202
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c11
-rw-r--r--drivers/net/wireless/mwifiex/11n.c3
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c27
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c8
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c40
-rw-r--r--drivers/net/wireless/mwifiex/fw.h2
-rw-r--r--drivers/net/wireless/mwifiex/join.c8
-rw-r--r--drivers/net/wireless/mwifiex/main.c16
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c14
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c15
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c2
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c2
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c10
-rw-r--r--drivers/net/wireless/mwifiex/tdls.c22
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c4
-rw-r--r--drivers/net/wireless/ti/wl12xx/main.c2
-rw-r--r--drivers/net/wireless/ti/wl18xx/cmd.c89
-rw-r--r--drivers/net/wireless/ti/wl18xx/cmd.h19
-rw-r--r--drivers/net/wireless/ti/wl18xx/event.c65
-rw-r--r--drivers/net/wireless/ti/wl18xx/event.h2
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c34
-rw-r--r--drivers/net/wireless/ti/wl18xx/tx.c7
-rw-r--r--drivers/net/wireless/ti/wl18xx/wl18xx.h2
-rw-r--r--drivers/net/wireless/ti/wlcore/Makefile2
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.c12
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.h3
-rw-r--r--drivers/net/wireless/ti/wlcore/debugfs.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/hw_ops.h27
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c103
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/vendor_cmd.c197
-rw-r--r--drivers/net/wireless/ti/wlcore/vendor_cmd.h45
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore.h8
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore_i.h20
-rw-r--r--drivers/net/wireless/zd1211rw/Kconfig4
115 files changed, 4949 insertions, 1924 deletions
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index d185dc0cd12b..4333107ecf37 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -603,16 +603,19 @@ static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
if (ret)
return ret;
- src_ring->hw_index =
- ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
- src_ring->hw_index &= nentries_mask;
+ read_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
+ if (read_index == 0xffffffff)
+ return -ENODEV;
+
+ read_index &= nentries_mask;
+ src_ring->hw_index = read_index;
ath10k_pci_sleep(ar);
}
read_index = src_ring->hw_index;
- if ((read_index == sw_index) || (read_index == 0xffffffff))
+ if (read_index == sw_index)
return -EIO;
sbase = src_ring->shadow_base;
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index e6c56c5bb0f6..93adb8c58969 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -802,7 +802,7 @@ int ath10k_core_start(struct ath10k *ar)
INIT_LIST_HEAD(&ar->arvifs);
- if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
+ if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) {
ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
ar->hw_params.name,
ar->target_version,
@@ -811,6 +811,12 @@ int ath10k_core_start(struct ath10k *ar)
ar->fw_api,
ar->htt.target_version_major,
ar->htt.target_version_minor);
+ ath10k_info("debug %d debugfs %d tracing %d dfs %d\n",
+ config_enabled(CONFIG_ATH10K_DEBUG),
+ config_enabled(CONFIG_ATH10K_DEBUGFS),
+ config_enabled(CONFIG_ATH10K_TRACING),
+ config_enabled(CONFIG_ATH10K_DFS_CERTIFIED));
+ }
__set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags);
@@ -988,7 +994,9 @@ err_unregister_mac:
err_release_fw:
ath10k_core_free_firmware_files(ar);
err:
- device_release_driver(ar->dev);
+ /* TODO: It's probably a good idea to release device from the driver
+ * but calling device_release_driver() here will cause a deadlock.
+ */
return;
}
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 68ceef61933d..83a5fa91531d 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -290,6 +290,9 @@ struct ath10k_debug {
struct ath_dfs_pool_stats dfs_pool_stats;
u32 fw_dbglog_mask;
+
+ u8 htt_max_amsdu;
+ u8 htt_max_ampdu;
};
enum ath10k_state {
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 1b7ff4ba122c..3030158c478e 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -671,6 +671,72 @@ static const struct file_operations fops_htt_stats_mask = {
.llseek = default_llseek,
};
+static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ char buf[64];
+ u8 amsdu = 3, ampdu = 64;
+ unsigned int len;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->debug.htt_max_amsdu)
+ amsdu = ar->debug.htt_max_amsdu;
+
+ if (ar->debug.htt_max_ampdu)
+ ampdu = ar->debug.htt_max_ampdu;
+
+ mutex_unlock(&ar->conf_mutex);
+
+ len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ int res;
+ char buf[64];
+ unsigned int amsdu, ampdu;
+
+ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
+
+ /* make sure that buf is null terminated */
+ buf[sizeof(buf) - 1] = 0;
+
+ res = sscanf(buf, "%u %u", &amsdu, &ampdu);
+
+ if (res != 2)
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ res = ath10k_htt_h2t_aggr_cfg_msg(&ar->htt, ampdu, amsdu);
+ if (res)
+ goto out;
+
+ res = count;
+ ar->debug.htt_max_amsdu = amsdu;
+ ar->debug.htt_max_ampdu = ampdu;
+
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return res;
+}
+
+static const struct file_operations fops_htt_max_amsdu_ampdu = {
+ .read = ath10k_read_htt_max_amsdu_ampdu,
+ .write = ath10k_write_htt_max_amsdu_ampdu,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static ssize_t ath10k_read_fw_dbglog(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@@ -757,6 +823,9 @@ void ath10k_debug_stop(struct ath10k *ar)
* warning from del_timer(). */
if (ar->debug.htt_stats_mask != 0)
cancel_delayed_work(&ar->debug.htt_stats_dwork);
+
+ ar->debug.htt_max_amsdu = 0;
+ ar->debug.htt_max_ampdu = 0;
}
static ssize_t ath10k_write_simulate_radar(struct file *file,
@@ -867,6 +936,10 @@ int ath10k_debug_create(struct ath10k *ar)
debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_htt_stats_mask);
+ debugfs_create_file("htt_max_amsdu_ampdu", S_IRUSR | S_IWUSR,
+ ar->debug.debugfs_phy, ar,
+ &fops_htt_max_amsdu_ampdu);
+
debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_fw_dbglog);
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 9a263462c793..6c93f3885ee5 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -240,16 +240,10 @@ struct htt_oob_sync_req {
__le16 rsvd0;
} __packed;
-#define HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_MASK 0x1F
-#define HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_LSB 0
-
struct htt_aggr_conf {
u8 max_num_ampdu_subframes;
- union {
- /* dont use bitfields; undefined behaviour */
- u8 flags; /* see %HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_ */
- u8 max_num_amsdu_subframes:5;
- } __packed;
+ /* amsdu_subframes is limited by 0x1F mask */
+ u8 max_num_amsdu_subframes;
} __packed;
#define HTT_MGMT_FRM_HDR_DOWNLOAD_LEN 32
@@ -1343,6 +1337,9 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt);
int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie);
int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt);
+int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
+ u8 max_subfrms_ampdu,
+ u8 max_subfrms_amsdu);
void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt);
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt);
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 7064354d1f4f..accb6b4f6faf 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -307,6 +307,52 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
return 0;
}
+int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
+ u8 max_subfrms_ampdu,
+ u8 max_subfrms_amsdu)
+{
+ struct htt_aggr_conf *aggr_conf;
+ struct sk_buff *skb;
+ struct htt_cmd *cmd;
+ int len;
+ int ret;
+
+ /* Firmware defaults are: amsdu = 3 and ampdu = 64 */
+
+ if (max_subfrms_ampdu == 0 || max_subfrms_ampdu > 64)
+ return -EINVAL;
+
+ if (max_subfrms_amsdu == 0 || max_subfrms_amsdu > 31)
+ return -EINVAL;
+
+ len = sizeof(cmd->hdr);
+ len += sizeof(cmd->aggr_conf);
+
+ skb = ath10k_htc_alloc_skb(len);
+ if (!skb)
+ return -ENOMEM;
+
+ skb_put(skb, len);
+ cmd = (struct htt_cmd *)skb->data;
+ cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_AGGR_CFG;
+
+ aggr_conf = &cmd->aggr_conf;
+ aggr_conf->max_num_ampdu_subframes = max_subfrms_ampdu;
+ aggr_conf->max_num_amsdu_subframes = max_subfrms_amsdu;
+
+ ath10k_dbg(ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d",
+ aggr_conf->max_num_amsdu_subframes,
+ aggr_conf->max_num_ampdu_subframes);
+
+ ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+
+ return 0;
+}
+
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
{
struct device *dev = htt->ar->dev;
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index d0004d59c97e..06840d101c45 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1362,8 +1362,6 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr);
}
- init_completion(&xfer.done);
-
ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0);
if (ret)
goto err_resp;
@@ -1414,10 +1412,7 @@ static void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state)
&nbytes, &transfer_id))
return;
- if (xfer->wait_for_resp)
- return;
-
- complete(&xfer->done);
+ xfer->tx_done = true;
}
static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
@@ -1438,7 +1433,7 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
}
xfer->resp_len = nbytes;
- complete(&xfer->done);
+ xfer->rx_done = true;
}
static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
@@ -1451,7 +1446,7 @@ static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
ath10k_pci_bmi_send_done(tx_pipe);
ath10k_pci_bmi_recv_data(rx_pipe);
- if (completion_done(&xfer->done))
+ if (xfer->tx_done && (xfer->rx_done == xfer->wait_for_resp))
return 0;
schedule();
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index dfdebb4157aa..940129209990 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -38,7 +38,8 @@
#define DIAG_TRANSFER_LIMIT 2048
struct bmi_xfer {
- struct completion done;
+ bool tx_done;
+ bool rx_done;
bool wait_for_resp;
u32 resp_len;
};
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 4b7782a529ac..6f83cae57655 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2106,7 +2106,6 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_cmd_hdr *cmd_hdr;
enum wmi_event_id id;
- u16 len;
cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
@@ -2114,8 +2113,6 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb)
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
return;
- len = skb->len;
-
trace_ath10k_wmi_event(id, skb->data, skb->len);
switch (id) {
@@ -2225,7 +2222,6 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_cmd_hdr *cmd_hdr;
enum wmi_10x_event_id id;
- u16 len;
cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
@@ -2233,8 +2229,6 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
return;
- len = skb->len;
-
trace_ath10k_wmi_event(id, skb->data, skb->len);
switch (id) {
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.h b/drivers/net/wireless/ath/ath6kl/bmi.h
index 18fdd69e1f71..397a52f2628b 100644
--- a/drivers/net/wireless/ath/ath6kl/bmi.h
+++ b/drivers/net/wireless/ath/ath6kl/bmi.h
@@ -242,7 +242,8 @@ struct ath6kl_bmi_target_info {
(void) (check_type == val); \
addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \
ret = ath6kl_bmi_read(ar, addr, (u8 *) &tmp, 4); \
- *val = le32_to_cpu(tmp); \
+ if (!ret) \
+ *val = le32_to_cpu(tmp); \
ret; \
})
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 1c4ce8e3eebe..e535807c3d89 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -2899,7 +2899,8 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (info->inactivity_timeout) {
inactivity_timeout = info->inactivity_timeout;
- if (ar->hw.flags & ATH6KL_HW_AP_INACTIVITY_MINS)
+ if (test_bit(ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS,
+ ar->fw_capabilities))
inactivity_timeout = DIV_ROUND_UP(inactivity_timeout,
60);
@@ -3782,7 +3783,8 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
ath6kl_band_5ghz.ht_cap.ht_supported = false;
}
- if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) {
+ if (test_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES,
+ ar->fw_capabilities)) {
ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c
index b0b652042760..0df74b245af4 100644
--- a/drivers/net/wireless/ath/ath6kl/core.c
+++ b/drivers/net/wireless/ath/ath6kl/core.c
@@ -123,6 +123,22 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
/* FIXME: we should free all firmwares in the error cases below */
+ /*
+ * Backwards compatibility support for older ar6004 firmware images
+ * which do not set these feature flags.
+ */
+ if (ar->target_type == TARGET_TYPE_AR6004 &&
+ ar->fw_api <= 4) {
+ __set_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES,
+ ar->fw_capabilities);
+ __set_bit(ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS,
+ ar->fw_capabilities);
+
+ if (ar->hw.id == AR6004_HW_1_3_VERSION)
+ __set_bit(ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT,
+ ar->fw_capabilities);
+ }
+
/* Indicate that WMI is enabled (although not ready yet) */
set_bit(WMI_ENABLED, &ar->flag);
ar->wmi = ath6kl_wmi_init(ar);
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 26b0f92424e1..2b78c863d030 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -136,6 +136,21 @@ enum ath6kl_fw_capability {
*/
ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL,
+ /* WMI_SET_TX_SELECT_RATES_CMDID uses 64 bit size rate table */
+ ATH6KL_FW_CAPABILITY_64BIT_RATES,
+
+ /* WMI_AP_CONN_INACT_CMDID uses minutes as units */
+ ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS,
+
+ /* use low priority endpoint for all data */
+ ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT,
+
+ /* ratetable is the 2 stream version (max MCS15) */
+ ATH6KL_FW_CAPABILITY_RATETABLE_MCS15,
+
+ /* firmare doesn't support IP checksumming */
+ ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM,
+
/* this needs to be last */
ATH6KL_FW_CAPABILITY_MAX,
};
@@ -149,15 +164,13 @@ struct ath6kl_fw_ie {
};
enum ath6kl_hw_flags {
- ATH6KL_HW_64BIT_RATES = BIT(0),
- ATH6KL_HW_AP_INACTIVITY_MINS = BIT(1),
- ATH6KL_HW_MAP_LP_ENDPOINT = BIT(2),
ATH6KL_HW_SDIO_CRC_ERROR_WAR = BIT(3),
};
#define ATH6KL_FW_API2_FILE "fw-2.bin"
#define ATH6KL_FW_API3_FILE "fw-3.bin"
#define ATH6KL_FW_API4_FILE "fw-4.bin"
+#define ATH6KL_FW_API5_FILE "fw-5.bin"
/* AR6003 1.0 definitions */
#define AR6003_HW_1_0_VERSION 0x300002ba
@@ -215,8 +228,21 @@ enum ath6kl_hw_flags {
#define AR6004_HW_1_3_VERSION 0x31c8088a
#define AR6004_HW_1_3_FW_DIR "ath6k/AR6004/hw1.3"
#define AR6004_HW_1_3_FIRMWARE_FILE "fw.ram.bin"
-#define AR6004_HW_1_3_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin"
-#define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin"
+#define AR6004_HW_1_3_TCMD_FIRMWARE_FILE "utf.bin"
+#define AR6004_HW_1_3_UTF_FIRMWARE_FILE "utf.bin"
+#define AR6004_HW_1_3_TESTSCRIPT_FILE "nullTestFlow.bin"
+#define AR6004_HW_1_3_BOARD_DATA_FILE AR6004_HW_1_3_FW_DIR "/bdata.bin"
+#define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE AR6004_HW_1_3_FW_DIR "/bdata.bin"
+
+/* AR6004 3.0 definitions */
+#define AR6004_HW_3_0_VERSION 0x31C809F8
+#define AR6004_HW_3_0_FW_DIR "ath6k/AR6004/hw3.0"
+#define AR6004_HW_3_0_FIRMWARE_FILE "fw.ram.bin"
+#define AR6004_HW_3_0_TCMD_FIRMWARE_FILE "utf.bin"
+#define AR6004_HW_3_0_UTF_FIRMWARE_FILE "utf.bin"
+#define AR6004_HW_3_0_TESTSCRIPT_FILE "nullTestFlow.bin"
+#define AR6004_HW_3_0_BOARD_DATA_FILE AR6004_HW_3_0_FW_DIR "/bdata.bin"
+#define AR6004_HW_3_0_DEFAULT_BOARD_DATA_FILE AR6004_HW_3_0_FW_DIR "/bdata.bin"
/* Per STA data, used in AP mode */
#define STA_PS_AWAKE BIT(0)
diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
index 756fe52a12c8..ca1a18c86c0d 100644
--- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c
+++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
@@ -1170,8 +1170,12 @@ static int htc_wait_recv_ctrl_message(struct htc_target *target)
static void htc_rxctrl_complete(struct htc_target *context,
struct htc_packet *packet)
{
- /* TODO, can't really receive HTC control messages yet.... */
- ath6kl_dbg(ATH6KL_DBG_HTC, "%s: invalid call function\n", __func__);
+ struct sk_buff *skb = packet->skb;
+
+ if (packet->endpoint == ENDPOINT_0 &&
+ packet->status == -ECANCELED &&
+ skb != NULL)
+ dev_kfree_skb(skb);
}
/* htc pipe initialization */
@@ -1678,7 +1682,29 @@ static void ath6kl_htc_pipe_activity_changed(struct htc_target *target,
static void ath6kl_htc_pipe_flush_rx_buf(struct htc_target *target)
{
- /* TODO */
+ struct htc_endpoint *endpoint;
+ struct htc_packet *packet, *tmp_pkt;
+ int i;
+
+ for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
+ endpoint = &target->endpoint[i];
+
+ spin_lock_bh(&target->rx_lock);
+
+ list_for_each_entry_safe(packet, tmp_pkt,
+ &endpoint->rx_bufq, list) {
+ list_del(&packet->list);
+ spin_unlock_bh(&target->rx_lock);
+ ath6kl_dbg(ATH6KL_DBG_HTC,
+ "htc rx flush pkt 0x%p len %d ep %d\n",
+ packet, packet->buf_len,
+ packet->endpoint);
+ dev_kfree_skb(packet->pkt_cntxt);
+ spin_lock_bh(&target->rx_lock);
+ }
+
+ spin_unlock_bh(&target->rx_lock);
+ }
}
static int ath6kl_htc_pipe_credit_setup(struct htc_target *target,
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 8ee7097f0b25..fffd52355123 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -93,8 +93,7 @@ static const struct ath6kl_hw hw_list[] = {
.board_addr = 0x433900,
.refclk_hz = 26000000,
.uarttx_pin = 11,
- .flags = ATH6KL_HW_64BIT_RATES |
- ATH6KL_HW_AP_INACTIVITY_MINS,
+ .flags = 0,
.fw = {
.dir = AR6004_HW_1_0_FW_DIR,
@@ -114,8 +113,7 @@ static const struct ath6kl_hw hw_list[] = {
.board_addr = 0x43d400,
.refclk_hz = 40000000,
.uarttx_pin = 11,
- .flags = ATH6KL_HW_64BIT_RATES |
- ATH6KL_HW_AP_INACTIVITY_MINS,
+ .flags = 0,
.fw = {
.dir = AR6004_HW_1_1_FW_DIR,
.fw = AR6004_HW_1_1_FIRMWARE_FILE,
@@ -134,8 +132,7 @@ static const struct ath6kl_hw hw_list[] = {
.board_addr = 0x435c00,
.refclk_hz = 40000000,
.uarttx_pin = 11,
- .flags = ATH6KL_HW_64BIT_RATES |
- ATH6KL_HW_AP_INACTIVITY_MINS,
+ .flags = 0,
.fw = {
.dir = AR6004_HW_1_2_FW_DIR,
@@ -152,20 +149,43 @@ static const struct ath6kl_hw hw_list[] = {
.board_ext_data_addr = 0x437000,
.reserved_ram_size = 7168,
.board_addr = 0x436400,
- .refclk_hz = 40000000,
+ .refclk_hz = 0,
.uarttx_pin = 11,
- .flags = ATH6KL_HW_64BIT_RATES |
- ATH6KL_HW_AP_INACTIVITY_MINS |
- ATH6KL_HW_MAP_LP_ENDPOINT,
+ .flags = 0,
.fw = {
.dir = AR6004_HW_1_3_FW_DIR,
.fw = AR6004_HW_1_3_FIRMWARE_FILE,
+ .tcmd = AR6004_HW_1_3_TCMD_FIRMWARE_FILE,
+ .utf = AR6004_HW_1_3_UTF_FIRMWARE_FILE,
+ .testscript = AR6004_HW_1_3_TESTSCRIPT_FILE,
},
.fw_board = AR6004_HW_1_3_BOARD_DATA_FILE,
.fw_default_board = AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE,
},
+ {
+ .id = AR6004_HW_3_0_VERSION,
+ .name = "ar6004 hw 3.0",
+ .dataset_patch_addr = 0,
+ .app_load_addr = 0x1234,
+ .board_ext_data_addr = 0,
+ .reserved_ram_size = 7168,
+ .board_addr = 0x436400,
+ .testscript_addr = 0,
+ .flags = 0,
+
+ .fw = {
+ .dir = AR6004_HW_3_0_FW_DIR,
+ .fw = AR6004_HW_3_0_FIRMWARE_FILE,
+ .tcmd = AR6004_HW_3_0_TCMD_FIRMWARE_FILE,
+ .utf = AR6004_HW_3_0_UTF_FIRMWARE_FILE,
+ .testscript = AR6004_HW_3_0_TESTSCRIPT_FILE,
+ },
+
+ .fw_board = AR6004_HW_3_0_BOARD_DATA_FILE,
+ .fw_default_board = AR6004_HW_3_0_DEFAULT_BOARD_DATA_FILE,
+ },
};
/*
@@ -601,7 +621,9 @@ int ath6kl_configure_target(struct ath6kl *ar)
* but possible in theory.
*/
- if (ar->target_type == TARGET_TYPE_AR6003) {
+ if ((ar->target_type == TARGET_TYPE_AR6003) ||
+ (ar->version.target_ver == AR6004_HW_1_3_VERSION) ||
+ (ar->version.target_ver == AR6004_HW_3_0_VERSION)) {
param = ar->hw.board_ext_data_addr;
ram_reserved_size = ar->hw.reserved_ram_size;
@@ -629,9 +651,12 @@ int ath6kl_configure_target(struct ath6kl *ar)
return status;
/* Configure target refclk_hz */
- status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz, ar->hw.refclk_hz);
- if (status)
- return status;
+ if (ar->hw.refclk_hz != 0) {
+ status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz,
+ ar->hw.refclk_hz);
+ if (status)
+ return status;
+ }
return 0;
}
@@ -1112,6 +1137,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar)
if (ret)
return ret;
+ ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API5_FILE);
+ if (ret == 0) {
+ ar->fw_api = 5;
+ goto out;
+ }
+
ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE);
if (ret == 0) {
ar->fw_api = 4;
@@ -1161,11 +1192,19 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
ath6kl_bmi_write_hi32(ar, hi_board_data,
board_address);
} else {
- ath6kl_bmi_read_hi32(ar, hi_board_data, &board_address);
+ ret = ath6kl_bmi_read_hi32(ar, hi_board_data, &board_address);
+ if (ret) {
+ ath6kl_err("Failed to get board file target address.\n");
+ return ret;
+ }
}
/* determine where in target ram to write extended board data */
- ath6kl_bmi_read_hi32(ar, hi_board_ext_data, &board_ext_address);
+ ret = ath6kl_bmi_read_hi32(ar, hi_board_ext_data, &board_ext_address);
+ if (ret) {
+ ath6kl_err("Failed to get extended board file target address.\n");
+ return ret;
+ }
if (ar->target_type == TARGET_TYPE_AR6003 &&
board_ext_address == 0) {
@@ -1229,7 +1268,13 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
}
/* record the fact that Board Data IS initialized */
- ath6kl_bmi_write_hi32(ar, hi_board_data_initialized, 1);
+ if ((ar->version.target_ver == AR6004_HW_1_3_VERSION) ||
+ (ar->version.target_ver == AR6004_HW_3_0_VERSION))
+ param = board_data_size;
+ else
+ param = 1;
+
+ ath6kl_bmi_write_hi32(ar, hi_board_data_initialized, param);
return ret;
}
@@ -1360,7 +1405,11 @@ static int ath6kl_upload_testscript(struct ath6kl *ar)
}
ath6kl_bmi_write_hi32(ar, hi_ota_testscript, address);
- ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 4096);
+
+ if ((ar->version.target_ver != AR6004_HW_1_3_VERSION) &&
+ (ar->version.target_ver != AR6004_HW_3_0_VERSION))
+ ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 4096);
+
ath6kl_bmi_write_hi32(ar, hi_test_apps_related, 1);
return 0;
@@ -1566,6 +1615,11 @@ static const struct fw_capa_str_map {
{ ATH6KL_FW_CAPABILITY_REGDOMAIN, "regdomain" },
{ ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, "sched-scan-v2" },
{ ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, "hb-poll" },
+ { ATH6KL_FW_CAPABILITY_64BIT_RATES, "64bit-rates" },
+ { ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS, "ap-inactivity-mins" },
+ { ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, "map-lp-endpoint" },
+ { ATH6KL_FW_CAPABILITY_RATETABLE_MCS15, "ratetable-mcs15" },
+ { ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM, "no-ip-checksum" },
};
static const char *ath6kl_init_get_fw_capa_name(unsigned int id)
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index d56554674da4..21516bc65785 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -702,6 +702,7 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len)
struct ath6kl *ar = vif->ar;
struct target_stats *stats = &vif->target_stats;
struct tkip_ccmp_stats *ccmp_stats;
+ s32 rate;
u8 ac;
if (len < sizeof(*tgt_stats))
@@ -731,8 +732,9 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len)
le32_to_cpu(tgt_stats->stats.tx.mult_retry_cnt);
stats->tx_rts_fail_cnt +=
le32_to_cpu(tgt_stats->stats.tx.rts_fail_cnt);
- stats->tx_ucast_rate =
- ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.tx.ucast_rate));
+
+ rate = a_sle32_to_cpu(tgt_stats->stats.tx.ucast_rate);
+ stats->tx_ucast_rate = ath6kl_wmi_get_rate(ar->wmi, rate);
stats->rx_pkt += le32_to_cpu(tgt_stats->stats.rx.pkt);
stats->rx_byte += le32_to_cpu(tgt_stats->stats.rx.byte);
@@ -749,8 +751,9 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len)
le32_to_cpu(tgt_stats->stats.rx.key_cache_miss);
stats->rx_decrypt_err += le32_to_cpu(tgt_stats->stats.rx.decrypt_err);
stats->rx_dupl_frame += le32_to_cpu(tgt_stats->stats.rx.dupl_frame);
- stats->rx_ucast_rate =
- ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.rx.ucast_rate));
+
+ rate = a_sle32_to_cpu(tgt_stats->stats.rx.ucast_rate);
+ stats->rx_ucast_rate = ath6kl_wmi_get_rate(ar->wmi, rate);
ccmp_stats = &tgt_stats->stats.tkip_ccmp_stats;
@@ -1290,6 +1293,8 @@ static const struct net_device_ops ath6kl_netdev_ops = {
void init_netdev(struct net_device *dev)
{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
dev->netdev_ops = &ath6kl_netdev_ops;
dev->destructor = free_netdev;
dev->watchdog_timeo = ATH6KL_TX_TIMEOUT;
@@ -1301,7 +1306,9 @@ void init_netdev(struct net_device *dev)
WMI_MAX_TX_META_SZ +
ATH6KL_HTC_ALIGN_BYTES, 4);
- dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
+ if (!test_bit(ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM,
+ ar->fw_capabilities))
+ dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
return;
}
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
index 3afc5a463d06..c44325856b81 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -802,7 +802,8 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,
break;
case WMI_DATA_VI_SVC:
- if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT)
+ if (test_bit(ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT,
+ ar->fw_capabilities))
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP;
else
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
@@ -814,7 +815,8 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,
break;
case WMI_DATA_VO_SVC:
- if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT)
+ if (test_bit(ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT,
+ ar->fw_capabilities))
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP;
else
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
@@ -1208,6 +1210,7 @@ static int ath6kl_usb_pm_reset_resume(struct usb_interface *intf)
/* table of devices that work with this driver */
static struct usb_device_id ath6kl_usb_ids[] = {
+ {USB_DEVICE(0x0cf3, 0x9375)},
{USB_DEVICE(0x0cf3, 0x9374)},
{ /* Terminating entry */ },
};
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 4d7f9e4712e9..94df345d08c2 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -59,6 +59,55 @@ static const s32 wmi_rate_tbl[][2] = {
{0, 0}
};
+static const s32 wmi_rate_tbl_mcs15[][2] = {
+ /* {W/O SGI, with SGI} */
+ {1000, 1000},
+ {2000, 2000},
+ {5500, 5500},
+ {11000, 11000},
+ {6000, 6000},
+ {9000, 9000},
+ {12000, 12000},
+ {18000, 18000},
+ {24000, 24000},
+ {36000, 36000},
+ {48000, 48000},
+ {54000, 54000},
+ {6500, 7200}, /* HT 20, MCS 0 */
+ {13000, 14400},
+ {19500, 21700},
+ {26000, 28900},
+ {39000, 43300},
+ {52000, 57800},
+ {58500, 65000},
+ {65000, 72200},
+ {13000, 14400}, /* HT 20, MCS 8 */
+ {26000, 28900},
+ {39000, 43300},
+ {52000, 57800},
+ {78000, 86700},
+ {104000, 115600},
+ {117000, 130000},
+ {130000, 144400}, /* HT 20, MCS 15 */
+ {13500, 15000}, /*HT 40, MCS 0 */
+ {27000, 30000},
+ {40500, 45000},
+ {54000, 60000},
+ {81000, 90000},
+ {108000, 120000},
+ {121500, 135000},
+ {135000, 150000},
+ {27000, 30000}, /*HT 40, MCS 8 */
+ {54000, 60000},
+ {81000, 90000},
+ {108000, 120000},
+ {162000, 180000},
+ {216000, 240000},
+ {243000, 270000},
+ {270000, 300000}, /*HT 40, MCS 15 */
+ {0, 0}
+};
+
/* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */
static const u8 up_to_ac[] = {
WMM_AC_BE,
@@ -2838,7 +2887,8 @@ int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
{
struct ath6kl *ar = wmi->parent_dev;
- if (ar->hw.flags & ATH6KL_HW_64BIT_RATES)
+ if (test_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES,
+ ar->fw_capabilities))
return ath6kl_set_bitrate_mask64(wmi, if_idx, mask);
else
return ath6kl_set_bitrate_mask32(wmi, if_idx, mask);
@@ -3279,9 +3329,11 @@ int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2)
NO_SYNC_WMIFLAG);
}
-s32 ath6kl_wmi_get_rate(s8 rate_index)
+s32 ath6kl_wmi_get_rate(struct wmi *wmi, s8 rate_index)
{
+ struct ath6kl *ar = wmi->parent_dev;
u8 sgi = 0;
+ s32 ret;
if (rate_index == RATE_AUTO)
return 0;
@@ -3292,10 +3344,20 @@ s32 ath6kl_wmi_get_rate(s8 rate_index)
sgi = 1;
}
- if (WARN_ON(rate_index > RATE_MCS_7_40))
- rate_index = RATE_MCS_7_40;
+ if (test_bit(ATH6KL_FW_CAPABILITY_RATETABLE_MCS15,
+ ar->fw_capabilities)) {
+ if (WARN_ON(rate_index >= ARRAY_SIZE(wmi_rate_tbl_mcs15)))
+ return 0;
+
+ ret = wmi_rate_tbl_mcs15[(u32) rate_index][sgi];
+ } else {
+ if (WARN_ON(rate_index >= ARRAY_SIZE(wmi_rate_tbl)))
+ return 0;
- return wmi_rate_tbl[(u32) rate_index][sgi];
+ ret = wmi_rate_tbl[(u32) rate_index][sgi];
+ }
+
+ return ret;
}
static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap,
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index bb23fc00111d..19f88b4a24fb 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -2632,7 +2632,7 @@ int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx,
struct ath6kl_htcap *htcap);
int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len);
-s32 ath6kl_wmi_get_rate(s8 rate_index);
+s32 ath6kl_wmi_get_rate(struct wmi *wmi, s8 rate_index);
int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx,
__be32 ips0, __be32 ips1);
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
index 741b38ddcb37..59af9f9712da 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
@@ -281,7 +281,7 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
ACCESS_ONCE(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen)
| (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
- | SM(i->txpower, AR_XmitPower)
+ | SM(i->txpower, AR_XmitPower0)
| (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
| (i->flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
| (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
@@ -306,6 +306,10 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
| set11nRateFlags(i->rates, 2)
| set11nRateFlags(i->rates, 3)
| SM(i->rtscts_rate, AR_RTSCTSRate);
+
+ ACCESS_ONCE(ads->ds_ctl9) = SM(i->txpower, AR_XmitPower1);
+ ACCESS_ONCE(ads->ds_ctl10) = SM(i->txpower, AR_XmitPower2);
+ ACCESS_ONCE(ads->ds_ctl11) = SM(i->txpower, AR_XmitPower3);
}
static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 729ffbf07343..71e38e85aa99 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -101,7 +101,7 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen)
| (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
- | SM(i->txpower, AR_XmitPower)
+ | SM(i->txpower, AR_XmitPower0)
| (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
| (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
| (i->flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0)
@@ -151,6 +151,10 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
| SM(i->rtscts_rate, AR_RTSCTSRate);
ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding;
+
+ ACCESS_ONCE(ads->ctl20) = SM(i->txpower, AR_XmitPower1);
+ ACCESS_ONCE(ads->ctl21) = SM(i->txpower, AR_XmitPower2);
+ ACCESS_ONCE(ads->ctl22) = SM(i->txpower, AR_XmitPower3);
}
static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 11b5e4dd6294..7fc13a8da675 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -182,7 +182,8 @@ struct ath_atx_ac {
struct ath_frame_info {
struct ath_buf *bf;
- int framelen;
+ u16 framelen;
+ s8 txq;
enum ath9k_key_type keytype;
u8 keyix;
u8 rtscts_rate;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index ce073e995dfe..d2279365be6f 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -202,7 +202,7 @@ static ssize_t write_file_ani(struct file *file,
if (kstrtoul(buf, 0, &ani))
return -EINVAL;
- if (ani < 0 || ani > 1)
+ if (ani > 1)
return -EINVAL;
common->disable_ani = !ani;
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index da7686757535..6c56cafa5ca4 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -346,8 +346,14 @@ struct ar5416_desc {
#define AR_FrameLen 0x00000fff
#define AR_VirtMoreFrag 0x00001000
#define AR_TxCtlRsvd00 0x0000e000
-#define AR_XmitPower 0x003f0000
-#define AR_XmitPower_S 16
+#define AR_XmitPower0 0x003f0000
+#define AR_XmitPower0_S 16
+#define AR_XmitPower1 0x3f000000
+#define AR_XmitPower1_S 24
+#define AR_XmitPower2 0x3f000000
+#define AR_XmitPower2_S 24
+#define AR_XmitPower3 0x3f000000
+#define AR_XmitPower3_S 24
#define AR_RTSEnable 0x00400000
#define AR_VEOL 0x00800000
#define AR_ClrDestMask 0x01000000
diff --git a/drivers/net/wireless/ath/ath9k/spectral.c b/drivers/net/wireless/ath/ath9k/spectral.c
index 99f4de95c264..5fe29b9f8fa2 100644
--- a/drivers/net/wireless/ath/ath9k/spectral.c
+++ b/drivers/net/wireless/ath/ath9k/spectral.c
@@ -313,7 +313,7 @@ static ssize_t write_file_spectral_short_repeat(struct file *file,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- if (val < 0 || val > 1)
+ if (val > 1)
return -EINVAL;
sc->spec_config.short_repeat = val;
@@ -361,7 +361,7 @@ static ssize_t write_file_spectral_count(struct file *file,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- if (val < 0 || val > 255)
+ if (val > 255)
return -EINVAL;
sc->spec_config.count = val;
@@ -409,7 +409,7 @@ static ssize_t write_file_spectral_period(struct file *file,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- if (val < 0 || val > 255)
+ if (val > 255)
return -EINVAL;
sc->spec_config.period = val;
@@ -457,7 +457,7 @@ static ssize_t write_file_spectral_fft_period(struct file *file,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- if (val < 0 || val > 15)
+ if (val > 15)
return -EINVAL;
sc->spec_config.fft_period = val;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index d4927c9a6bae..704fcbcbe20b 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -157,15 +157,14 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- int q, hw_queue;
-
- q = skb_get_queue_mapping(skb);
- if (txq == sc->tx.uapsdq)
- txq = sc->tx.txq_map[q];
+ struct ath_frame_info *fi = get_frame_info(skb);
+ int hw_queue;
+ int q = fi->txq;
- if (txq != sc->tx.txq_map[q])
+ if (q < 0)
return;
+ txq = sc->tx.txq_map[q];
if (WARN_ON(--txq->pending_frames < 0))
txq->pending_frames = 0;
@@ -898,6 +897,15 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
tx_info = IEEE80211_SKB_CB(skb);
tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT;
+
+ /*
+ * No aggregation session is running, but there may be frames
+ * from a previous session or a failed attempt in the queue.
+ * Send them out as normal data frames
+ */
+ if (!tid->active)
+ tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+
if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {
bf->bf_state.bf_type = 0;
return bf;
@@ -2036,6 +2044,7 @@ static void setup_frame_info(struct ieee80211_hw *hw,
an = (struct ath_node *) sta->drv_priv;
memset(fi, 0, sizeof(*fi));
+ fi->txq = -1;
if (hw_key)
fi->keyix = hw_key->hw_key_idx;
else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0)
@@ -2187,6 +2196,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = txctl->sta;
struct ieee80211_vif *vif = info->control.vif;
+ struct ath_frame_info *fi = get_frame_info(skb);
struct ath_vif *avp = NULL;
struct ath_softc *sc = hw->priv;
struct ath_txq *txq = txctl->txq;
@@ -2216,11 +2226,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
hw_queue = (info->hw_queue >= sc->hw->queues - 2) ? q : info->hw_queue;
ath_txq_lock(sc, txq);
- if (txq == sc->tx.txq_map[q] &&
- ++txq->pending_frames > sc->tx.txq_max_pending[q] &&
- !txq->stopped) {
- ieee80211_stop_queue(sc->hw, hw_queue);
- txq->stopped = true;
+ if (txq == sc->tx.txq_map[q]) {
+ fi->txq = q;
+ if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
+ !txq->stopped) {
+ ieee80211_stop_queue(sc->hw, hw_queue);
+ txq->stopped = true;
+ }
}
queue = ieee80211_is_data_present(hdr->frame_control);
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index a868c5eebe37..8f66186adb8c 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -448,8 +448,10 @@ static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
char *kbuf = kmalloc(len + 1, GFP_KERNEL);
if (!kbuf)
return -ENOMEM;
- if (copy_from_user(kbuf, buf, len))
+ if (copy_from_user(kbuf, buf, len)) {
+ kfree(kbuf);
return -EIO;
+ }
kbuf[len] = '\0';
rc = kstrtol(kbuf, 0, &channel);
@@ -963,6 +965,26 @@ static const struct file_operations fops_sta = {
};
/*----------------*/
+static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
+ struct dentry *dbg)
+{
+ int i;
+ char name[32];
+
+ for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
+ struct debugfs_blob_wrapper *blob = &wil->blobs[i];
+ const struct fw_map *map = &fw_mapping[i];
+
+ if (!map->name)
+ continue;
+
+ blob->data = (void * __force)wil->csr + HOSTADDR(map->host);
+ blob->size = map->to - map->from;
+ snprintf(name, sizeof(name), "blob_%s", map->name);
+ wil_debugfs_create_ioblob(name, S_IRUGO, dbg, blob);
+ }
+}
+
int wil6210_debugfs_init(struct wil6210_priv *wil)
{
struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
@@ -986,6 +1008,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
&wil->secure_pcp);
wil_debugfs_create_ulong("status", S_IRUGO | S_IWUSR, dbg,
&wil->status);
+ debugfs_create_u32("fw_version", S_IRUGO, dbg, &wil->fw_version);
+ debugfs_create_x32("hw_version", S_IRUGO, dbg, &wil->hw_version);
wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg,
HOSTADDR(RGF_USER_USER_ICR));
@@ -998,6 +1022,9 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
wil6210_debugfs_create_pseudo_ISR(wil, dbg);
wil6210_debugfs_create_ITR_CNT(wil, dbg);
+ wil_debugfs_create_iomem_x32("RGF_USER_USAGE_1", S_IRUGO, dbg,
+ wil->csr +
+ HOSTADDR(RGF_USER_USAGE_1));
debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr);
debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread);
@@ -1010,34 +1037,7 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
debugfs_create_file("link", S_IRUGO, dbg, wil, &fops_link);
debugfs_create_file("info", S_IRUGO, dbg, wil, &fops_info);
- wil->rgf_blob.data = (void * __force)wil->csr + 0;
- wil->rgf_blob.size = 0xa000;
- wil_debugfs_create_ioblob("blob_rgf", S_IRUGO, dbg, &wil->rgf_blob);
-
- wil->fw_code_blob.data = (void * __force)wil->csr + 0x40000;
- wil->fw_code_blob.size = 0x40000;
- wil_debugfs_create_ioblob("blob_fw_code", S_IRUGO, dbg,
- &wil->fw_code_blob);
-
- wil->fw_data_blob.data = (void * __force)wil->csr + 0x80000;
- wil->fw_data_blob.size = 0x8000;
- wil_debugfs_create_ioblob("blob_fw_data", S_IRUGO, dbg,
- &wil->fw_data_blob);
-
- wil->fw_peri_blob.data = (void * __force)wil->csr + 0x88000;
- wil->fw_peri_blob.size = 0x18000;
- wil_debugfs_create_ioblob("blob_fw_peri", S_IRUGO, dbg,
- &wil->fw_peri_blob);
-
- wil->uc_code_blob.data = (void * __force)wil->csr + 0xa0000;
- wil->uc_code_blob.size = 0x10000;
- wil_debugfs_create_ioblob("blob_uc_code", S_IRUGO, dbg,
- &wil->uc_code_blob);
-
- wil->uc_data_blob.data = (void * __force)wil->csr + 0xb0000;
- wil->uc_data_blob.size = 0x4000;
- wil_debugfs_create_ioblob("blob_uc_data", S_IRUGO, dbg,
- &wil->uc_data_blob);
+ wil6210_debugfs_init_blobs(wil, dbg);
return 0;
}
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 53a689ed7c7d..3704d2a434f3 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -314,8 +314,9 @@ static void wil_target_reset(struct wil6210_priv *wil)
int delay = 0;
u32 hw_state;
u32 rev_id;
+ bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW);
- wil_dbg_misc(wil, "Resetting...\n");
+ wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name);
/* register read */
#define R(a) ioread32(wil->csr + HOSTADDR(a))
@@ -328,35 +329,59 @@ static void wil_target_reset(struct wil6210_priv *wil)
wil->hw_version = R(RGF_USER_FW_REV_ID);
rev_id = wil->hw_version & 0xff;
+
+ /* Clear MAC link up */
+ S(RGF_HP_CTRL, BIT(15));
/* hpal_perst_from_pad_src_n_mask */
S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6));
/* car_perst_rst_src_n_mask */
S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7));
wmb(); /* order is important here */
+ if (is_sparrow) {
+ W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
+ wmb(); /* order is important here */
+ }
+
W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */
W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
wmb(); /* order is important here */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170);
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000B0 : 0x00000170);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00);
wmb(); /* order is important here */
+ if (is_sparrow) {
+ W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
+ wmb(); /* order is important here */
+ }
+
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
wmb(); /* order is important here */
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
- if (rev_id == 1) {
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
- } else {
- W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
+ if (is_sparrow) {
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
+ /* reset A2 PCIE AHB */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
+
+ } else {
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
+ if (rev_id == 1) {
+ /* reset A1 BOTH PCIE AHB & PCIE RGF */
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
+ } else {
+ W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
+ }
+
}
+
+ /* TODO: check order here!!! Erez code is different */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
wmb(); /* order is important here */
@@ -371,7 +396,8 @@ static void wil_target_reset(struct wil6210_priv *wil)
}
} while (hw_state != HW_MACHINE_BOOT_DONE);
- if (rev_id == 2)
+ /* TODO: Erez check rev_id != 1 */
+ if (!is_sparrow && (rev_id != 1))
W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 77b6272d93fb..d3fbfa28db62 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -122,10 +122,12 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct wil6210_priv *wil;
struct device *dev = &pdev->dev;
void __iomem *csr;
+ struct wil_board *board = (struct wil_board *)id->driver_data;
int rc;
/* check HW */
- dev_info(&pdev->dev, WIL_NAME " device found [%04x:%04x] (rev %x)\n",
+ dev_info(&pdev->dev, WIL_NAME
+ " \"%s\" device found [%04x:%04x] (rev %x)\n", board->name,
(int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) {
@@ -175,6 +177,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_drvdata(pdev, wil);
wil->pdev = pdev;
+ wil->board = board;
wil6210_clear_irq(wil);
/* FW should raise IRQ when ready */
@@ -225,8 +228,21 @@ static void wil_pcie_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-static DEFINE_PCI_DEVICE_TABLE(wil6210_pcie_ids) = {
- { PCI_DEVICE(0x1ae9, 0x0301) },
+static const struct wil_board wil_board_marlon = {
+ .board = WIL_BOARD_MARLON,
+ .name = "marlon",
+};
+
+static const struct wil_board wil_board_sparrow = {
+ .board = WIL_BOARD_SPARROW,
+ .name = "sparrow",
+};
+
+static const struct pci_device_id wil6210_pcie_ids[] = {
+ { PCI_DEVICE(0x1ae9, 0x0301),
+ .driver_data = (kernel_ulong_t)&wil_board_marlon },
+ { PCI_DEVICE(0x1ae9, 0x0310),
+ .driver_data = (kernel_ulong_t)&wil_board_sparrow },
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index af4b93e4beb5..d3467943d39d 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1108,8 +1108,10 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
while (vring->swtail != new_swtail) {
struct vring_tx_desc dd, *d = &dd;
u16 dmalen;
- struct wil_ctx *ctx = &vring->ctx[vring->swtail];
- struct sk_buff *skb = ctx->skb;
+ struct sk_buff *skb;
+
+ ctx = &vring->ctx[vring->swtail];
+ skb = ctx->skb;
_d = &vring->va[vring->swtail].tx;
*d = *_d;
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 424906635f05..67e9624f7111 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -24,6 +24,13 @@
#define WIL_NAME "wil6210"
+struct wil_board {
+ int board;
+#define WIL_BOARD_MARLON (1)
+#define WIL_BOARD_SPARROW (2)
+ const char * const name;
+};
+
/**
* extract bits [@b0:@b1] (inclusive) from the value @x
* it should be @b0 <= @b1, or result is incorrect
@@ -78,6 +85,7 @@ struct RGF_ICR {
} __packed;
/* registers - FW addresses */
+#define RGF_USER_USAGE_1 (0x880004)
#define RGF_USER_HW_MACHINE_STATE (0x8801dc)
#define HW_MACHINE_BOOT_DONE (0x3fffffd)
#define RGF_USER_USER_CPU_0 (0x8801e0)
@@ -93,6 +101,7 @@ struct RGF_ICR {
#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14)
#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */
#define BIT_USER_USER_ICR_SW_INT_2 BIT(18)
+#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0 (0x880c18)
#define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */
#define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0)
@@ -121,6 +130,7 @@ struct RGF_ICR {
#define BIT_DMA_PSEUDO_CAUSE_TX BIT(1)
#define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2)
+#define RGF_HP_CTRL (0x88265c)
#define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4)
/* popular locations */
@@ -135,6 +145,14 @@ struct RGF_ICR {
#define ISR_MISC_FW_ERROR BIT_DMA_EP_MISC_ICR_FW_INT(3)
/* Hardware definitions end */
+struct fw_map {
+ u32 from; /* linker address - from, inclusive */
+ u32 to; /* linker address - to, exclusive */
+ u32 host; /* PCI/Host address - BAR0 + 0x880000 */
+ const char *name; /* for debugfs */
+};
+/* array size should be in sync with actual definition in the wmi.c */
+extern const struct fw_map fw_mapping[7];
/**
* mk_cidxtid - construct @cidxtid field
@@ -365,6 +383,7 @@ struct wil6210_priv {
ulong status;
u32 fw_version;
u32 hw_version;
+ struct wil_board *board;
u8 n_mids; /* number of additional MIDs as reported by FW */
int recovery_count; /* num of FW recovery attempts in a short time */
unsigned long last_fw_recovery; /* jiffies of last fw recovery */
@@ -415,12 +434,7 @@ struct wil6210_priv {
atomic_t isr_count_rx, isr_count_tx;
/* debugfs */
struct dentry *debug;
- struct debugfs_blob_wrapper fw_code_blob;
- struct debugfs_blob_wrapper fw_data_blob;
- struct debugfs_blob_wrapper fw_peri_blob;
- struct debugfs_blob_wrapper uc_code_blob;
- struct debugfs_blob_wrapper uc_data_blob;
- struct debugfs_blob_wrapper rgf_blob;
+ struct debugfs_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)];
};
#define wil_to_wiphy(i) (i->wdev->wiphy)
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index a136dab560e2..1d1d0afdd2e1 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -65,18 +65,17 @@
/**
* @fw_mapping provides memory remapping table
+ *
+ * array size should be in sync with the declaration in the wil6210.h
*/
-static const struct {
- u32 from; /* linker address - from, inclusive */
- u32 to; /* linker address - to, exclusive */
- u32 host; /* PCI/Host address - BAR0 + 0x880000 */
-} fw_mapping[] = {
- {0x000000, 0x040000, 0x8c0000}, /* FW code RAM 256k */
- {0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */
- {0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */
- {0x880000, 0x88a000, 0x880000}, /* various RGF */
- {0x88b000, 0x88c000, 0x88b000}, /* Pcie_ext_rgf */
- {0x8c0000, 0x949000, 0x8c0000}, /* trivial mapping for upper area */
+const struct fw_map fw_mapping[] = {
+ {0x000000, 0x040000, 0x8c0000, "fw_code"}, /* FW code RAM 256k */
+ {0x800000, 0x808000, 0x900000, "fw_data"}, /* FW data RAM 32k */
+ {0x840000, 0x860000, 0x908000, "fw_peri"}, /* periph. data RAM 128k */
+ {0x880000, 0x88a000, 0x880000, "rgf"}, /* various RGF 40k */
+ {0x88a000, 0x88b000, 0x88a000, "AGC_tbl"}, /* AGC table 4k */
+ {0x88b000, 0x88c000, 0x88b000, "rgf_ext"}, /* Pcie_ext_rgf 4k */
+ {0x8c0000, 0x949000, 0x8c0000, "upper"}, /* upper area 548k */
/*
* 920000..930000 ucode code RAM
* 930000..932000 ucode data RAM
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 15aaeb132a32..d7055febe119 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -210,6 +210,9 @@ static struct ieee80211_channel b43_2ghz_chantable[] = {
CHAN2G(13, 2472, 0),
CHAN2G(14, 2484, 0),
};
+
+/* No support for the last 3 channels (12, 13, 14) */
+#define b43_2ghz_chantable_limited_size 11
#undef CHAN2G
#define CHAN4G(_channel, _flags) { \
@@ -287,6 +290,14 @@ static struct ieee80211_channel b43_5ghz_nphy_chantable[] = {
CHAN5G(182, 0),
};
+static struct ieee80211_channel b43_5ghz_nphy_chantable_limited[] = {
+ CHAN5G(36, 0), CHAN5G(40, 0),
+ CHAN5G(44, 0), CHAN5G(48, 0),
+ CHAN5G(149, 0), CHAN5G(153, 0),
+ CHAN5G(157, 0), CHAN5G(161, 0),
+ CHAN5G(165, 0),
+};
+
static struct ieee80211_channel b43_5ghz_aphy_chantable[] = {
CHAN5G(34, 0), CHAN5G(36, 0),
CHAN5G(38, 0), CHAN5G(40, 0),
@@ -319,6 +330,14 @@ static struct ieee80211_supported_band b43_band_5GHz_nphy = {
.n_bitrates = b43_a_ratetable_size,
};
+static struct ieee80211_supported_band b43_band_5GHz_nphy_limited = {
+ .band = IEEE80211_BAND_5GHZ,
+ .channels = b43_5ghz_nphy_chantable_limited,
+ .n_channels = ARRAY_SIZE(b43_5ghz_nphy_chantable_limited),
+ .bitrates = b43_a_ratetable,
+ .n_bitrates = b43_a_ratetable_size,
+};
+
static struct ieee80211_supported_band b43_band_5GHz_aphy = {
.band = IEEE80211_BAND_5GHZ,
.channels = b43_5ghz_aphy_chantable,
@@ -335,6 +354,14 @@ static struct ieee80211_supported_band b43_band_2GHz = {
.n_bitrates = b43_g_ratetable_size,
};
+static struct ieee80211_supported_band b43_band_2ghz_limited = {
+ .band = IEEE80211_BAND_2GHZ,
+ .channels = b43_2ghz_chantable,
+ .n_channels = b43_2ghz_chantable_limited_size,
+ .bitrates = b43_g_ratetable,
+ .n_bitrates = b43_g_ratetable_size,
+};
+
static void b43_wireless_core_exit(struct b43_wldev *dev);
static int b43_wireless_core_init(struct b43_wldev *dev);
static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev);
@@ -2953,6 +2980,45 @@ void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on)
}
}
+/* brcms_b_switch_macfreq */
+void b43_mac_switch_freq(struct b43_wldev *dev, u8 spurmode)
+{
+ u16 chip_id = dev->dev->chip_id;
+
+ if (chip_id == BCMA_CHIP_ID_BCM43217 ||
+ chip_id == BCMA_CHIP_ID_BCM43222 ||
+ chip_id == BCMA_CHIP_ID_BCM43224 ||
+ chip_id == BCMA_CHIP_ID_BCM43225 ||
+ chip_id == BCMA_CHIP_ID_BCM43227 ||
+ chip_id == BCMA_CHIP_ID_BCM43228) {
+ switch (spurmode) {
+ case 2: /* 126 Mhz */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x2082);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+ break;
+ case 1: /* 123 Mhz */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x5341);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+ break;
+ default: /* 120 Mhz */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x8889);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+ break;
+ }
+ } else if (dev->phy.type == B43_PHYTYPE_LCN) {
+ switch (spurmode) {
+ case 1: /* 82 Mhz */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x7CE0);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC);
+ break;
+ default: /* 80 Mhz */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0xCCCD);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC);
+ break;
+ }
+ }
+}
+
static void b43_adjust_opmode(struct b43_wldev *dev)
{
struct b43_wl *wl = dev->wl;
@@ -4335,8 +4401,9 @@ static int b43_phy_versioning(struct b43_wldev *dev)
u8 phy_type;
u8 phy_rev;
u16 radio_manuf;
- u16 radio_ver;
+ u16 radio_id;
u16 radio_rev;
+ u8 radio_ver;
int unsupported = 0;
/* Get PHY versioning */
@@ -4360,7 +4427,7 @@ static int b43_phy_versioning(struct b43_wldev *dev)
#endif
#ifdef CONFIG_B43_PHY_N
case B43_PHYTYPE_N:
- if (phy_rev > 9)
+ if (phy_rev >= 19)
unsupported = 1;
break;
#endif
@@ -4402,7 +4469,9 @@ static int b43_phy_versioning(struct b43_wldev *dev)
radio_rev = b43_read16(dev, B43_MMIO_RADIO24_DATA);
b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 1);
- radio_ver = b43_read16(dev, B43_MMIO_RADIO24_DATA);
+ radio_id = b43_read16(dev, B43_MMIO_RADIO24_DATA);
+
+ radio_ver = 0; /* Is there version somewhere? */
} else if (core_rev >= 24) {
u16 radio24[3];
@@ -4411,12 +4480,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA);
}
- /* Broadcom uses "id" for our "ver" and has separated "ver" */
- /* radio_ver = (radio24[0] & 0xF0) >> 4; */
-
radio_manuf = 0x17F;
- radio_ver = (radio24[2] << 8) | radio24[1];
+ radio_id = (radio24[2] << 8) | radio24[1];
radio_rev = (radio24[0] & 0xF);
+ radio_ver = (radio24[0] & 0xF0) >> 4;
} else {
if (dev->dev->chip_id == 0x4317) {
if (dev->dev->chip_rev == 0)
@@ -4435,15 +4502,16 @@ static int b43_phy_versioning(struct b43_wldev *dev)
<< 16;
}
radio_manuf = (tmp & 0x00000FFF);
- radio_ver = (tmp & 0x0FFFF000) >> 12;
+ radio_id = (tmp & 0x0FFFF000) >> 12;
radio_rev = (tmp & 0xF0000000) >> 28;
+ radio_ver = 0; /* Probably not available on old hw */
}
if (radio_manuf != 0x17F /* Broadcom */)
unsupported = 1;
switch (phy_type) {
case B43_PHYTYPE_A:
- if (radio_ver != 0x2060)
+ if (radio_id != 0x2060)
unsupported = 1;
if (radio_rev != 1)
unsupported = 1;
@@ -4451,43 +4519,49 @@ static int b43_phy_versioning(struct b43_wldev *dev)
unsupported = 1;
break;
case B43_PHYTYPE_B:
- if ((radio_ver & 0xFFF0) != 0x2050)
+ if ((radio_id & 0xFFF0) != 0x2050)
unsupported = 1;
break;
case B43_PHYTYPE_G:
- if (radio_ver != 0x2050)
+ if (radio_id != 0x2050)
unsupported = 1;
break;
case B43_PHYTYPE_N:
- if (radio_ver != 0x2055 && radio_ver != 0x2056)
+ if (radio_id != 0x2055 && radio_id != 0x2056 &&
+ radio_id != 0x2057)
+ unsupported = 1;
+ if (radio_id == 0x2057 &&
+ !(radio_rev == 9 || radio_rev == 14))
unsupported = 1;
break;
case B43_PHYTYPE_LP:
- if (radio_ver != 0x2062 && radio_ver != 0x2063)
+ if (radio_id != 0x2062 && radio_id != 0x2063)
unsupported = 1;
break;
case B43_PHYTYPE_HT:
- if (radio_ver != 0x2059)
+ if (radio_id != 0x2059)
unsupported = 1;
break;
case B43_PHYTYPE_LCN:
- if (radio_ver != 0x2064)
+ if (radio_id != 0x2064)
unsupported = 1;
break;
default:
B43_WARN_ON(1);
}
if (unsupported) {
- b43err(dev->wl, "FOUND UNSUPPORTED RADIO "
- "(Manuf 0x%X, Version 0x%X, Revision %u)\n",
- radio_manuf, radio_ver, radio_rev);
+ b43err(dev->wl,
+ "FOUND UNSUPPORTED RADIO (Manuf 0x%X, ID 0x%X, Revision %u, Version %u)\n",
+ radio_manuf, radio_id, radio_rev, radio_ver);
return -EOPNOTSUPP;
}
- b43dbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X, Revision %u\n",
- radio_manuf, radio_ver, radio_rev);
+ b43info(dev->wl,
+ "Found Radio: Manuf 0x%X, ID 0x%X, Revision %u, Version %u\n",
+ radio_manuf, radio_id, radio_rev, radio_ver);
+ /* FIXME: b43 treats "id" as "ver" and ignores the real "ver" */
phy->radio_manuf = radio_manuf;
- phy->radio_ver = radio_ver;
+ phy->radio_ver = radio_id;
phy->radio_rev = radio_rev;
phy->analog = analog_type;
@@ -5095,12 +5169,24 @@ static int b43_setup_bands(struct b43_wldev *dev,
bool have_2ghz_phy, bool have_5ghz_phy)
{
struct ieee80211_hw *hw = dev->wl->hw;
+ struct b43_phy *phy = &dev->phy;
+ bool limited_2g;
+ bool limited_5g;
+
+ /* We don't support all 2 GHz channels on some devices */
+ limited_2g = phy->radio_ver == 0x2057 &&
+ (phy->radio_rev == 9 || phy->radio_rev == 14);
+ limited_5g = phy->radio_ver == 0x2057 &&
+ phy->radio_rev == 9;
if (have_2ghz_phy)
- hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz;
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = limited_2g ?
+ &b43_band_2ghz_limited : &b43_band_2GHz;
if (dev->phy.type == B43_PHYTYPE_N) {
if (have_5ghz_phy)
- hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_nphy;
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = limited_5g ?
+ &b43_band_5GHz_nphy_limited :
+ &b43_band_5GHz_nphy;
} else {
if (have_5ghz_phy)
hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_aphy;
@@ -5248,14 +5334,15 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
b43_supported_bands(dev, &have_2ghz_phy, &have_5ghz_phy);
/* We don't support 5 GHz on some PHYs yet */
- switch (dev->phy.type) {
- case B43_PHYTYPE_A:
- case B43_PHYTYPE_G:
- case B43_PHYTYPE_N:
- case B43_PHYTYPE_LP:
- case B43_PHYTYPE_HT:
- b43warn(wl, "5 GHz band is unsupported on this PHY\n");
- have_5ghz_phy = false;
+ if (have_5ghz_phy) {
+ switch (dev->phy.type) {
+ case B43_PHYTYPE_A:
+ case B43_PHYTYPE_G:
+ case B43_PHYTYPE_LP:
+ case B43_PHYTYPE_HT:
+ b43warn(wl, "5 GHz band is unsupported on this PHY\n");
+ have_5ghz_phy = false;
+ }
}
if (!have_2ghz_phy && !have_5ghz_phy) {
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
index f476fc337d64..9f22e4b4c132 100644
--- a/drivers/net/wireless/b43/main.h
+++ b/drivers/net/wireless/b43/main.h
@@ -99,6 +99,7 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags);
void b43_mac_suspend(struct b43_wldev *dev);
void b43_mac_enable(struct b43_wldev *dev);
void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on);
+void b43_mac_switch_freq(struct b43_wldev *dev, u8 spurmode);
struct b43_request_fw_context;
diff --git a/drivers/net/wireless/b43/phy_lcn.c b/drivers/net/wireless/b43/phy_lcn.c
index 0bafa3b17035..e76bbdf3247e 100644
--- a/drivers/net/wireless/b43/phy_lcn.c
+++ b/drivers/net/wireless/b43/phy_lcn.c
@@ -54,39 +54,6 @@ enum lcn_sense_type {
B43_SENSE_VBAT,
};
-/* In theory it's PHY common function, move if needed */
-/* brcms_b_switch_macfreq */
-static void b43_phy_switch_macfreq(struct b43_wldev *dev, u8 spurmode)
-{
- if (dev->dev->chip_id == 43224 || dev->dev->chip_id == 43225) {
- switch (spurmode) {
- case 2: /* 126 Mhz */
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x2082);
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
- break;
- case 1: /* 123 Mhz */
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x5341);
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
- break;
- default: /* 120 Mhz */
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x8889);
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
- break;
- }
- } else if (dev->phy.type == B43_PHYTYPE_LCN) {
- switch (spurmode) {
- case 1: /* 82 Mhz */
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x7CE0);
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC);
- break;
- default: /* 80 Mhz */
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0xCCCD);
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC);
- break;
- }
- }
-}
-
/**************************************************
* Radio 2064.
**************************************************/
@@ -609,7 +576,7 @@ static void b43_phy_lcn_txrx_spur_avoidance_mode(struct b43_wldev *dev,
b43_phy_write(dev, 0x93b, ((0 << 13) + 23));
b43_phy_write(dev, 0x93c, ((0 << 13) + 1989));
}
- b43_phy_switch_macfreq(dev, enable);
+ b43_mac_switch_freq(dev, enable);
}
/**************************************************
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 50ca6f87d5e8..d269fbb27b9e 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -36,6 +36,7 @@
#include "main.h"
struct nphy_txgains {
+ u16 tx_lpf[2];
u16 txgm[2];
u16 pga[2];
u16 pad[2];
@@ -43,6 +44,7 @@ struct nphy_txgains {
};
struct nphy_iqcal_params {
+ u16 tx_lpf;
u16 txgm;
u16 pga;
u16 pad;
@@ -69,6 +71,14 @@ enum b43_nphy_rf_sequence {
B43_RFSEQ_UPDATE_GAINU,
};
+enum n_rf_ctl_over_cmd {
+ N_RF_CTL_OVER_CMD_RXRF_PU = 0,
+ N_RF_CTL_OVER_CMD_RX_PU = 1,
+ N_RF_CTL_OVER_CMD_TX_PU = 2,
+ N_RF_CTL_OVER_CMD_RX_GAIN = 3,
+ N_RF_CTL_OVER_CMD_TX_GAIN = 4,
+};
+
enum n_intc_override {
N_INTC_OVERRIDE_OFF = 0,
N_INTC_OVERRIDE_TRSW = 1,
@@ -140,11 +150,19 @@ ok:
b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
}
+static void b43_nphy_rf_ctl_override_rev19(struct b43_wldev *dev, u16 field,
+ u16 value, u8 core, bool off,
+ u8 override_id)
+{
+ /* TODO */
+}
+
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverrideRev7 */
static void b43_nphy_rf_ctl_override_rev7(struct b43_wldev *dev, u16 field,
u16 value, u8 core, bool off,
u8 override)
{
+ struct b43_phy *phy = &dev->phy;
const struct nphy_rf_control_override_rev7 *e;
u16 en_addrs[3][2] = {
{ 0x0E7, 0x0EC }, { 0x342, 0x343 }, { 0x346, 0x347 }
@@ -154,6 +172,11 @@ static void b43_nphy_rf_ctl_override_rev7(struct b43_wldev *dev, u16 field,
u16 val_addr;
u8 i;
+ if (phy->rev >= 19 || phy->rev < 3) {
+ B43_WARN_ON(1);
+ return;
+ }
+
/* Remember: we can get NULL! */
e = b43_nphy_get_rf_ctl_over_rev7(dev, field, override);
@@ -181,6 +204,50 @@ static void b43_nphy_rf_ctl_override_rev7(struct b43_wldev *dev, u16 field,
}
}
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverideOneToMany */
+static void b43_nphy_rf_ctl_override_one_to_many(struct b43_wldev *dev,
+ enum n_rf_ctl_over_cmd cmd,
+ u16 value, u8 core, bool off)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 tmp;
+
+ B43_WARN_ON(phy->rev < 7);
+
+ switch (cmd) {
+ case N_RF_CTL_OVER_CMD_RXRF_PU:
+ b43_nphy_rf_ctl_override_rev7(dev, 0x20, value, core, off, 1);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x10, value, core, off, 1);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x08, value, core, off, 1);
+ break;
+ case N_RF_CTL_OVER_CMD_RX_PU:
+ b43_nphy_rf_ctl_override_rev7(dev, 0x4, value, core, off, 1);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x2, value, core, off, 1);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x1, value, core, off, 1);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x2, value, core, off, 2);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x0800, 0, core, off, 1);
+ break;
+ case N_RF_CTL_OVER_CMD_TX_PU:
+ b43_nphy_rf_ctl_override_rev7(dev, 0x4, value, core, off, 0);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x2, value, core, off, 1);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x1, value, core, off, 2);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x0800, 1, core, off, 1);
+ break;
+ case N_RF_CTL_OVER_CMD_RX_GAIN:
+ tmp = value & 0xFF;
+ b43_nphy_rf_ctl_override_rev7(dev, 0x0800, tmp, core, off, 0);
+ tmp = value >> 8;
+ b43_nphy_rf_ctl_override_rev7(dev, 0x6000, tmp, core, off, 0);
+ break;
+ case N_RF_CTL_OVER_CMD_TX_GAIN:
+ tmp = value & 0x7FFF;
+ b43_nphy_rf_ctl_override_rev7(dev, 0x1000, tmp, core, off, 0);
+ tmp = value >> 14;
+ b43_nphy_rf_ctl_override_rev7(dev, 0x4000, tmp, core, off, 0);
+ break;
+ }
+}
+
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
static void b43_nphy_rf_ctl_override(struct b43_wldev *dev, u16 field,
u16 value, u8 core, bool off)
@@ -264,6 +331,8 @@ static void b43_nphy_rf_ctl_intc_override_rev7(struct b43_wldev *dev,
u16 reg, tmp, tmp2, val;
int core;
+ /* TODO: What about rev19+? Revs 3+ and 7+ are a bit similar */
+
for (core = 0; core < 2; core++) {
if ((core_sel == 1 && core != 0) ||
(core_sel == 2 && core != 1))
@@ -274,6 +343,7 @@ static void b43_nphy_rf_ctl_intc_override_rev7(struct b43_wldev *dev,
switch (intc_override) {
case N_INTC_OVERRIDE_OFF:
b43_phy_write(dev, reg, 0);
+ b43_phy_mask(dev, 0x2ff, ~0x2000);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
break;
case N_INTC_OVERRIDE_TRSW:
@@ -505,6 +575,14 @@ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable)
}
}
+/* http://bcm-v4.sipsolutions.net/PHY/N/Read_Lpf_Bw_Ctl */
+static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset)
+{
+ if (!offset)
+ offset = b43_is_40mhz(dev) ? 0x159 : 0x154;
+ return b43_ntab_read(dev, B43_NTAB16(7, offset)) & 0x7;
+}
+
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/AdjustLnaGainTbl */
static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
{
@@ -669,10 +747,63 @@ static void b43_radio_2057_setup(struct b43_wldev *dev,
b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C2, 0x8);
}
break;
- /* TODO */
+ case 9: /* e.g. PHY rev 16 */
+ b43_radio_write(dev, R2057_LOGEN_PTAT_RESETS, 0x20);
+ b43_radio_write(dev, R2057_VCOBUF_IDACS, 0x18);
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+ b43_radio_write(dev, R2057_LOGEN_PTAT_RESETS, 0x38);
+ b43_radio_write(dev, R2057_VCOBUF_IDACS, 0x0f);
+
+ if (b43_is_40mhz(dev)) {
+ /* TODO */
+ } else {
+ b43_radio_write(dev,
+ R2057_PAD_BIAS_FILTER_BWS_CORE0,
+ 0x3c);
+ b43_radio_write(dev,
+ R2057_PAD_BIAS_FILTER_BWS_CORE1,
+ 0x3c);
+ }
+ }
+ break;
+ case 14: /* 2 GHz only */
+ b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_R1, 0x1b);
+ b43_radio_write(dev, R2057_CP_KPD_IDAC, 0x3f);
+ b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C1, 0x1f);
+ b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C2, 0x1f);
+ break;
}
- /* TODO */
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ u16 txmix2g_tune_boost_pu = 0;
+ u16 pad2g_tune_pus = 0;
+
+ if (b43_nphy_ipa(dev)) {
+ switch (phy->radio_rev) {
+ case 9:
+ txmix2g_tune_boost_pu = 0x0041;
+ /* TODO */
+ break;
+ case 14:
+ txmix2g_tune_boost_pu = 0x21;
+ pad2g_tune_pus = 0x23;
+ break;
+ }
+ }
+
+ if (txmix2g_tune_boost_pu)
+ b43_radio_write(dev, R2057_TXMIX2G_TUNE_BOOST_PU_CORE0,
+ txmix2g_tune_boost_pu);
+ if (pad2g_tune_pus)
+ b43_radio_write(dev, R2057_PAD2G_TUNE_PUS_CORE0,
+ pad2g_tune_pus);
+ if (txmix2g_tune_boost_pu)
+ b43_radio_write(dev, R2057_TXMIX2G_TUNE_BOOST_PU_CORE1,
+ txmix2g_tune_boost_pu);
+ if (pad2g_tune_pus)
+ b43_radio_write(dev, R2057_PAD2G_TUNE_PUS_CORE1,
+ pad2g_tune_pus);
+ }
usleep_range(50, 100);
@@ -690,13 +821,62 @@ static void b43_radio_2057_setup(struct b43_wldev *dev,
static u8 b43_radio_2057_rcal(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
+ u16 saved_regs_phy[12];
+ u16 saved_regs_phy_rf[6];
+ u16 saved_regs_radio[2] = { };
+ static const u16 phy_to_store[] = {
+ B43_NPHY_RFCTL_RSSIO1, B43_NPHY_RFCTL_RSSIO2,
+ B43_NPHY_RFCTL_LUT_TRSW_LO1, B43_NPHY_RFCTL_LUT_TRSW_LO2,
+ B43_NPHY_RFCTL_RXG1, B43_NPHY_RFCTL_RXG2,
+ B43_NPHY_RFCTL_TXG1, B43_NPHY_RFCTL_TXG2,
+ B43_NPHY_REV7_RF_CTL_MISC_REG3, B43_NPHY_REV7_RF_CTL_MISC_REG4,
+ B43_NPHY_REV7_RF_CTL_MISC_REG5, B43_NPHY_REV7_RF_CTL_MISC_REG6,
+ };
+ static const u16 phy_to_store_rf[] = {
+ B43_NPHY_REV3_RFCTL_OVER0, B43_NPHY_REV3_RFCTL_OVER1,
+ B43_NPHY_REV7_RF_CTL_OVER3, B43_NPHY_REV7_RF_CTL_OVER4,
+ B43_NPHY_REV7_RF_CTL_OVER5, B43_NPHY_REV7_RF_CTL_OVER6,
+ };
u16 tmp;
+ int i;
- if (phy->radio_rev == 5) {
- b43_phy_mask(dev, 0x342, ~0x2);
+ /* Save */
+ for (i = 0; i < ARRAY_SIZE(phy_to_store); i++)
+ saved_regs_phy[i] = b43_phy_read(dev, phy_to_store[i]);
+ for (i = 0; i < ARRAY_SIZE(phy_to_store_rf); i++)
+ saved_regs_phy_rf[i] = b43_phy_read(dev, phy_to_store_rf[i]);
+
+ /* Set */
+ for (i = 0; i < ARRAY_SIZE(phy_to_store); i++)
+ b43_phy_write(dev, phy_to_store[i], 0);
+ b43_phy_write(dev, B43_NPHY_REV3_RFCTL_OVER0, 0x07ff);
+ b43_phy_write(dev, B43_NPHY_REV3_RFCTL_OVER1, 0x07ff);
+ b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER3, 0x07ff);
+ b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER4, 0x07ff);
+ b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER5, 0x007f);
+ b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER6, 0x007f);
+
+ switch (phy->radio_rev) {
+ case 5:
+ b43_phy_mask(dev, B43_NPHY_REV7_RF_CTL_OVER3, ~0x2);
udelay(10);
b43_radio_set(dev, R2057_IQTEST_SEL_PU, 0x1);
- b43_radio_maskset(dev, 0x1ca, ~0x2, 0x1);
+ b43_radio_maskset(dev, R2057v7_IQTEST_SEL_PU2, ~0x2, 0x1);
+ break;
+ case 9:
+ b43_phy_set(dev, B43_NPHY_REV7_RF_CTL_OVER3, 0x2);
+ b43_phy_set(dev, B43_NPHY_REV7_RF_CTL_MISC_REG3, 0x2);
+ saved_regs_radio[0] = b43_radio_read(dev, R2057_IQTEST_SEL_PU);
+ b43_radio_write(dev, R2057_IQTEST_SEL_PU, 0x11);
+ break;
+ case 14:
+ saved_regs_radio[0] = b43_radio_read(dev, R2057_IQTEST_SEL_PU);
+ saved_regs_radio[1] = b43_radio_read(dev, R2057v7_IQTEST_SEL_PU2);
+ b43_phy_set(dev, B43_NPHY_REV7_RF_CTL_MISC_REG3, 0x2);
+ b43_phy_set(dev, B43_NPHY_REV7_RF_CTL_OVER3, 0x2);
+ b43_radio_write(dev, R2057v7_IQTEST_SEL_PU2, 0x2);
+ b43_radio_write(dev, R2057_IQTEST_SEL_PU, 0x1);
+ break;
}
/* Enable */
@@ -720,14 +900,30 @@ static u8 b43_radio_2057_rcal(struct b43_wldev *dev)
/* Disable */
b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x1);
- if (phy->radio_rev == 5) {
- b43_radio_mask(dev, R2057_IPA2G_CASCONV_CORE0, ~0x1);
- b43_radio_mask(dev, 0x1ca, ~0x2);
- }
- if (phy->radio_rev <= 4 || phy->radio_rev == 6) {
+ /* Restore */
+ for (i = 0; i < ARRAY_SIZE(phy_to_store_rf); i++)
+ b43_phy_write(dev, phy_to_store_rf[i], saved_regs_phy_rf[i]);
+ for (i = 0; i < ARRAY_SIZE(phy_to_store); i++)
+ b43_phy_write(dev, phy_to_store[i], saved_regs_phy[i]);
+
+ switch (phy->radio_rev) {
+ case 0 ... 4:
+ case 6:
b43_radio_maskset(dev, R2057_TEMPSENSE_CONFIG, ~0x3C, tmp);
b43_radio_maskset(dev, R2057_BANDGAP_RCAL_TRIM, ~0xF0,
tmp << 2);
+ break;
+ case 5:
+ b43_radio_mask(dev, R2057_IPA2G_CASCONV_CORE0, ~0x1);
+ b43_radio_mask(dev, R2057v7_IQTEST_SEL_PU2, ~0x2);
+ break;
+ case 9:
+ b43_radio_write(dev, R2057_IQTEST_SEL_PU, saved_regs_radio[0]);
+ break;
+ case 14:
+ b43_radio_write(dev, R2057_IQTEST_SEL_PU, saved_regs_radio[0]);
+ b43_radio_write(dev, R2057v7_IQTEST_SEL_PU2, saved_regs_radio[1]);
+ break;
}
return tmp & 0x3e;
@@ -749,7 +945,7 @@ static u16 b43_radio_2057_rccal(struct b43_wldev *dev)
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xC0);
} else {
b43_radio_write(dev, R2057v7_RCCAL_MASTER, 0x61);
- b43_radio_write(dev, R2057_RCCAL_TRC0, 0xE1);
+ b43_radio_write(dev, R2057_RCCAL_TRC0, 0xE9);
}
b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
@@ -829,6 +1025,9 @@ static void b43_radio_2057_init_post(struct b43_wldev *dev)
{
b43_radio_set(dev, R2057_XTALPUOVR_PINCTRL, 0x1);
+ if (0) /* FIXME: Is this BCM43217 specific? */
+ b43_radio_set(dev, R2057_XTALPUOVR_PINCTRL, 0x2);
+
b43_radio_set(dev, R2057_RFPLL_MISC_CAL_RESETN, 0x78);
b43_radio_set(dev, R2057_XTAL_CONFIG2, 0x80);
mdelay(2);
@@ -1386,6 +1585,7 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
u16 wait, bool iqmode, bool dac_test,
bool modify_bbmult)
{
+ struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = dev->phy.n;
int i;
u16 seq_mode;
@@ -1393,6 +1593,26 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
b43_nphy_stay_in_carrier_search(dev, true);
+ if (phy->rev >= 7) {
+ bool lpf_bw3, lpf_bw4;
+
+ lpf_bw3 = b43_phy_read(dev, B43_NPHY_REV7_RF_CTL_OVER3) & 0x80;
+ lpf_bw4 = b43_phy_read(dev, B43_NPHY_REV7_RF_CTL_OVER4) & 0x80;
+
+ if (lpf_bw3 || lpf_bw4) {
+ /* TODO */
+ } else {
+ u16 value = b43_nphy_read_lpf_ctl(dev, 0);
+ if (phy->rev >= 19)
+ b43_nphy_rf_ctl_override_rev19(dev, 0x80, value,
+ 0, false, 1);
+ else
+ b43_nphy_rf_ctl_override_rev7(dev, 0x80, value,
+ 0, false, 1);
+ nphy->lpf_bw_overrode_for_sample_play = true;
+ }
+ }
+
if ((nphy->bb_mult_save & 0x80000000) == 0) {
tmp = b43_ntab_read(dev, B43_NTAB16(15, 87));
nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000;
@@ -1520,6 +1740,12 @@ static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
}
}
+static void b43_nphy_rssi_select_rev19(struct b43_wldev *dev, u8 code,
+ enum n_rssi_type rssi_type)
+{
+ /* TODO */
+}
+
static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code,
enum n_rssi_type rssi_type)
{
@@ -1589,13 +1815,15 @@ static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code,
enum ieee80211_band band =
b43_current_band(dev->wl);
- if (b43_nphy_ipa(dev))
- val = (band == IEEE80211_BAND_5GHZ) ? 0xC : 0xE;
- else
- val = 0x11;
- reg = (i == 0) ? 0x2000 : 0x3000;
- reg |= B2055_PADDRV;
- b43_radio_write(dev, reg, val);
+ if (dev->phy.rev < 7) {
+ if (b43_nphy_ipa(dev))
+ val = (band == IEEE80211_BAND_5GHZ) ? 0xC : 0xE;
+ else
+ val = 0x11;
+ reg = (i == 0) ? B2056_TX0 : B2056_TX1;
+ reg |= B2056_TX_TX_SSI_MUX;
+ b43_radio_write(dev, reg, val);
+ }
reg = (i == 0) ?
B43_NPHY_AFECTL_OVER1 :
@@ -1682,7 +1910,9 @@ static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code,
static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code,
enum n_rssi_type type)
{
- if (dev->phy.rev >= 3)
+ if (dev->phy.rev >= 19)
+ b43_nphy_rssi_select_rev19(dev, code, type);
+ else if (dev->phy.rev >= 3)
b43_nphy_rev3_rssi_select(dev, code, type);
else
b43_nphy_rev2_rssi_select(dev, code, type);
@@ -1726,6 +1956,8 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, enum n_rssi_type rssi_type,
u16 save_regs_phy[9];
u16 s[2];
+ /* TODO: rev7+ is treated like rev3+, what about rev19+? */
+
if (dev->phy.rev >= 3) {
save_regs_phy[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
save_regs_phy[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
@@ -1825,12 +2057,14 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
B43_NPHY_AFECTL_OVER1, B43_NPHY_AFECTL_OVER,
B43_NPHY_AFECTL_C1, B43_NPHY_AFECTL_C2,
B43_NPHY_TXF_40CO_B1S1, B43_NPHY_RFCTL_OVER,
- 0x342, 0x343, 0x346, 0x347,
+ B43_NPHY_REV7_RF_CTL_OVER3, B43_NPHY_REV7_RF_CTL_OVER4,
+ B43_NPHY_REV7_RF_CTL_OVER5, B43_NPHY_REV7_RF_CTL_OVER6,
0x2ff,
B43_NPHY_TXF_40CO_B1S0, B43_NPHY_TXF_40CO_B32S1,
B43_NPHY_RFCTL_CMD,
B43_NPHY_RFCTL_LUT_TRSW_UP1, B43_NPHY_RFCTL_LUT_TRSW_UP2,
- 0x340, 0x341, 0x344, 0x345,
+ B43_NPHY_REV7_RF_CTL_MISC_REG3, B43_NPHY_REV7_RF_CTL_MISC_REG4,
+ B43_NPHY_REV7_RF_CTL_MISC_REG5, B43_NPHY_REV7_RF_CTL_MISC_REG6,
B43_NPHY_RFCTL_RSSIO1, B43_NPHY_RFCTL_RSSIO2
};
u16 *regs_to_store;
@@ -1877,9 +2111,24 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_TRSW, 1, 7);
if (dev->phy.rev >= 7) {
- /* TODO */
+ b43_nphy_rf_ctl_override_one_to_many(dev,
+ N_RF_CTL_OVER_CMD_RXRF_PU,
+ 0, 0, false);
+ b43_nphy_rf_ctl_override_one_to_many(dev,
+ N_RF_CTL_OVER_CMD_RX_PU,
+ 1, 0, false);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x80, 1, 0, false, 0);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x40, 1, 0, false, 0);
if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+ b43_nphy_rf_ctl_override_rev7(dev, 0x20, 0, 0, false,
+ 0);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x10, 1, 0, false,
+ 0);
} else {
+ b43_nphy_rf_ctl_override_rev7(dev, 0x10, 0, 0, false,
+ 0);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x20, 1, 0, false,
+ 0);
}
} else {
b43_nphy_rf_ctl_override(dev, 0x1, 0, 0, false);
@@ -1908,7 +2157,10 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
/* Grab RSSI results for every possible VCM */
for (vcm = 0; vcm < 8; vcm++) {
if (dev->phy.rev >= 7)
- ;
+ b43_radio_maskset(dev,
+ core ? R2057_NB_MASTER_CORE1 :
+ R2057_NB_MASTER_CORE0,
+ ~R2057_VCM_MASK, vcm);
else
b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC,
0xE3, vcm << 2);
@@ -1939,7 +2191,10 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
/* Select the best VCM */
if (dev->phy.rev >= 7)
- ;
+ b43_radio_maskset(dev,
+ core ? R2057_NB_MASTER_CORE1 :
+ R2057_NB_MASTER_CORE0,
+ ~R2057_VCM_MASK, vcm);
else
b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC,
0xE3, vcm_final << 2);
@@ -2009,6 +2264,10 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G;
}
if (dev->phy.rev >= 7) {
+ rssical_radio_regs[0] = b43_radio_read(dev,
+ R2057_NB_MASTER_CORE0);
+ rssical_radio_regs[1] = b43_radio_read(dev,
+ R2057_NB_MASTER_CORE1);
} else {
rssical_radio_regs[0] = b43_radio_read(dev, B2056_RX0 |
B2056_RX_RSSI_MISC);
@@ -2209,7 +2468,9 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, enum n_rssi_type type)
*/
static void b43_nphy_rssi_cal(struct b43_wldev *dev)
{
- if (dev->phy.rev >= 3) {
+ if (dev->phy.rev >= 19) {
+ /* TODO */
+ } else if (dev->phy.rev >= 3) {
b43_nphy_rev3_rssi_cal(dev);
} else {
b43_nphy_rev2_rssi_cal(dev, N_RSSI_NB);
@@ -2222,7 +2483,21 @@ static void b43_nphy_rssi_cal(struct b43_wldev *dev)
* Workarounds
**************************************************/
-static void b43_nphy_gain_ctl_workarounds_rev3plus(struct b43_wldev *dev)
+static void b43_nphy_gain_ctl_workarounds_rev19(struct b43_wldev *dev)
+{
+ /* TODO */
+}
+
+static void b43_nphy_gain_ctl_workarounds_rev7(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ switch (phy->rev) {
+ /* TODO */
+ }
+}
+
+static void b43_nphy_gain_ctl_workarounds_rev3(struct b43_wldev *dev)
{
struct ssb_sprom *sprom = dev->dev->bus_sprom;
@@ -2419,46 +2694,54 @@ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev)
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
static void b43_nphy_gain_ctl_workarounds(struct b43_wldev *dev)
{
- if (dev->phy.rev >= 7)
- ; /* TODO */
+ if (dev->phy.rev >= 19)
+ b43_nphy_gain_ctl_workarounds_rev19(dev);
+ else if (dev->phy.rev >= 7)
+ b43_nphy_gain_ctl_workarounds_rev7(dev);
else if (dev->phy.rev >= 3)
- b43_nphy_gain_ctl_workarounds_rev3plus(dev);
+ b43_nphy_gain_ctl_workarounds_rev3(dev);
else
b43_nphy_gain_ctl_workarounds_rev1_2(dev);
}
-/* http://bcm-v4.sipsolutions.net/PHY/N/Read_Lpf_Bw_Ctl */
-static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset)
-{
- if (!offset)
- offset = b43_is_40mhz(dev) ? 0x159 : 0x154;
- return b43_ntab_read(dev, B43_NTAB16(7, offset)) & 0x7;
-}
-
static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
{
struct ssb_sprom *sprom = dev->dev->bus_sprom;
struct b43_phy *phy = &dev->phy;
+ /* TX to RX */
+ u8 tx2rx_events[7] = { 4, 3, 5, 2, 1, 8, 31, };
+ u8 tx2rx_delays[7] = { 8, 4, 4, 4, 4, 6, 1, };
+ /* RX to TX */
u8 rx2tx_events_ipa[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0xF, 0x3,
0x1F };
u8 rx2tx_delays_ipa[9] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 };
- u16 ntab7_15e_16e[] = { 0x10f, 0x10f };
+ static const u16 ntab7_15e_16e[] = { 0, 0x10f, 0x10f };
u8 ntab7_138_146[] = { 0x11, 0x11 };
u8 ntab7_133[] = { 0x77, 0x11, 0x11 };
- u16 lpf_20, lpf_40, lpf_11b;
- u16 bcap_val, bcap_val_11b, bcap_val_11n_20, bcap_val_11n_40;
- u16 scap_val, scap_val_11b, scap_val_11n_20, scap_val_11n_40;
+ u16 lpf_ofdm_20mhz[2], lpf_ofdm_40mhz[2], lpf_11b[2];
+ u16 bcap_val;
+ s16 bcap_val_11b[2], bcap_val_11n_20[2], bcap_val_11n_40[2];
+ u16 scap_val;
+ s16 scap_val_11b[2], scap_val_11n_20[2], scap_val_11n_40[2];
bool rccal_ovrd = false;
- u16 rx2tx_lut_20_11b, rx2tx_lut_20_11n, rx2tx_lut_40_11n;
u16 bias, conv, filt;
+ u32 noise_tbl[2];
+
u32 tmp32;
u8 core;
+ b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x0125);
+ b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x01b3);
+ b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x0105);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x016e);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0x00cd);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x0020);
+
if (phy->rev == 7) {
b43_phy_set(dev, B43_NPHY_FINERX2_CGC, 0x10);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN0, 0xFF80, 0x0020);
@@ -2478,11 +2761,18 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
b43_phy_maskset(dev, B43_NPHY_FREQGAIN7, 0xFF80, 0x0040);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN7, 0x80FF, 0x4000);
}
- if (phy->rev <= 8) {
+
+ if (phy->rev >= 16) {
+ b43_phy_write(dev, B43_NPHY_FORCEFRONT0, 0x7ff);
+ b43_phy_write(dev, B43_NPHY_FORCEFRONT1, 0x7ff);
+ } else if (phy->rev <= 8) {
b43_phy_write(dev, B43_NPHY_FORCEFRONT0, 0x1B0);
b43_phy_write(dev, B43_NPHY_FORCEFRONT1, 0x1B0);
}
- if (phy->rev >= 8)
+
+ if (phy->rev >= 16)
+ b43_phy_maskset(dev, B43_NPHY_TXTAILCNT, ~0xFF, 0xa0);
+ else if (phy->rev >= 8)
b43_phy_maskset(dev, B43_NPHY_TXTAILCNT, ~0xFF, 0x72);
b43_ntab_write(dev, B43_NTAB16(8, 0x00), 2);
@@ -2490,9 +2780,11 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
tmp32 = b43_ntab_read(dev, B43_NTAB32(30, 0));
tmp32 &= 0xffffff;
b43_ntab_write(dev, B43_NTAB32(30, 0), tmp32);
- b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x15e), 2, ntab7_15e_16e);
- b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x16e), 2, ntab7_15e_16e);
+ b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x15d), 3, ntab7_15e_16e);
+ b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x16d), 3, ntab7_15e_16e);
+ b43_nphy_set_rf_sequence(dev, 1, tx2rx_events, tx2rx_delays,
+ ARRAY_SIZE(tx2rx_events));
if (b43_nphy_ipa(dev))
b43_nphy_set_rf_sequence(dev, 0, rx2tx_events_ipa,
rx2tx_delays_ipa, ARRAY_SIZE(rx2tx_events_ipa));
@@ -2500,84 +2792,176 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
b43_phy_maskset(dev, B43_NPHY_EPS_OVERRIDEI_0, 0x3FFF, 0x4000);
b43_phy_maskset(dev, B43_NPHY_EPS_OVERRIDEI_1, 0x3FFF, 0x4000);
- lpf_20 = b43_nphy_read_lpf_ctl(dev, 0x154);
- lpf_40 = b43_nphy_read_lpf_ctl(dev, 0x159);
- lpf_11b = b43_nphy_read_lpf_ctl(dev, 0x152);
+ for (core = 0; core < 2; core++) {
+ lpf_ofdm_20mhz[core] = b43_nphy_read_lpf_ctl(dev, 0x154 + core * 0x10);
+ lpf_ofdm_40mhz[core] = b43_nphy_read_lpf_ctl(dev, 0x159 + core * 0x10);
+ lpf_11b[core] = b43_nphy_read_lpf_ctl(dev, 0x152 + core * 0x10);
+ }
+
+ bcap_val = b43_radio_read(dev, R2057_RCCAL_BCAP_VAL);
+ scap_val = b43_radio_read(dev, R2057_RCCAL_SCAP_VAL);
+
if (b43_nphy_ipa(dev)) {
- if ((phy->radio_rev == 5 && b43_is_40mhz(dev)) ||
- phy->radio_rev == 7 || phy->radio_rev == 8) {
- bcap_val = b43_radio_read(dev, 0x16b);
- scap_val = b43_radio_read(dev, 0x16a);
- scap_val_11b = scap_val;
- bcap_val_11b = bcap_val;
- if (phy->radio_rev == 5 && b43_is_40mhz(dev)) {
- scap_val_11n_20 = scap_val;
- bcap_val_11n_20 = bcap_val;
- scap_val_11n_40 = bcap_val_11n_40 = 0xc;
+ bool ghz2 = b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ;
+
+ switch (phy->radio_rev) {
+ case 5:
+ /* Check radio version (to be 0) by PHY rev for now */
+ if (phy->rev == 8 && b43_is_40mhz(dev)) {
+ for (core = 0; core < 2; core++) {
+ scap_val_11b[core] = scap_val;
+ bcap_val_11b[core] = bcap_val;
+ scap_val_11n_20[core] = scap_val;
+ bcap_val_11n_20[core] = bcap_val;
+ scap_val_11n_40[core] = 0xc;
+ bcap_val_11n_40[core] = 0xc;
+ }
+
rccal_ovrd = true;
- } else { /* Rev 7/8 */
- lpf_20 = 4;
- lpf_11b = 1;
+ }
+ if (phy->rev == 9) {
+ /* TODO: Radio version 1 (e.g. BCM5357B0) */
+ }
+ break;
+ case 7:
+ case 8:
+ for (core = 0; core < 2; core++) {
+ scap_val_11b[core] = scap_val;
+ bcap_val_11b[core] = bcap_val;
+ lpf_ofdm_20mhz[core] = 4;
+ lpf_11b[core] = 1;
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
- scap_val_11n_20 = 0xc;
- bcap_val_11n_20 = 0xc;
- scap_val_11n_40 = 0xa;
- bcap_val_11n_40 = 0xa;
+ scap_val_11n_20[core] = 0xc;
+ bcap_val_11n_20[core] = 0xc;
+ scap_val_11n_40[core] = 0xa;
+ bcap_val_11n_40[core] = 0xa;
} else {
- scap_val_11n_20 = 0x14;
- bcap_val_11n_20 = 0x14;
- scap_val_11n_40 = 0xf;
- bcap_val_11n_40 = 0xf;
+ scap_val_11n_20[core] = 0x14;
+ bcap_val_11n_20[core] = 0x14;
+ scap_val_11n_40[core] = 0xf;
+ bcap_val_11n_40[core] = 0xf;
}
- rccal_ovrd = true;
}
+
+ rccal_ovrd = true;
+ break;
+ case 9:
+ for (core = 0; core < 2; core++) {
+ bcap_val_11b[core] = bcap_val;
+ scap_val_11b[core] = scap_val;
+ lpf_11b[core] = 1;
+
+ if (ghz2) {
+ bcap_val_11n_20[core] = bcap_val + 13;
+ scap_val_11n_20[core] = scap_val + 15;
+ } else {
+ bcap_val_11n_20[core] = bcap_val + 14;
+ scap_val_11n_20[core] = scap_val + 15;
+ }
+ lpf_ofdm_20mhz[core] = 4;
+
+ if (ghz2) {
+ bcap_val_11n_40[core] = bcap_val - 7;
+ scap_val_11n_40[core] = scap_val - 5;
+ } else {
+ bcap_val_11n_40[core] = bcap_val + 2;
+ scap_val_11n_40[core] = scap_val + 4;
+ }
+ lpf_ofdm_40mhz[core] = 4;
+ }
+
+ rccal_ovrd = true;
+ break;
+ case 14:
+ for (core = 0; core < 2; core++) {
+ bcap_val_11b[core] = bcap_val;
+ scap_val_11b[core] = scap_val;
+ lpf_11b[core] = 1;
+ }
+
+ bcap_val_11n_20[0] = bcap_val + 20;
+ scap_val_11n_20[0] = scap_val + 20;
+ lpf_ofdm_20mhz[0] = 3;
+
+ bcap_val_11n_20[1] = bcap_val + 16;
+ scap_val_11n_20[1] = scap_val + 16;
+ lpf_ofdm_20mhz[1] = 3;
+
+ bcap_val_11n_40[0] = bcap_val + 20;
+ scap_val_11n_40[0] = scap_val + 20;
+ lpf_ofdm_40mhz[0] = 4;
+
+ bcap_val_11n_40[1] = bcap_val + 10;
+ scap_val_11n_40[1] = scap_val + 10;
+ lpf_ofdm_40mhz[1] = 4;
+
+ rccal_ovrd = true;
+ break;
}
} else {
if (phy->radio_rev == 5) {
- lpf_20 = 1;
- lpf_40 = 3;
- bcap_val = b43_radio_read(dev, 0x16b);
- scap_val = b43_radio_read(dev, 0x16a);
- scap_val_11b = scap_val;
- bcap_val_11b = bcap_val;
- scap_val_11n_20 = 0x11;
- scap_val_11n_40 = 0x11;
- bcap_val_11n_20 = 0x13;
- bcap_val_11n_40 = 0x13;
+ for (core = 0; core < 2; core++) {
+ lpf_ofdm_20mhz[core] = 1;
+ lpf_ofdm_40mhz[core] = 3;
+ scap_val_11b[core] = scap_val;
+ bcap_val_11b[core] = bcap_val;
+ scap_val_11n_20[core] = 0x11;
+ scap_val_11n_40[core] = 0x11;
+ bcap_val_11n_20[core] = 0x13;
+ bcap_val_11n_40[core] = 0x13;
+ }
+
rccal_ovrd = true;
}
}
if (rccal_ovrd) {
- rx2tx_lut_20_11b = (bcap_val_11b << 8) |
- (scap_val_11b << 3) |
- lpf_11b;
- rx2tx_lut_20_11n = (bcap_val_11n_20 << 8) |
- (scap_val_11n_20 << 3) |
- lpf_20;
- rx2tx_lut_40_11n = (bcap_val_11n_40 << 8) |
- (scap_val_11n_40 << 3) |
- lpf_40;
+ u16 rx2tx_lut_20_11b[2], rx2tx_lut_20_11n[2], rx2tx_lut_40_11n[2];
+ u8 rx2tx_lut_extra = 1;
+
+ for (core = 0; core < 2; core++) {
+ bcap_val_11b[core] = clamp_val(bcap_val_11b[core], 0, 0x1f);
+ scap_val_11b[core] = clamp_val(scap_val_11b[core], 0, 0x1f);
+ bcap_val_11n_20[core] = clamp_val(bcap_val_11n_20[core], 0, 0x1f);
+ scap_val_11n_20[core] = clamp_val(scap_val_11n_20[core], 0, 0x1f);
+ bcap_val_11n_40[core] = clamp_val(bcap_val_11n_40[core], 0, 0x1f);
+ scap_val_11n_40[core] = clamp_val(scap_val_11n_40[core], 0, 0x1f);
+
+ rx2tx_lut_20_11b[core] = (rx2tx_lut_extra << 13) |
+ (bcap_val_11b[core] << 8) |
+ (scap_val_11b[core] << 3) |
+ lpf_11b[core];
+ rx2tx_lut_20_11n[core] = (rx2tx_lut_extra << 13) |
+ (bcap_val_11n_20[core] << 8) |
+ (scap_val_11n_20[core] << 3) |
+ lpf_ofdm_20mhz[core];
+ rx2tx_lut_40_11n[core] = (rx2tx_lut_extra << 13) |
+ (bcap_val_11n_40[core] << 8) |
+ (scap_val_11n_40[core] << 3) |
+ lpf_ofdm_40mhz[core];
+ }
+
for (core = 0; core < 2; core++) {
b43_ntab_write(dev, B43_NTAB16(7, 0x152 + core * 16),
- rx2tx_lut_20_11b);
+ rx2tx_lut_20_11b[core]);
b43_ntab_write(dev, B43_NTAB16(7, 0x153 + core * 16),
- rx2tx_lut_20_11n);
+ rx2tx_lut_20_11n[core]);
b43_ntab_write(dev, B43_NTAB16(7, 0x154 + core * 16),
- rx2tx_lut_20_11n);
+ rx2tx_lut_20_11n[core]);
b43_ntab_write(dev, B43_NTAB16(7, 0x155 + core * 16),
- rx2tx_lut_40_11n);
+ rx2tx_lut_40_11n[core]);
b43_ntab_write(dev, B43_NTAB16(7, 0x156 + core * 16),
- rx2tx_lut_40_11n);
+ rx2tx_lut_40_11n[core]);
b43_ntab_write(dev, B43_NTAB16(7, 0x157 + core * 16),
- rx2tx_lut_40_11n);
+ rx2tx_lut_40_11n[core]);
b43_ntab_write(dev, B43_NTAB16(7, 0x158 + core * 16),
- rx2tx_lut_40_11n);
+ rx2tx_lut_40_11n[core]);
b43_ntab_write(dev, B43_NTAB16(7, 0x159 + core * 16),
- rx2tx_lut_40_11n);
+ rx2tx_lut_40_11n[core]);
}
- b43_nphy_rf_ctl_override_rev7(dev, 16, 1, 3, false, 2);
}
+
b43_phy_write(dev, 0x32F, 0x3);
+
if (phy->radio_rev == 4 || phy->radio_rev == 6)
b43_nphy_rf_ctl_override_rev7(dev, 4, 1, 3, false, 0);
@@ -2625,7 +3009,8 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
0x7f);
}
}
- if (phy->radio_rev == 3) {
+ switch (phy->radio_rev) {
+ case 3:
for (core = 0; core < 2; core++) {
if (core == 0) {
b43_radio_write(dev, 0x64,
@@ -2651,7 +3036,9 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
0x3E);
}
}
- } else if (phy->radio_rev == 7 || phy->radio_rev == 8) {
+ break;
+ case 7:
+ case 8:
if (!b43_is_40mhz(dev)) {
b43_radio_write(dev, 0x5F, 0x14);
b43_radio_write(dev, 0xE8, 0x12);
@@ -2659,6 +3046,21 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
b43_radio_write(dev, 0x5F, 0x16);
b43_radio_write(dev, 0xE8, 0x16);
}
+ break;
+ case 14:
+ for (core = 0; core < 2; core++) {
+ int o = core ? 0x85 : 0;
+
+ b43_radio_write(dev, o + R2057_IPA2G_CASCONV_CORE0, 0x13);
+ b43_radio_write(dev, o + R2057_TXMIX2G_TUNE_BOOST_PU_CORE0, 0x21);
+ b43_radio_write(dev, o + R2057_IPA2G_BIAS_FILTER_CORE0, 0xff);
+ b43_radio_write(dev, o + R2057_PAD2G_IDACS_CORE0, 0x88);
+ b43_radio_write(dev, o + R2057_PAD2G_TUNE_PUS_CORE0, 0x23);
+ b43_radio_write(dev, o + R2057_IPA2G_IMAIN_CORE0, 0x16);
+ b43_radio_write(dev, o + R2057_PAD_BIAS_FILTER_BWS_CORE0, 0x3e);
+ b43_radio_write(dev, o + R2057_BACKUP1_CORE0, 0x10);
+ }
+ break;
}
} else {
u16 freq = phy->chandef->chan->center_freq;
@@ -2706,8 +3108,8 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x1);
b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x1);
b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x1);
- b43_ntab_write(dev, B43_NTAB16(8, 0x05), 0x20);
- b43_ntab_write(dev, B43_NTAB16(8, 0x15), 0x20);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x05), 0);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x15), 0);
b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x4);
b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, ~0x4);
@@ -2718,20 +3120,20 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_ENDROP_TLEN, 0x2);
b43_ntab_write(dev, B43_NTAB32(16, 0x100), 20);
- b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x138), 2, ntab7_138_146);
+ b43_ntab_write_bulk(dev, B43_NTAB8(7, 0x138), 2, ntab7_138_146);
b43_ntab_write(dev, B43_NTAB16(7, 0x141), 0x77);
- b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x133), 3, ntab7_133);
- b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x146), 2, ntab7_138_146);
+ b43_ntab_write_bulk(dev, B43_NTAB8(7, 0x133), 3, ntab7_133);
+ b43_ntab_write_bulk(dev, B43_NTAB8(7, 0x146), 2, ntab7_138_146);
b43_ntab_write(dev, B43_NTAB16(7, 0x123), 0x77);
b43_ntab_write(dev, B43_NTAB16(7, 0x12A), 0x77);
- if (!b43_is_40mhz(dev)) {
- b43_ntab_write(dev, B43_NTAB32(16, 0x03), 0x18D);
- b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x18D);
- } else {
- b43_ntab_write(dev, B43_NTAB32(16, 0x03), 0x14D);
- b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x14D);
- }
+ b43_ntab_read_bulk(dev, B43_NTAB32(16, 0x02), 1, noise_tbl);
+ noise_tbl[1] = b43_is_40mhz(dev) ? 0x14D : 0x18D;
+ b43_ntab_write_bulk(dev, B43_NTAB32(16, 0x02), 2, noise_tbl);
+
+ b43_ntab_read_bulk(dev, B43_NTAB32(16, 0x7E), 1, noise_tbl);
+ noise_tbl[1] = b43_is_40mhz(dev) ? 0x14D : 0x18D;
+ b43_ntab_write_bulk(dev, B43_NTAB32(16, 0x7E), 2, noise_tbl);
b43_nphy_gain_ctl_workarounds(dev);
@@ -3059,6 +3461,7 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
b43_phy_set(dev, B43_NPHY_IQFLIP,
B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
+ /* TODO: rev19+ */
if (dev->phy.rev >= 7)
b43_nphy_workarounds_rev7plus(dev);
else if (dev->phy.rev >= 3)
@@ -3120,6 +3523,7 @@ static void b43_nphy_update_txrx_chain(struct b43_wldev *dev)
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */
static void b43_nphy_stop_playback(struct b43_wldev *dev)
{
+ struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = dev->phy.n;
u16 tmp;
@@ -3140,6 +3544,15 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev)
nphy->bb_mult_save = 0;
}
+ if (phy->rev >= 7 && nphy->lpf_bw_overrode_for_sample_play) {
+ if (phy->rev >= 19)
+ b43_nphy_rf_ctl_override_rev19(dev, 0x80, 0, 0, true,
+ 1);
+ else
+ b43_nphy_rf_ctl_override_rev7(dev, 0x80, 0, 0, true, 1);
+ nphy->lpf_bw_overrode_for_sample_play = false;
+ }
+
if (nphy->hang_avoid)
b43_nphy_stay_in_carrier_search(dev, 0);
}
@@ -3149,16 +3562,23 @@ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core,
struct nphy_txgains target,
struct nphy_iqcal_params *params)
{
+ struct b43_phy *phy = &dev->phy;
int i, j, indx;
u16 gain;
if (dev->phy.rev >= 3) {
+ params->tx_lpf = target.tx_lpf[core]; /* Rev 7+ */
params->txgm = target.txgm[core];
params->pga = target.pga[core];
params->pad = target.pad[core];
params->ipa = target.ipa[core];
- params->cal_gain = (params->txgm << 12) | (params->pga << 8) |
- (params->pad << 4) | (params->ipa);
+ if (phy->rev >= 19) {
+ /* TODO */
+ } else if (phy->rev >= 7) {
+ params->cal_gain = (params->txgm << 12) | (params->pga << 8) | (params->pad << 3) | (params->ipa) | (params->tx_lpf << 15);
+ } else {
+ params->cal_gain = (params->txgm << 12) | (params->pga << 8) | (params->pad << 4) | (params->ipa);
+ }
for (j = 0; j < 5; j++)
params->ncorr[j] = 0x79;
} else {
@@ -3199,6 +3619,7 @@ static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */
static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
{
+ struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = dev->phy.n;
u8 i;
u16 bmask, val, tmp;
@@ -3268,12 +3689,25 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD, ~(bmask), val);
if (band == IEEE80211_BAND_5GHZ) {
- b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD,
- ~B43_NPHY_TXPCTL_CMD_INIT, 0x64);
- if (dev->phy.rev > 1)
+ if (phy->rev >= 19) {
+ /* TODO */
+ } else if (phy->rev >= 7) {
+ b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD,
+ ~B43_NPHY_TXPCTL_CMD_INIT,
+ 0x32);
b43_phy_maskset(dev, B43_NPHY_TXPCTL_INIT,
~B43_NPHY_TXPCTL_INIT_PIDXI1,
+ 0x32);
+ } else {
+ b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD,
+ ~B43_NPHY_TXPCTL_CMD_INIT,
0x64);
+ if (phy->rev > 1)
+ b43_phy_maskset(dev,
+ B43_NPHY_TXPCTL_INIT,
+ ~B43_NPHY_TXPCTL_INIT_PIDXI1,
+ 0x64);
+ }
}
if (dev->phy.rev >= 3) {
@@ -3290,6 +3724,10 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
}
}
+ if (phy->rev >= 7) {
+ /* TODO */
+ }
+
if (dev->phy.rev >= 3) {
b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, ~0x100);
b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x100);
@@ -3331,6 +3769,7 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
if (nphy->hang_avoid)
b43_nphy_stay_in_carrier_search(dev, 1);
+ /* TODO: rev19+ */
if (dev->phy.rev >= 7) {
txpi[0] = txpi[1] = 30;
} else if (dev->phy.rev >= 3) {
@@ -3433,7 +3872,9 @@ static void b43_nphy_ipa_internal_tssi_setup(struct b43_wldev *dev)
u8 core;
u16 r; /* routing */
- if (phy->rev >= 7) {
+ if (phy->rev >= 19) {
+ /* TODO */
+ } else if (phy->rev >= 7) {
for (core = 0; core < 2; core++) {
r = core ? 0x190 : 0x170;
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
@@ -3516,13 +3957,16 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
u32 tmp;
s32 rssi[4] = { };
- /* TODO: check if we can transmit */
+ if (phy->chandef->chan->flags & IEEE80211_CHAN_NO_IR)
+ return;
if (b43_nphy_ipa(dev))
b43_nphy_ipa_internal_tssi_setup(dev);
- if (phy->rev >= 7)
- b43_nphy_rf_ctl_override_rev7(dev, 0x2000, 0, 3, false, 0);
+ if (phy->rev >= 19)
+ b43_nphy_rf_ctl_override_rev19(dev, 0x1000, 0, 3, false, 0);
+ else if (phy->rev >= 7)
+ b43_nphy_rf_ctl_override_rev7(dev, 0x1000, 0, 3, false, 0);
else if (phy->rev >= 3)
b43_nphy_rf_ctl_override(dev, 0x2000, 0, 3, false);
@@ -3531,14 +3975,20 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
udelay(20);
tmp = b43_nphy_poll_rssi(dev, N_RSSI_TSSI_2G, rssi, 1);
b43_nphy_stop_playback(dev);
+
b43_nphy_rssi_select(dev, 0, N_RSSI_W1);
- if (phy->rev >= 7)
- b43_nphy_rf_ctl_override_rev7(dev, 0x2000, 0, 3, true, 0);
+ if (phy->rev >= 19)
+ b43_nphy_rf_ctl_override_rev19(dev, 0x1000, 0, 3, true, 0);
+ else if (phy->rev >= 7)
+ b43_nphy_rf_ctl_override_rev7(dev, 0x1000, 0, 3, true, 0);
else if (phy->rev >= 3)
b43_nphy_rf_ctl_override(dev, 0x2000, 0, 3, true);
- if (phy->rev >= 3) {
+ if (phy->rev >= 19) {
+ /* TODO */
+ return;
+ } else if (phy->rev >= 3) {
nphy->pwr_ctl_info[0].idle_tssi_5g = (tmp >> 24) & 0xFF;
nphy->pwr_ctl_info[1].idle_tssi_5g = (tmp >> 8) & 0xFF;
} else {
@@ -3730,7 +4180,9 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev)
udelay(1);
}
- if (dev->phy.rev >= 7) {
+ if (phy->rev >= 19) {
+ /* TODO */
+ } else if (phy->rev >= 7) {
b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD,
~B43_NPHY_TXPCTL_CMD_INIT, 0x19);
b43_phy_maskset(dev, B43_NPHY_TXPCTL_INIT,
@@ -3793,24 +4245,30 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev)
b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128, table);
b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128, table);
- if (phy->rev >= 3) {
+ if (phy->rev < 3)
+ return;
+
#if 0
- nphy->gmval = (table[0] >> 16) & 0x7000;
+ nphy->gmval = (table[0] >> 16) & 0x7000;
#endif
- for (i = 0; i < 128; i++) {
+ for (i = 0; i < 128; i++) {
+ if (phy->rev >= 19) {
+ /* TODO */
+ return;
+ } else if (phy->rev >= 7) {
+ /* TODO */
+ return;
+ } else {
pga_gain = (table[i] >> 24) & 0xF;
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
- rfpwr_offset =
- b43_ntab_papd_pga_gain_delta_ipa_2g[pga_gain];
+ rfpwr_offset = b43_ntab_papd_pga_gain_delta_ipa_2g[pga_gain];
else
- rfpwr_offset =
- 0; /* FIXME */
- b43_ntab_write(dev, B43_NTAB32(26, 576 + i),
- rfpwr_offset);
- b43_ntab_write(dev, B43_NTAB32(27, 576 + i),
- rfpwr_offset);
+ rfpwr_offset = 0; /* FIXME */
}
+
+ b43_ntab_write(dev, B43_NTAB32(26, 576 + i), rfpwr_offset);
+ b43_ntab_write(dev, B43_NTAB32(27, 576 + i), rfpwr_offset);
}
}
@@ -3827,7 +4285,9 @@ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable)
nphy->rfctrl_intc2_save = b43_phy_read(dev,
B43_NPHY_RFCTL_INTC2);
band = b43_current_band(dev->wl);
- if (dev->phy.rev >= 3) {
+ if (dev->phy.rev >= 7) {
+ tmp = 0x1480;
+ } else if (dev->phy.rev >= 3) {
if (band == IEEE80211_BAND_5GHZ)
tmp = 0x600;
else
@@ -4274,7 +4734,13 @@ static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev)
rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G;
}
- if (dev->phy.rev >= 7) {
+ if (dev->phy.rev >= 19) {
+ /* TODO */
+ } else if (dev->phy.rev >= 7) {
+ b43_radio_maskset(dev, R2057_NB_MASTER_CORE0, ~R2057_VCM_MASK,
+ rssical_radio_regs[0]);
+ b43_radio_maskset(dev, R2057_NB_MASTER_CORE1, ~R2057_VCM_MASK,
+ rssical_radio_regs[1]);
} else {
b43_radio_maskset(dev, B2056_RX0 | B2056_RX_RSSI_MISC, 0xE3,
rssical_radio_regs[0]);
@@ -4298,15 +4764,78 @@ static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, rssical_phy_regs[11]);
}
+static void b43_nphy_tx_cal_radio_setup_rev19(struct b43_wldev *dev)
+{
+ /* TODO */
+}
+
+static void b43_nphy_tx_cal_radio_setup_rev7(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_phy_n *nphy = dev->phy.n;
+ u16 *save = nphy->tx_rx_cal_radio_saveregs;
+ int core, off;
+ u16 r, tmp;
+
+ for (core = 0; core < 2; core++) {
+ r = core ? 0x20 : 0;
+ off = core * 11;
+
+ save[off + 0] = b43_radio_read(dev, r + R2057_TX0_TX_SSI_MASTER);
+ save[off + 1] = b43_radio_read(dev, r + R2057_TX0_IQCAL_VCM_HG);
+ save[off + 2] = b43_radio_read(dev, r + R2057_TX0_IQCAL_IDAC);
+ save[off + 3] = b43_radio_read(dev, r + R2057_TX0_TSSI_VCM);
+ save[off + 4] = 0;
+ save[off + 5] = b43_radio_read(dev, r + R2057_TX0_TX_SSI_MUX);
+ if (phy->radio_rev != 5)
+ save[off + 6] = b43_radio_read(dev, r + R2057_TX0_TSSIA);
+ save[off + 7] = b43_radio_read(dev, r + R2057_TX0_TSSIG);
+ save[off + 8] = b43_radio_read(dev, r + R2057_TX0_TSSI_MISC1);
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+ b43_radio_write(dev, r + R2057_TX0_TX_SSI_MASTER, 0xA);
+ b43_radio_write(dev, r + R2057_TX0_IQCAL_VCM_HG, 0x43);
+ b43_radio_write(dev, r + R2057_TX0_IQCAL_IDAC, 0x55);
+ b43_radio_write(dev, r + R2057_TX0_TSSI_VCM, 0);
+ b43_radio_write(dev, r + R2057_TX0_TSSIG, 0);
+ if (nphy->use_int_tx_iq_lo_cal) {
+ b43_radio_write(dev, r + R2057_TX0_TX_SSI_MUX, 0x4);
+ tmp = true ? 0x31 : 0x21; /* TODO */
+ b43_radio_write(dev, r + R2057_TX0_TSSIA, tmp);
+ }
+ b43_radio_write(dev, r + R2057_TX0_TSSI_MISC1, 0x00);
+ } else {
+ b43_radio_write(dev, r + R2057_TX0_TX_SSI_MASTER, 0x6);
+ b43_radio_write(dev, r + R2057_TX0_IQCAL_VCM_HG, 0x43);
+ b43_radio_write(dev, r + R2057_TX0_IQCAL_IDAC, 0x55);
+ b43_radio_write(dev, r + R2057_TX0_TSSI_VCM, 0);
+
+ if (phy->radio_rev != 5)
+ b43_radio_write(dev, r + R2057_TX0_TSSIA, 0);
+ if (nphy->use_int_tx_iq_lo_cal) {
+ b43_radio_write(dev, r + R2057_TX0_TX_SSI_MUX, 0x6);
+ tmp = true ? 0x31 : 0x21; /* TODO */
+ b43_radio_write(dev, r + R2057_TX0_TSSIG, tmp);
+ }
+ b43_radio_write(dev, r + R2057_TX0_TSSI_MISC1, 0);
+ }
+ }
+}
+
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */
static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev)
{
+ struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = dev->phy.n;
u16 *save = nphy->tx_rx_cal_radio_saveregs;
u16 tmp;
u8 offset, i;
- if (dev->phy.rev >= 3) {
+ if (phy->rev >= 19) {
+ b43_nphy_tx_cal_radio_setup_rev19(dev);
+ } else if (phy->rev >= 7) {
+ b43_nphy_tx_cal_radio_setup_rev7(dev);
+ } else if (phy->rev >= 3) {
for (i = 0; i < 2; i++) {
tmp = (i == 0) ? 0x2000 : 0x3000;
offset = i * 11;
@@ -4415,41 +4944,61 @@ static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core)
}
}
+static void b43_nphy_pa_set_tx_dig_filter(struct b43_wldev *dev, u16 offset,
+ const s16 *filter)
+{
+ int i;
+
+ offset = B43_PHY_N(offset);
+
+ for (i = 0; i < 15; i++, offset++)
+ b43_phy_write(dev, offset, filter[i]);
+}
+
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ExtPaSetTxDigiFilts */
static void b43_nphy_ext_pa_set_tx_dig_filters(struct b43_wldev *dev)
{
- int i;
- for (i = 0; i < 15; i++)
- b43_phy_write(dev, B43_PHY_N(0x2C5 + i),
- tbl_tx_filter_coef_rev4[2][i]);
+ b43_nphy_pa_set_tx_dig_filter(dev, 0x2C5,
+ tbl_tx_filter_coef_rev4[2]);
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IpaSetTxDigiFilts */
static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev)
{
- int i, j;
/* B43_NPHY_TXF_20CO_S0A1, B43_NPHY_TXF_40CO_S0A1, unknown */
static const u16 offset[] = { 0x186, 0x195, 0x2C5 };
+ static const s16 dig_filter_phy_rev16[] = {
+ -375, 136, -407, 208, -1527,
+ 956, 93, 186, 93, 230,
+ -44, 230, 201, -191, 201,
+ };
+ int i;
for (i = 0; i < 3; i++)
- for (j = 0; j < 15; j++)
- b43_phy_write(dev, B43_PHY_N(offset[i] + j),
- tbl_tx_filter_coef_rev4[i][j]);
+ b43_nphy_pa_set_tx_dig_filter(dev, offset[i],
+ tbl_tx_filter_coef_rev4[i]);
+
+ /* Verified with BCM43227 and BCM43228 */
+ if (dev->phy.rev == 16)
+ b43_nphy_pa_set_tx_dig_filter(dev, 0x186, dig_filter_phy_rev16);
+
+ if (dev->dev->chip_id == BCMA_CHIP_ID_BCM43217) {
+ b43_nphy_pa_set_tx_dig_filter(dev, 0x186, dig_filter_phy_rev16);
+ b43_nphy_pa_set_tx_dig_filter(dev, 0x195,
+ tbl_tx_filter_coef_rev4[1]);
+ }
if (b43_is_40mhz(dev)) {
- for (j = 0; j < 15; j++)
- b43_phy_write(dev, B43_PHY_N(offset[0] + j),
- tbl_tx_filter_coef_rev4[3][j]);
- } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
- for (j = 0; j < 15; j++)
- b43_phy_write(dev, B43_PHY_N(offset[0] + j),
- tbl_tx_filter_coef_rev4[5][j]);
- }
-
- if (dev->phy.channel == 14)
- for (j = 0; j < 15; j++)
- b43_phy_write(dev, B43_PHY_N(offset[0] + j),
- tbl_tx_filter_coef_rev4[6][j]);
+ b43_nphy_pa_set_tx_dig_filter(dev, 0x186,
+ tbl_tx_filter_coef_rev4[3]);
+ } else {
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+ b43_nphy_pa_set_tx_dig_filter(dev, 0x186,
+ tbl_tx_filter_coef_rev4[5]);
+ if (dev->phy.channel == 14)
+ b43_nphy_pa_set_tx_dig_filter(dev, 0x186,
+ tbl_tx_filter_coef_rev4[6]);
+ }
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */
@@ -4471,7 +5020,13 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev)
b43_nphy_stay_in_carrier_search(dev, false);
for (i = 0; i < 2; ++i) {
- if (dev->phy.rev >= 3) {
+ if (dev->phy.rev >= 7) {
+ target.ipa[i] = curr_gain[i] & 0x0007;
+ target.pad[i] = (curr_gain[i] & 0x00F8) >> 3;
+ target.pga[i] = (curr_gain[i] & 0x0F00) >> 8;
+ target.txgm[i] = (curr_gain[i] & 0x7000) >> 12;
+ target.tx_lpf[i] = (curr_gain[i] & 0x8000) >> 15;
+ } else if (dev->phy.rev >= 3) {
target.ipa[i] = curr_gain[i] & 0x000F;
target.pad[i] = (curr_gain[i] & 0x00F0) >> 4;
target.pga[i] = (curr_gain[i] & 0x0F00) >> 8;
@@ -4498,7 +5053,13 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev)
if (!table)
break;
- if (dev->phy.rev >= 3) {
+ if (dev->phy.rev >= 7) {
+ target.ipa[i] = (table[index[i]] >> 16) & 0x7;
+ target.pad[i] = (table[index[i]] >> 19) & 0x1F;
+ target.pga[i] = (table[index[i]] >> 24) & 0xF;
+ target.txgm[i] = (table[index[i]] >> 28) & 0x7;
+ target.tx_lpf[i] = (table[index[i]] >> 31) & 0x1;
+ } else if (dev->phy.rev >= 3) {
target.ipa[i] = (table[index[i]] >> 16) & 0xF;
target.pad[i] = (table[index[i]] >> 20) & 0xF;
target.pga[i] = (table[index[i]] >> 24) & 0xF;
@@ -4547,6 +5108,8 @@ static void b43_nphy_tx_cal_phy_cleanup(struct b43_wldev *dev)
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhySetup */
static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev)
{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_phy_n *nphy = dev->phy.n;
u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs;
u16 tmp;
@@ -4578,7 +5141,12 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev)
regs[7] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
- b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_PA, 1, 3);
+ if (!nphy->use_int_tx_iq_lo_cal)
+ b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_PA,
+ 1, 3);
+ else
+ b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_PA,
+ 0, 3);
b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_TRSW, 2, 1);
b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_TRSW, 8, 2);
@@ -4586,6 +5154,33 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev)
regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1);
b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001);
b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001);
+
+ tmp = b43_nphy_read_lpf_ctl(dev, 0);
+ if (phy->rev >= 19)
+ b43_nphy_rf_ctl_override_rev19(dev, 0x80, tmp, 0, false,
+ 1);
+ else if (phy->rev >= 7)
+ b43_nphy_rf_ctl_override_rev7(dev, 0x80, tmp, 0, false,
+ 1);
+
+ if (nphy->use_int_tx_iq_lo_cal && true /* FIXME */) {
+ if (phy->rev >= 19) {
+ b43_nphy_rf_ctl_override_rev19(dev, 0x8, 0, 0x3,
+ false, 0);
+ } else if (phy->rev >= 8) {
+ b43_nphy_rf_ctl_override_rev7(dev, 0x8, 0, 0x3,
+ false, 0);
+ } else if (phy->rev == 7) {
+ b43_radio_maskset(dev, R2057_OVR_REG0, 1 << 4, 1 << 4);
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ b43_radio_maskset(dev, R2057_PAD2G_TUNE_PUS_CORE0, ~1, 0);
+ b43_radio_maskset(dev, R2057_PAD2G_TUNE_PUS_CORE1, ~1, 0);
+ } else {
+ b43_radio_maskset(dev, R2057_IPA5G_CASCOFFV_PU_CORE0, ~1, 0);
+ b43_radio_maskset(dev, R2057_IPA5G_CASCOFFV_PU_CORE1, ~1, 0);
+ }
+ }
+ }
} else {
b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, 0xA000);
b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, 0xA000);
@@ -4614,6 +5209,7 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev)
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SaveCal */
static void b43_nphy_save_cal(struct b43_wldev *dev)
{
+ struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = dev->phy.n;
struct b43_phy_n_iq_comp *rxcal_coeffs = NULL;
@@ -4638,7 +5234,26 @@ static void b43_nphy_save_cal(struct b43_wldev *dev)
b43_nphy_rx_iq_coeffs(dev, false, rxcal_coeffs);
/* TODO use some definitions */
- if (dev->phy.rev >= 3) {
+ if (phy->rev >= 19) {
+ /* TODO */
+ } else if (phy->rev >= 7) {
+ txcal_radio_regs[0] = b43_radio_read(dev,
+ R2057_TX0_LOFT_FINE_I);
+ txcal_radio_regs[1] = b43_radio_read(dev,
+ R2057_TX0_LOFT_FINE_Q);
+ txcal_radio_regs[4] = b43_radio_read(dev,
+ R2057_TX0_LOFT_COARSE_I);
+ txcal_radio_regs[5] = b43_radio_read(dev,
+ R2057_TX0_LOFT_COARSE_Q);
+ txcal_radio_regs[2] = b43_radio_read(dev,
+ R2057_TX1_LOFT_FINE_I);
+ txcal_radio_regs[3] = b43_radio_read(dev,
+ R2057_TX1_LOFT_FINE_Q);
+ txcal_radio_regs[6] = b43_radio_read(dev,
+ R2057_TX1_LOFT_COARSE_I);
+ txcal_radio_regs[7] = b43_radio_read(dev,
+ R2057_TX1_LOFT_COARSE_Q);
+ } else if (phy->rev >= 3) {
txcal_radio_regs[0] = b43_radio_read(dev, 0x2021);
txcal_radio_regs[1] = b43_radio_read(dev, 0x2022);
txcal_radio_regs[2] = b43_radio_read(dev, 0x3021);
@@ -4665,6 +5280,7 @@ static void b43_nphy_save_cal(struct b43_wldev *dev)
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */
static void b43_nphy_restore_cal(struct b43_wldev *dev)
{
+ struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = dev->phy.n;
u16 coef[4];
@@ -4712,7 +5328,26 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev)
}
/* TODO use some definitions */
- if (dev->phy.rev >= 3) {
+ if (phy->rev >= 19) {
+ /* TODO */
+ } else if (phy->rev >= 7) {
+ b43_radio_write(dev, R2057_TX0_LOFT_FINE_I,
+ txcal_radio_regs[0]);
+ b43_radio_write(dev, R2057_TX0_LOFT_FINE_Q,
+ txcal_radio_regs[1]);
+ b43_radio_write(dev, R2057_TX0_LOFT_COARSE_I,
+ txcal_radio_regs[4]);
+ b43_radio_write(dev, R2057_TX0_LOFT_COARSE_Q,
+ txcal_radio_regs[5]);
+ b43_radio_write(dev, R2057_TX1_LOFT_FINE_I,
+ txcal_radio_regs[2]);
+ b43_radio_write(dev, R2057_TX1_LOFT_FINE_Q,
+ txcal_radio_regs[3]);
+ b43_radio_write(dev, R2057_TX1_LOFT_COARSE_I,
+ txcal_radio_regs[6]);
+ b43_radio_write(dev, R2057_TX1_LOFT_COARSE_Q,
+ txcal_radio_regs[7]);
+ } else if (phy->rev >= 3) {
b43_radio_write(dev, 0x2021, txcal_radio_regs[0]);
b43_radio_write(dev, 0x2022, txcal_radio_regs[1]);
b43_radio_write(dev, 0x3021, txcal_radio_regs[2]);
@@ -4789,7 +5424,13 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
}
}
- b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9);
+ if (phy->rev >= 19) {
+ /* TODO */
+ } else if (phy->rev >= 7) {
+ b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AD9);
+ } else {
+ b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9);
+ }
if (!b43_is_40mhz(dev))
freq = 2500;
@@ -5183,6 +5824,9 @@ static int b43_nphy_rev3_cal_rx_iq(struct b43_wldev *dev,
static int b43_nphy_cal_rx_iq(struct b43_wldev *dev,
struct nphy_txgains target, u8 type, bool debug)
{
+ if (dev->phy.rev >= 7)
+ type = 0;
+
if (dev->phy.rev >= 3)
return b43_nphy_rev3_cal_rx_iq(dev, target, type, debug);
else
@@ -5269,6 +5913,9 @@ static void b43_nphy_bphy_init(struct b43_wldev *dev)
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SuperSwitchInit */
static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init)
{
+ if (dev->phy.rev >= 7)
+ return;
+
if (dev->phy.rev >= 3) {
if (!init)
return;
@@ -5344,6 +5991,10 @@ static int b43_phy_initn(struct b43_wldev *dev)
#endif
}
}
+ nphy->use_int_tx_iq_lo_cal = b43_nphy_ipa(dev) ||
+ phy->rev >= 7 ||
+ (phy->rev >= 5 &&
+ sprom->boardflags2_hi & B43_BFH2_INTERNDET_TXIQCAL);
nphy->deaf_count = 0;
b43_nphy_tables_init(dev);
nphy->crsminpwr_adjusted = false;
@@ -5353,6 +6004,16 @@ static int b43_phy_initn(struct b43_wldev *dev)
if (dev->phy.rev >= 3) {
b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, 0);
b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
+ if (phy->rev >= 7) {
+ b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER3, 0);
+ b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER4, 0);
+ b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER5, 0);
+ b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER6, 0);
+ }
+ if (phy->rev >= 19) {
+ /* TODO */
+ }
+
b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, 0);
b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, 0);
} else {
@@ -5390,7 +6051,9 @@ static int b43_phy_initn(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x50);
b43_phy_write(dev, B43_NPHY_TXRIFS_FRDEL, 0x30);
- b43_nphy_update_mimo_config(dev, nphy->preamble_override);
+ if (phy->rev < 8)
+ b43_nphy_update_mimo_config(dev, nphy->preamble_override);
+
b43_nphy_update_txrx_chain(dev);
if (phy->rev < 2) {
@@ -5422,10 +6085,12 @@ static int b43_phy_initn(struct b43_wldev *dev)
b43_mac_phy_clock_set(dev, true);
- b43_nphy_pa_override(dev, false);
- b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
- b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
- b43_nphy_pa_override(dev, true);
+ if (phy->rev < 7) {
+ b43_nphy_pa_override(dev, false);
+ b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
+ b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+ b43_nphy_pa_override(dev, true);
+ }
b43_nphy_classifier(dev, 0, 0);
b43_nphy_read_clip_detection(dev, clip);
@@ -5548,23 +6213,23 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev,
struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = dev->phy.n;
int ch = new_channel->hw_value;
-
- u16 old_band_5ghz;
u16 tmp16;
- old_band_5ghz =
- b43_phy_read(dev, B43_NPHY_BANDCTL) & B43_NPHY_BANDCTL_5GHZ;
- if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) {
+ if (new_channel->band == IEEE80211_BAND_5GHZ) {
tmp16 = b43_read16(dev, B43_MMIO_PSM_PHY_HDR);
b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16 | 4);
- b43_phy_set(dev, B43_PHY_B_BBCFG, 0xC000);
+ /* Put BPHY in the reset */
+ b43_phy_set(dev, B43_PHY_B_BBCFG,
+ B43_PHY_B_BBCFG_RSTCCA | B43_PHY_B_BBCFG_RSTRX);
b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16);
b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ);
- } else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) {
+ } else if (new_channel->band == IEEE80211_BAND_2GHZ) {
b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
tmp16 = b43_read16(dev, B43_MMIO_PSM_PHY_HDR);
b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16 | 4);
- b43_phy_mask(dev, B43_PHY_B_BBCFG, 0x3FFF);
+ /* Take BPHY out of the reset */
+ b43_phy_mask(dev, B43_PHY_B_BBCFG,
+ (u16)~(B43_PHY_B_BBCFG_RSTCCA | B43_PHY_B_BBCFG_RSTRX));
b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16);
}
@@ -5589,31 +6254,45 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev,
if (dev->phy.rev >= 3 &&
dev->phy.n->spur_avoid != B43_SPUR_AVOID_DISABLE) {
- bool avoid = false;
+ u8 spuravoid = 0;
+
if (dev->phy.n->spur_avoid == B43_SPUR_AVOID_FORCE) {
- avoid = true;
- } else if (!b43_is_40mhz(dev)) {
- if ((ch >= 5 && ch <= 8) || ch == 13 || ch == 14)
- avoid = true;
- } else { /* 40MHz */
- if (nphy->aband_spurwar_en &&
- (ch == 38 || ch == 102 || ch == 118))
- avoid = dev->dev->chip_id == 0x4716;
+ spuravoid = 1;
+ } else if (phy->rev >= 19) {
+ /* TODO */
+ } else if (phy->rev >= 18) {
+ /* TODO */
+ } else if (phy->rev >= 17) {
+ /* TODO: Off for channels 1-11, but check 12-14! */
+ } else if (phy->rev >= 16) {
+ /* TODO: Off for 2 GHz, but check 5 GHz! */
+ } else if (phy->rev >= 7) {
+ if (!b43_is_40mhz(dev)) { /* 20MHz */
+ if (ch == 13 || ch == 14 || ch == 153)
+ spuravoid = 1;
+ } else { /* 40 MHz */
+ if (ch == 54)
+ spuravoid = 1;
+ }
+ } else {
+ if (!b43_is_40mhz(dev)) { /* 20MHz */
+ if ((ch >= 5 && ch <= 8) || ch == 13 || ch == 14)
+ spuravoid = 1;
+ } else { /* 40MHz */
+ if (nphy->aband_spurwar_en &&
+ (ch == 38 || ch == 102 || ch == 118))
+ spuravoid = dev->dev->chip_id == 0x4716;
+ }
}
- b43_nphy_pmu_spur_avoid(dev, avoid);
+ b43_nphy_pmu_spur_avoid(dev, spuravoid);
- if (dev->dev->chip_id == 43222 || dev->dev->chip_id == 43224 ||
- dev->dev->chip_id == 43225) {
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW,
- avoid ? 0x5341 : 0x8889);
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
- }
+ b43_mac_switch_freq(dev, spuravoid);
if (dev->phy.rev == 3 || dev->phy.rev == 4)
; /* TODO: reset PLL */
- if (avoid)
+ if (spuravoid)
b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTRX);
else
b43_phy_mask(dev, B43_NPHY_BBCFG,
@@ -5644,7 +6323,10 @@ static int b43_nphy_set_channel(struct b43_wldev *dev,
u8 tmp;
- if (phy->rev >= 7) {
+ if (phy->rev >= 19) {
+ return -ESRCH;
+ /* TODO */
+ } else if (phy->rev >= 7) {
r2057_get_chantabent_rev7(dev, channel->center_freq,
&tabent_r7, &tabent_r7_2g);
if (!tabent_r7 && !tabent_r7_2g)
@@ -5681,7 +6363,9 @@ static int b43_nphy_set_channel(struct b43_wldev *dev,
b43_phy_mask(dev, 0x310, (u16)~0x8000);
}
- if (phy->rev >= 7) {
+ if (phy->rev >= 19) {
+ /* TODO */
+ } else if (phy->rev >= 7) {
const struct b43_phy_n_sfo_cfg *phy_regs = tabent_r7 ?
&(tabent_r7->phy_regs) : &(tabent_r7_2g->phy_regs);
@@ -5834,7 +6518,7 @@ static void b43_nphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
{
/* Register 1 is a 32-bit register. */
- B43_WARN_ON(reg == 1);
+ B43_WARN_ON(dev->phy.rev < 7 && reg == 1);
if (dev->phy.rev >= 7)
reg |= 0x200; /* Radio 0x2057 */
@@ -5848,7 +6532,7 @@ static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
{
/* Register 1 is a 32-bit register. */
- B43_WARN_ON(reg == 1);
+ B43_WARN_ON(dev->phy.rev < 7 && reg == 1);
b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
@@ -5858,15 +6542,23 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
bool blocked)
{
+ struct b43_phy *phy = &dev->phy;
+
if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
b43err(dev->wl, "MAC not suspended\n");
if (blocked) {
- b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
- ~B43_NPHY_RFCTL_CMD_CHIP0PU);
- if (dev->phy.rev >= 7) {
+ if (phy->rev >= 19) {
/* TODO */
- } else if (dev->phy.rev >= 3) {
+ } else if (phy->rev >= 8) {
+ b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+ ~B43_NPHY_RFCTL_CMD_CHIP0PU);
+ } else if (phy->rev >= 7) {
+ /* Nothing needed */
+ } else if (phy->rev >= 3) {
+ b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+ ~B43_NPHY_RFCTL_CMD_CHIP0PU);
+
b43_radio_mask(dev, 0x09, ~0x2);
b43_radio_write(dev, 0x204D, 0);
@@ -5884,11 +6576,13 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
b43_radio_write(dev, 0x3064, 0);
}
} else {
- if (dev->phy.rev >= 7) {
+ if (phy->rev >= 19) {
+ /* TODO */
+ } else if (phy->rev >= 7) {
if (!dev->phy.radio_on)
b43_radio_2057_init(dev);
b43_switch_channel(dev, dev->phy.channel);
- } else if (dev->phy.rev >= 3) {
+ } else if (phy->rev >= 3) {
if (!dev->phy.radio_on)
b43_radio_init2056(dev);
b43_switch_channel(dev, dev->phy.channel);
@@ -5901,10 +6595,13 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
/* http://bcm-v4.sipsolutions.net/802.11/PHY/Anacore */
static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on)
{
+ struct b43_phy *phy = &dev->phy;
u16 override = on ? 0x0 : 0x7FFF;
u16 core = on ? 0xD : 0x00FD;
- if (dev->phy.rev >= 3) {
+ if (phy->rev >= 19) {
+ /* TODO */
+ } else if (phy->rev >= 3) {
if (on) {
b43_phy_write(dev, B43_NPHY_AFECTL_C1, core);
b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, override);
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h
index ecfbf66dbc3b..30bec815b969 100644
--- a/drivers/net/wireless/b43/phy_n.h
+++ b/drivers/net/wireless/b43/phy_n.h
@@ -366,11 +366,13 @@
#define B43_NPHY_TXF_40CO_B1S0 B43_PHY_N(0x0E5) /* TX filter 40 coeff B1 stage 0 */
#define B43_NPHY_TXF_40CO_B32S1 B43_PHY_N(0x0E6) /* TX filter 40 coeff B32 stage 1 */
#define B43_NPHY_TXF_40CO_B1S1 B43_PHY_N(0x0E7) /* TX filter 40 coeff B1 stage 1 */
+#define B43_NPHY_REV3_RFCTL_OVER0 B43_PHY_N(0x0E7)
#define B43_NPHY_TXF_40CO_B32S2 B43_PHY_N(0x0E8) /* TX filter 40 coeff B32 stage 2 */
#define B43_NPHY_TXF_40CO_B1S2 B43_PHY_N(0x0E9) /* TX filter 40 coeff B1 stage 2 */
#define B43_NPHY_BIST_STAT2 B43_PHY_N(0x0EA) /* BIST status 2 */
#define B43_NPHY_BIST_STAT3 B43_PHY_N(0x0EB) /* BIST status 3 */
#define B43_NPHY_RFCTL_OVER B43_PHY_N(0x0EC) /* RF control override */
+#define B43_NPHY_REV3_RFCTL_OVER1 B43_PHY_N(0x0EC)
#define B43_NPHY_MIMOCFG B43_PHY_N(0x0ED) /* MIMO config */
#define B43_NPHY_MIMOCFG_GFMIX 0x0004 /* Greenfield or mixed mode */
#define B43_NPHY_MIMOCFG_AUTO 0x0100 /* Greenfield/mixed mode auto */
@@ -857,7 +859,18 @@
#define B43_NPHY_REV3_C2_CLIP2_GAIN_A B43_PHY_N(0x2AF)
#define B43_NPHY_REV3_C2_CLIP2_GAIN_B B43_PHY_N(0x2B0)
+#define B43_NPHY_REV7_RF_CTL_MISC_REG3 B43_PHY_N(0x340)
+#define B43_NPHY_REV7_RF_CTL_MISC_REG4 B43_PHY_N(0x341)
+#define B43_NPHY_REV7_RF_CTL_OVER3 B43_PHY_N(0x342)
+#define B43_NPHY_REV7_RF_CTL_OVER4 B43_PHY_N(0x343)
+#define B43_NPHY_REV7_RF_CTL_MISC_REG5 B43_PHY_N(0x344)
+#define B43_NPHY_REV7_RF_CTL_MISC_REG6 B43_PHY_N(0x345)
+#define B43_NPHY_REV7_RF_CTL_OVER5 B43_PHY_N(0x346)
+#define B43_NPHY_REV7_RF_CTL_OVER6 B43_PHY_N(0x347)
+
#define B43_PHY_B_BBCFG B43_PHY_N_BMODE(0x001) /* BB config */
+#define B43_PHY_B_BBCFG_RSTCCA 0x4000 /* Reset CCA */
+#define B43_PHY_B_BBCFG_RSTRX 0x8000 /* Reset RX */
#define B43_PHY_B_TEST B43_PHY_N_BMODE(0x00A)
struct b43_wldev;
@@ -935,6 +948,8 @@ struct b43_phy_n {
bool gain_boost;
bool elna_gain_config;
bool band5g_pwrgain;
+ bool use_int_tx_iq_lo_cal;
+ bool lpf_bw_overrode_for_sample_play;
u8 mphase_cal_phase_id;
u16 mphase_txcal_cmdidx;
diff --git a/drivers/net/wireless/b43/radio_2057.c b/drivers/net/wireless/b43/radio_2057.c
index df3574545819..ff1e026a61a1 100644
--- a/drivers/net/wireless/b43/radio_2057.c
+++ b/drivers/net/wireless/b43/radio_2057.c
@@ -105,6 +105,27 @@ static u16 r2057_rev8_init[][2] = {
};
*/
+/* Extracted from MMIO dump of 6.30.223.141 */
+static u16 r2057_rev9_init[][2] = {
+ { 0x27, 0x1f }, { 0x28, 0x0a }, { 0x29, 0x2f }, { 0x42, 0x1f },
+ { 0x48, 0x3f }, { 0x5c, 0x41 }, { 0x63, 0x14 }, { 0x64, 0x12 },
+ { 0x66, 0xff }, { 0x74, 0xa3 }, { 0x7b, 0x14 }, { 0x7c, 0x14 },
+ { 0x7d, 0xee }, { 0x86, 0xc0 }, { 0xc4, 0x10 }, { 0xc9, 0x01 },
+ { 0xe1, 0x41 }, { 0xe8, 0x14 }, { 0xe9, 0x12 }, { 0xeb, 0xff },
+ { 0xf5, 0x0a }, { 0xf8, 0x09 }, { 0xf9, 0xa3 }, { 0x100, 0x14 },
+ { 0x101, 0x10 }, { 0x102, 0xee }, { 0x10b, 0xc0 }, { 0x149, 0x10 },
+ { 0x14e, 0x01 }, { 0x1b7, 0x05 }, { 0x1c2, 0xa0 },
+};
+
+/* Extracted from MMIO dump of 6.30.223.248 */
+static u16 r2057_rev14_init[][2] = {
+ { 0x011, 0xfc }, { 0x030, 0x24 }, { 0x040, 0x1c }, { 0x082, 0x08 },
+ { 0x0b4, 0x44 }, { 0x0c8, 0x01 }, { 0x0c9, 0x01 }, { 0x107, 0x08 },
+ { 0x14d, 0x01 }, { 0x14e, 0x01 }, { 0x1af, 0x40 }, { 0x1b0, 0x40 },
+ { 0x1cc, 0x01 }, { 0x1cf, 0x10 }, { 0x1d0, 0x0f }, { 0x1d3, 0x10 },
+ { 0x1d4, 0x0f },
+};
+
#define RADIOREGS7(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \
r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \
r20, r21, r22, r23, r24, r25, r26, r27) \
@@ -137,6 +158,27 @@ static u16 r2057_rev8_init[][2] = {
.radio_lna2g_tune_core1 = r26, \
.radio_lna5g_tune_core1 = r27
+#define RADIOREGS7_2G(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \
+ r10, r11, r12, r13, r14, r15, r16, r17) \
+ .radio_vcocal_countval0 = r00, \
+ .radio_vcocal_countval1 = r01, \
+ .radio_rfpll_refmaster_sparextalsize = r02, \
+ .radio_rfpll_loopfilter_r1 = r03, \
+ .radio_rfpll_loopfilter_c2 = r04, \
+ .radio_rfpll_loopfilter_c1 = r05, \
+ .radio_cp_kpd_idac = r06, \
+ .radio_rfpll_mmd0 = r07, \
+ .radio_rfpll_mmd1 = r08, \
+ .radio_vcobuf_tune = r09, \
+ .radio_logen_mx2g_tune = r10, \
+ .radio_logen_indbuf2g_tune = r11, \
+ .radio_txmix2g_tune_boost_pu_core0 = r12, \
+ .radio_pad2g_tune_pus_core0 = r13, \
+ .radio_lna2g_tune_core0 = r14, \
+ .radio_txmix2g_tune_boost_pu_core1 = r15, \
+ .radio_pad2g_tune_pus_core1 = r16, \
+ .radio_lna2g_tune_core1 = r17
+
#define PHYREGS(r0, r1, r2, r3, r4, r5) \
.phy_regs.phy_bw1a = r0, \
.phy_regs.phy_bw2 = r1, \
@@ -145,6 +187,353 @@ static u16 r2057_rev8_init[][2] = {
.phy_regs.phy_bw5 = r4, \
.phy_regs.phy_bw6 = r5
+/* Copied from brcmsmac (5.75.11): chan_info_nphyrev8_2057_rev5 */
+static const struct b43_nphy_chantabent_rev7_2g b43_nphy_chantab_phy_rev8_radio_rev5[] = {
+ {
+ .freq = 2412,
+ RADIOREGS7_2G(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c,
+ 0x09, 0x0d, 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61,
+ 0x03, 0xff),
+ PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
+ },
+ {
+ .freq = 2417,
+ RADIOREGS7_2G(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71,
+ 0x09, 0x0d, 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61,
+ 0x03, 0xff),
+ PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
+ },
+ {
+ .freq = 2422,
+ RADIOREGS7_2G(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76,
+ 0x09, 0x0d, 0x08, 0x0e, 0x61, 0x03, 0xef, 0x61,
+ 0x03, 0xef),
+ PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
+ },
+ {
+ .freq = 2427,
+ RADIOREGS7_2G(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b,
+ 0x09, 0x0c, 0x08, 0x0e, 0x61, 0x03, 0xdf, 0x61,
+ 0x03, 0xdf),
+ PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
+ },
+ {
+ .freq = 2432,
+ RADIOREGS7_2G(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80,
+ 0x09, 0x0c, 0x07, 0x0d, 0x61, 0x03, 0xcf, 0x61,
+ 0x03, 0xcf),
+ PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
+ },
+ {
+ .freq = 2437,
+ RADIOREGS7_2G(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85,
+ 0x09, 0x0c, 0x07, 0x0d, 0x61, 0x03, 0xbf, 0x61,
+ 0x03, 0xbf),
+ PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
+ },
+ {
+ .freq = 2442,
+ RADIOREGS7_2G(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a,
+ 0x09, 0x0b, 0x07, 0x0d, 0x61, 0x03, 0xaf, 0x61,
+ 0x03, 0xaf),
+ PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
+ },
+ {
+ .freq = 2447,
+ RADIOREGS7_2G(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f,
+ 0x09, 0x0b, 0x07, 0x0d, 0x61, 0x03, 0x9f, 0x61,
+ 0x03, 0x9f),
+ PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
+ },
+ {
+ .freq = 2452,
+ RADIOREGS7_2G(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94,
+ 0x09, 0x0b, 0x07, 0x0d, 0x61, 0x03, 0x8f, 0x61,
+ 0x03, 0x8f),
+ PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
+ },
+ {
+ .freq = 2457,
+ RADIOREGS7_2G(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99,
+ 0x09, 0x0b, 0x07, 0x0c, 0x61, 0x03, 0x7f, 0x61,
+ 0x03, 0x7f),
+ PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
+ },
+ {
+ .freq = 2462,
+ RADIOREGS7_2G(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e,
+ 0x09, 0x0b, 0x07, 0x0c, 0x61, 0x03, 0x6f, 0x61,
+ 0x03, 0x6f),
+ PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
+ },
+ {
+ .freq = 2467,
+ RADIOREGS7_2G(0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3,
+ 0x09, 0x0b, 0x06, 0x0c, 0x61, 0x03, 0x5f, 0x61,
+ 0x03, 0x5f),
+ PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b),
+ },
+ {
+ .freq = 2472,
+ RADIOREGS7_2G(0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8,
+ 0x09, 0x0a, 0x06, 0x0b, 0x61, 0x03, 0x4f, 0x61,
+ 0x03, 0x4f),
+ PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429),
+ },
+ {
+ .freq = 2484,
+ RADIOREGS7_2G(0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4,
+ 0x09, 0x0a, 0x06, 0x0b, 0x61, 0x03, 0x3f, 0x61,
+ 0x03, 0x3f),
+ PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424),
+ }
+};
+
+/* Extracted from MMIO dump of 6.30.223.248 */
+static const struct b43_nphy_chantabent_rev7_2g b43_nphy_chantab_phy_rev17_radio_rev14[] = {
+ {
+ .freq = 2412,
+ RADIOREGS7_2G(0x48, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x6c,
+ 0x09, 0x0d, 0x09, 0x03, 0x21, 0x53, 0xff, 0x21,
+ 0x53, 0xff),
+ PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
+ },
+ {
+ .freq = 2417,
+ RADIOREGS7_2G(0x4b, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x71,
+ 0x09, 0x0d, 0x08, 0x03, 0x21, 0x53, 0xff, 0x21,
+ 0x53, 0xff),
+ PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
+ },
+ {
+ .freq = 2422,
+ RADIOREGS7_2G(0x4e, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x76,
+ 0x09, 0x0d, 0x08, 0x03, 0x21, 0x53, 0xff, 0x21,
+ 0x53, 0xff),
+ PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
+ },
+ {
+ .freq = 2427,
+ RADIOREGS7_2G(0x52, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x7b,
+ 0x09, 0x0c, 0x08, 0x03, 0x21, 0x53, 0xff, 0x21,
+ 0x53, 0xff),
+ PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
+ },
+ {
+ .freq = 2432,
+ RADIOREGS7_2G(0x55, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x80,
+ 0x09, 0x0c, 0x08, 0x03, 0x21, 0x53, 0xff, 0x21,
+ 0x53, 0xff),
+ PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
+ },
+ {
+ .freq = 2437,
+ RADIOREGS7_2G(0x58, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x85,
+ 0x09, 0x0c, 0x08, 0x03, 0x21, 0x53, 0xff, 0x21,
+ 0x53, 0xff),
+ PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
+ },
+ {
+ .freq = 2442,
+ RADIOREGS7_2G(0x5c, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x8a,
+ 0x09, 0x0c, 0x08, 0x03, 0x21, 0x43, 0xff, 0x21,
+ 0x43, 0xff),
+ PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
+ },
+ {
+ .freq = 2447,
+ RADIOREGS7_2G(0x5f, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x8f,
+ 0x09, 0x0c, 0x08, 0x03, 0x21, 0x43, 0xff, 0x21,
+ 0x43, 0xff),
+ PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
+ },
+ {
+ .freq = 2452,
+ RADIOREGS7_2G(0x62, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x94,
+ 0x09, 0x0c, 0x08, 0x03, 0x21, 0x43, 0xff, 0x21,
+ 0x43, 0xff),
+ PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
+ },
+ {
+ .freq = 2457,
+ RADIOREGS7_2G(0x66, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x99,
+ 0x09, 0x0b, 0x07, 0x03, 0x21, 0x43, 0xff, 0x21,
+ 0x43, 0xff),
+ PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
+ },
+ {
+ .freq = 2462,
+ RADIOREGS7_2G(0x69, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x9e,
+ 0x09, 0x0b, 0x07, 0x03, 0x01, 0x43, 0xff, 0x01,
+ 0x43, 0xff),
+ PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
+ },
+};
+
+/* Extracted from MMIO dump of 6.30.223.141 */
+static const struct b43_nphy_chantabent_rev7 b43_nphy_chantab_phy_rev16_radio_rev9[] = {
+ {
+ .freq = 2412,
+ RADIOREGS7(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c,
+ 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x41, 0x63,
+ 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00,
+ 0x00, 0x00, 0xf0, 0x00),
+ PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
+ },
+ {
+ .freq = 2417,
+ RADIOREGS7(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71,
+ 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x41, 0x63,
+ 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00,
+ 0x00, 0x00, 0xf0, 0x00),
+ PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
+ },
+ {
+ .freq = 2422,
+ RADIOREGS7(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76,
+ 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x41, 0x63,
+ 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00,
+ 0x00, 0x00, 0xf0, 0x00),
+ PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
+ },
+ {
+ .freq = 2427,
+ RADIOREGS7(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b,
+ 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x41, 0x63,
+ 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00,
+ 0x00, 0x00, 0xf0, 0x00),
+ PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
+ },
+ {
+ .freq = 2432,
+ RADIOREGS7(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80,
+ 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x41, 0x63,
+ 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00,
+ 0x00, 0x00, 0xf0, 0x00),
+ PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
+ },
+ {
+ .freq = 2437,
+ RADIOREGS7(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85,
+ 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x41, 0x63,
+ 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00,
+ 0x00, 0x00, 0xf0, 0x00),
+ PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
+ },
+ {
+ .freq = 2442,
+ RADIOREGS7(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a,
+ 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x41, 0x63,
+ 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00,
+ 0x00, 0x00, 0xf0, 0x00),
+ PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
+ },
+ {
+ .freq = 2447,
+ RADIOREGS7(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f,
+ 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x41, 0x63,
+ 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00,
+ 0x00, 0x00, 0xf0, 0x00),
+ PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
+ },
+ {
+ .freq = 2452,
+ RADIOREGS7(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94,
+ 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x41, 0x63,
+ 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00,
+ 0x00, 0x00, 0xf0, 0x00),
+ PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
+ },
+ {
+ .freq = 2457,
+ RADIOREGS7(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99,
+ 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x41, 0x63,
+ 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00,
+ 0x00, 0x00, 0xf0, 0x00),
+ PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
+ },
+ {
+ .freq = 2462,
+ RADIOREGS7(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e,
+ 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x41, 0x63,
+ 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00,
+ 0x00, 0x00, 0xf0, 0x00),
+ PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
+ },
+ {
+ .freq = 5180,
+ RADIOREGS7(0xbe, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x06,
+ 0x02, 0x0e, 0x00, 0x0e, 0x00, 0x9e, 0x00, 0x00,
+ 0x9f, 0x2f, 0xa3, 0x00, 0xfc, 0x00, 0x00, 0x4f,
+ 0x3a, 0x83, 0x00, 0xfc),
+ PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb),
+ },
+ {
+ .freq = 5200,
+ RADIOREGS7(0xc5, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x08,
+ 0x02, 0x0e, 0x00, 0x0e, 0x00, 0x9e, 0x00, 0x00,
+ 0x7f, 0x2f, 0x83, 0x00, 0xf8, 0x00, 0x00, 0x4c,
+ 0x4a, 0x83, 0x00, 0xf8),
+ PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9),
+ },
+ {
+ .freq = 5220,
+ RADIOREGS7(0xcc, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0a,
+ 0x02, 0x0e, 0x00, 0x0e, 0x00, 0x9e, 0x00, 0x00,
+ 0x6d, 0x3d, 0x83, 0x00, 0xf8, 0x00, 0x00, 0x2d,
+ 0x2a, 0x73, 0x00, 0xf8),
+ PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7),
+ },
+ {
+ .freq = 5240,
+ RADIOREGS7(0xd2, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0c,
+ 0x02, 0x0d, 0x00, 0x0d, 0x00, 0x8d, 0x00, 0x00,
+ 0x4d, 0x1c, 0x73, 0x00, 0xf8, 0x00, 0x00, 0x4d,
+ 0x2b, 0x73, 0x00, 0xf8),
+ PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5),
+ },
+ {
+ .freq = 5745,
+ RADIOREGS7(0x7b, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x7d,
+ 0x04, 0x08, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00,
+ 0x08, 0x03, 0x03, 0x00, 0x30, 0x00, 0x00, 0x06,
+ 0x02, 0x03, 0x00, 0x30),
+ PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9),
+ },
+ {
+ .freq = 5765,
+ RADIOREGS7(0x81, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x81,
+ 0x04, 0x08, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00,
+ 0x06, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x02, 0x03, 0x00, 0x00),
+ PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8),
+ },
+ {
+ .freq = 5785,
+ RADIOREGS7(0x88, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x85,
+ 0x04, 0x08, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00,
+ 0x08, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x21, 0x03, 0x00, 0x00),
+ PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6),
+ },
+ {
+ .freq = 5805,
+ RADIOREGS7(0x8f, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x89,
+ 0x04, 0x07, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00,
+ 0x06, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x03, 0x00, 0x00),
+ PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4),
+ },
+ {
+ .freq = 5825,
+ RADIOREGS7(0x95, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x8d,
+ 0x04, 0x07, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00,
+ 0x05, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x03, 0x00, 0x00),
+ PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3),
+ },
+};
+
void r2057_upload_inittabs(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
@@ -171,6 +560,18 @@ void r2057_upload_inittabs(struct b43_wldev *dev)
size = ARRAY_SIZE(r2057_rev5a_init);
}
break;
+ case 16:
+ if (phy->radio_rev == 9) {
+ table = r2057_rev9_init[0];
+ size = ARRAY_SIZE(r2057_rev9_init);
+ }
+ break;
+ case 17:
+ if (phy->radio_rev == 14) {
+ table = r2057_rev14_init[0];
+ size = ARRAY_SIZE(r2057_rev14_init);
+ }
+ break;
}
B43_WARN_ON(!table);
@@ -193,8 +594,25 @@ void r2057_get_chantabent_rev7(struct b43_wldev *dev, u16 freq,
*tabent_r7 = NULL;
*tabent_r7_2g = NULL;
- /* TODO */
switch (phy->rev) {
+ case 8:
+ if (phy->radio_rev == 5) {
+ e_r7_2g = b43_nphy_chantab_phy_rev8_radio_rev5;
+ len = ARRAY_SIZE(b43_nphy_chantab_phy_rev8_radio_rev5);
+ }
+ break;
+ case 16:
+ if (phy->radio_rev == 9) {
+ e_r7 = b43_nphy_chantab_phy_rev16_radio_rev9;
+ len = ARRAY_SIZE(b43_nphy_chantab_phy_rev16_radio_rev9);
+ }
+ break;
+ case 17:
+ if (phy->radio_rev == 14) {
+ e_r7_2g = b43_nphy_chantab_phy_rev17_radio_rev14;
+ len = ARRAY_SIZE(b43_nphy_chantab_phy_rev17_radio_rev14);
+ }
+ break;
default:
break;
}
diff --git a/drivers/net/wireless/b43/radio_2057.h b/drivers/net/wireless/b43/radio_2057.h
index 675d1bb64429..220d080238ff 100644
--- a/drivers/net/wireless/b43/radio_2057.h
+++ b/drivers/net/wireless/b43/radio_2057.h
@@ -84,6 +84,8 @@
#define R2057_CMOSBUF_RX_RCCR 0x04c
#define R2057_LOGEN_SEL_PKDET 0x04d
#define R2057_CMOSBUF_SHAREIQ_PTAT 0x04e
+
+/* MISC core 0 */
#define R2057_RXTXBIAS_CONFIG_CORE0 0x04f
#define R2057_TXGM_TXRF_PUS_CORE0 0x050
#define R2057_TXGM_IDAC_BLEED_CORE0 0x051
@@ -204,6 +206,8 @@
#define R2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE0 0x0d1
#define R2057_LPF_GAIN_CORE0 0x0d2
#define R2057_DACBUF_IDACS_BW_CORE0 0x0d3
+
+/* MISC core 1 */
#define R2057_RXTXBIAS_CONFIG_CORE1 0x0d4
#define R2057_TXGM_TXRF_PUS_CORE1 0x0d5
#define R2057_TXGM_IDAC_BLEED_CORE1 0x0d6
@@ -324,6 +328,7 @@
#define R2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE1 0x156
#define R2057_LPF_GAIN_CORE1 0x157
#define R2057_DACBUF_IDACS_BW_CORE1 0x158
+
#define R2057_DACBUF_VINCM_CORE1 0x159
#define R2057_RCCAL_START_R1_Q1_P1 0x15a
#define R2057_RCCAL_X1 0x15b
@@ -345,6 +350,8 @@
#define R2057_RCCAL_BCAP_VAL 0x16b
#define R2057_RCCAL_HPC_VAL 0x16c
#define R2057_RCCAL_OVERRIDES 0x16d
+
+/* TX core 0 */
#define R2057_TX0_IQCAL_GAIN_BW 0x170
#define R2057_TX0_LOFT_FINE_I 0x171
#define R2057_TX0_LOFT_FINE_Q 0x172
@@ -362,6 +369,8 @@
#define R2057_TX0_TXRXCOUPLE_2G_PWRUP 0x17e
#define R2057_TX0_TXRXCOUPLE_5G_ATTEN 0x17f
#define R2057_TX0_TXRXCOUPLE_5G_PWRUP 0x180
+
+/* TX core 1 */
#define R2057_TX1_IQCAL_GAIN_BW 0x190
#define R2057_TX1_LOFT_FINE_I 0x191
#define R2057_TX1_LOFT_FINE_Q 0x192
@@ -379,6 +388,7 @@
#define R2057_TX1_TXRXCOUPLE_2G_PWRUP 0x19e
#define R2057_TX1_TXRXCOUPLE_5G_ATTEN 0x19f
#define R2057_TX1_TXRXCOUPLE_5G_PWRUP 0x1a0
+
#define R2057_AFE_VCM_CAL_MASTER_CORE0 0x1a1
#define R2057_AFE_SET_VCM_I_CORE0 0x1a2
#define R2057_AFE_SET_VCM_Q_CORE0 0x1a3
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index b28dce950e1f..4b5885077b01 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -2408,6 +2408,41 @@ static const u32 b43_ntab_tx_gain_epa_rev3_2g[] = {
0x1041003c, 0x1041003b, 0x10410039, 0x10410037,
};
+static const u32 b43_ntab_tx_gain_epa_rev3_hi_pwr_2g[] = {
+ 0x0f410044, 0x0f410042, 0x0f410040, 0x0f41003e,
+ 0x0f41003c, 0x0f41003b, 0x0f410039, 0x0f410037,
+ 0x0e410044, 0x0e410042, 0x0e410040, 0x0e41003e,
+ 0x0e41003c, 0x0e41003b, 0x0e410039, 0x0e410037,
+ 0x0d410044, 0x0d410042, 0x0d410040, 0x0d41003e,
+ 0x0d41003c, 0x0d41003b, 0x0d410039, 0x0d410037,
+ 0x0c410044, 0x0c410042, 0x0c410040, 0x0c41003e,
+ 0x0c41003c, 0x0c41003b, 0x0c410039, 0x0c410037,
+ 0x0b410044, 0x0b410042, 0x0b410040, 0x0b41003e,
+ 0x0b41003c, 0x0b41003b, 0x0b410039, 0x0b410037,
+ 0x0a410044, 0x0a410042, 0x0a410040, 0x0a41003e,
+ 0x0a41003c, 0x0a41003b, 0x0a410039, 0x0a410037,
+ 0x09410044, 0x09410042, 0x09410040, 0x0941003e,
+ 0x0941003c, 0x0941003b, 0x09410039, 0x09410037,
+ 0x08410044, 0x08410042, 0x08410040, 0x0841003e,
+ 0x0841003c, 0x0841003b, 0x08410039, 0x08410037,
+ 0x07410044, 0x07410042, 0x07410040, 0x0741003e,
+ 0x0741003c, 0x0741003b, 0x07410039, 0x07410037,
+ 0x06410044, 0x06410042, 0x06410040, 0x0641003e,
+ 0x0641003c, 0x0641003b, 0x06410039, 0x06410037,
+ 0x05410044, 0x05410042, 0x05410040, 0x0541003e,
+ 0x0541003c, 0x0541003b, 0x05410039, 0x05410037,
+ 0x04410044, 0x04410042, 0x04410040, 0x0441003e,
+ 0x0441003c, 0x0441003b, 0x04410039, 0x04410037,
+ 0x03410044, 0x03410042, 0x03410040, 0x0341003e,
+ 0x0341003c, 0x0341003b, 0x03410039, 0x03410037,
+ 0x02410044, 0x02410042, 0x02410040, 0x0241003e,
+ 0x0241003c, 0x0241003b, 0x02410039, 0x02410037,
+ 0x01410044, 0x01410042, 0x01410040, 0x0141003e,
+ 0x0141003c, 0x0141003b, 0x01410039, 0x01410037,
+ 0x00410044, 0x00410042, 0x00410040, 0x0041003e,
+ 0x0041003c, 0x0041003b, 0x00410039, 0x00410037
+};
+
/* EPA 5 GHz */
static const u32 b43_ntab_tx_gain_epa_rev3_5g[] = {
@@ -2480,6 +2515,41 @@ static const u32 b43_ntab_tx_gain_epa_rev4_5g[] = {
0x20d2003a, 0x20d20038, 0x20d20036, 0x20d20034,
};
+static const u32 b43_ntab_tx_gain_epa_rev4_hi_pwr_5g[] = {
+ 0x2ff10044, 0x2ff10042, 0x2ff10040, 0x2ff1003e,
+ 0x2ff1003c, 0x2ff1003b, 0x2ff10039, 0x2ff10037,
+ 0x2ef10044, 0x2ef10042, 0x2ef10040, 0x2ef1003e,
+ 0x2ef1003c, 0x2ef1003b, 0x2ef10039, 0x2ef10037,
+ 0x2df10044, 0x2df10042, 0x2df10040, 0x2df1003e,
+ 0x2df1003c, 0x2df1003b, 0x2df10039, 0x2df10037,
+ 0x2cf10044, 0x2cf10042, 0x2cf10040, 0x2cf1003e,
+ 0x2cf1003c, 0x2cf1003b, 0x2cf10039, 0x2cf10037,
+ 0x2bf10044, 0x2bf10042, 0x2bf10040, 0x2bf1003e,
+ 0x2bf1003c, 0x2bf1003b, 0x2bf10039, 0x2bf10037,
+ 0x2af10044, 0x2af10042, 0x2af10040, 0x2af1003e,
+ 0x2af1003c, 0x2af1003b, 0x2af10039, 0x2af10037,
+ 0x29f10044, 0x29f10042, 0x29f10040, 0x29f1003e,
+ 0x29f1003c, 0x29f1003b, 0x29f10039, 0x29f10037,
+ 0x28f10044, 0x28f10042, 0x28f10040, 0x28f1003e,
+ 0x28f1003c, 0x28f1003b, 0x28f10039, 0x28f10037,
+ 0x27f10044, 0x27f10042, 0x27f10040, 0x27f1003e,
+ 0x27f1003c, 0x27f1003b, 0x27f10039, 0x27f10037,
+ 0x26f10044, 0x26f10042, 0x26f10040, 0x26f1003e,
+ 0x26f1003c, 0x26f1003b, 0x26f10039, 0x26f10037,
+ 0x25f10044, 0x25f10042, 0x25f10040, 0x25f1003e,
+ 0x25f1003c, 0x25f1003b, 0x25f10039, 0x25f10037,
+ 0x24f10044, 0x24f10042, 0x24f10040, 0x24f1003e,
+ 0x24f1003c, 0x24f1003b, 0x24f10039, 0x24f10038,
+ 0x23f10041, 0x23f10040, 0x23f1003f, 0x23f1003e,
+ 0x23f1003c, 0x23f1003b, 0x23f10039, 0x23f10037,
+ 0x22f10044, 0x22f10042, 0x22f10040, 0x22f1003e,
+ 0x22f1003c, 0x22f1003b, 0x22f10039, 0x22f10037,
+ 0x21f10044, 0x21f10042, 0x21f10040, 0x21f1003e,
+ 0x21f1003c, 0x21f1003b, 0x21f10039, 0x21f10037,
+ 0x20d10043, 0x20d10041, 0x20d1003e, 0x20d1003c,
+ 0x20d1003a, 0x20d10038, 0x20d10036, 0x20d10034
+};
+
static const u32 b43_ntab_tx_gain_epa_rev5_5g[] = {
0x0f62004a, 0x0f620048, 0x0f620046, 0x0f620044,
0x0f620042, 0x0f620040, 0x0f62003e, 0x0f62003c,
@@ -2622,6 +2692,42 @@ static const u32 b43_ntab_tx_gain_ipa_rev6_2g[] = {
0x00f70028, 0x00f70027, 0x00f70026, 0x00f70025,
};
+/* Copied from brcmsmac (5.75.11): nphy_tpc_txgain_ipa_2g_2057rev5 */
+static const u32 b43_ntab_tx_gain_ipa_2057_rev5_2g[] = {
+ 0x30ff0031, 0x30e70031, 0x30e7002e, 0x30cf002e,
+ 0x30bf002e, 0x30af002e, 0x309f002f, 0x307f0033,
+ 0x307f0031, 0x307f002e, 0x3077002e, 0x306f002e,
+ 0x3067002e, 0x305f002f, 0x30570030, 0x3057002d,
+ 0x304f002e, 0x30470031, 0x3047002e, 0x3047002c,
+ 0x30470029, 0x303f002c, 0x303f0029, 0x3037002d,
+ 0x3037002a, 0x30370028, 0x302f002c, 0x302f002a,
+ 0x302f0028, 0x302f0026, 0x3027002c, 0x30270029,
+ 0x30270027, 0x30270025, 0x30270023, 0x301f002c,
+ 0x301f002a, 0x301f0028, 0x301f0025, 0x301f0024,
+ 0x301f0022, 0x301f001f, 0x3017002d, 0x3017002b,
+ 0x30170028, 0x30170026, 0x30170024, 0x30170022,
+ 0x30170020, 0x3017001e, 0x3017001d, 0x3017001b,
+ 0x3017001a, 0x30170018, 0x30170017, 0x30170015,
+ 0x300f002c, 0x300f0029, 0x300f0027, 0x300f0024,
+ 0x300f0022, 0x300f0021, 0x300f001f, 0x300f001d,
+ 0x300f001b, 0x300f001a, 0x300f0018, 0x300f0017,
+ 0x300f0016, 0x300f0015, 0x300f0115, 0x300f0215,
+ 0x300f0315, 0x300f0415, 0x300f0515, 0x300f0615,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+};
+
/* Extracted from MMIO dump of 6.30.223.141 */
static const u32 b43_ntab_tx_gain_ipa_2057_rev9_2g[] = {
0x60ff0031, 0x60e7002c, 0x60cf002a, 0x60c70029,
@@ -2658,6 +2764,42 @@ static const u32 b43_ntab_tx_gain_ipa_2057_rev9_2g[] = {
0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715,
};
+/* Extracted from MMIO dump of 6.30.223.248 */
+static const u32 b43_ntab_tx_gain_ipa_2057_rev14_2g[] = {
+ 0x50df002e, 0x50cf002d, 0x50bf002c, 0x50b7002b,
+ 0x50af002a, 0x50a70029, 0x509f0029, 0x50970028,
+ 0x508f0027, 0x50870027, 0x507f0027, 0x50770027,
+ 0x506f0027, 0x50670027, 0x505f0028, 0x50570029,
+ 0x504f002b, 0x5047002e, 0x5047002b, 0x50470029,
+ 0x503f002c, 0x503f0029, 0x5037002c, 0x5037002a,
+ 0x50370028, 0x502f002d, 0x502f002b, 0x502f0028,
+ 0x502f0026, 0x5027002d, 0x5027002a, 0x50270028,
+ 0x50270026, 0x50270024, 0x501f002e, 0x501f002b,
+ 0x501f0029, 0x501f0027, 0x501f0024, 0x501f0022,
+ 0x501f0020, 0x501f001f, 0x5017002c, 0x50170029,
+ 0x50170027, 0x50170024, 0x50170022, 0x50170021,
+ 0x5017001f, 0x5017001d, 0x5017001b, 0x5017001a,
+ 0x50170018, 0x50170017, 0x50170015, 0x500f002c,
+ 0x500f002a, 0x500f0027, 0x500f0025, 0x500f0023,
+ 0x500f0022, 0x500f001f, 0x500f001e, 0x500f001c,
+ 0x500f001a, 0x500f0019, 0x500f0018, 0x500f0016,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+ 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015,
+};
+
/* IPA 2 5Hz */
static const u32 b43_ntab_tx_gain_ipa_rev3_5g[] = {
@@ -2967,11 +3109,11 @@ static const struct nphy_rf_control_override_rev7
{ 0x0010, 0x07A, 0x07D, 0x0010, 4 },
{ 0x0020, 0x07A, 0x07D, 0x0020, 5 },
{ 0x0040, 0x07A, 0x07D, 0x0040, 6 },
- { 0x0080, 0x0F8, 0x0FA, 0x0080, 7 },
+ { 0x0080, 0x07A, 0x07D, 0x0080, 7 },
{ 0x0400, 0x0F8, 0x0FA, 0x0070, 4 },
{ 0x0800, 0x07B, 0x07E, 0xFFFF, 0 },
{ 0x1000, 0x07C, 0x07F, 0xFFFF, 0 },
- { 0x6000, 0x348, 0x349, 0xFFFF, 0 },
+ { 0x6000, 0x348, 0x349, 0x00FF, 0 },
{ 0x2000, 0x348, 0x349, 0x000F, 0 },
};
@@ -3477,9 +3619,18 @@ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev)
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
switch (phy->rev) {
+ case 17:
+ if (phy->radio_rev == 14)
+ return b43_ntab_tx_gain_ipa_2057_rev14_2g;
+ break;
case 16:
if (phy->radio_rev == 9)
return b43_ntab_tx_gain_ipa_2057_rev9_2g;
+ break;
+ case 8:
+ if (phy->radio_rev == 5)
+ return b43_ntab_tx_gain_ipa_2057_rev5_2g;
+ break;
case 6:
if (dev->dev->chip_id == BCMA_CHIP_ID_BCM47162)
return b43_ntab_tx_gain_ipa_rev5_2g;
@@ -3489,23 +3640,24 @@ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev)
case 4:
case 3:
return b43_ntab_tx_gain_ipa_rev3_2g;
- default:
- b43err(dev->wl,
- "No 2GHz IPA gain table available for this device\n");
- return NULL;
}
+
+ b43err(dev->wl,
+ "No 2GHz IPA gain table available for this device\n");
+ return NULL;
} else {
switch (phy->rev) {
case 16:
if (phy->radio_rev == 9)
return b43_ntab_tx_gain_ipa_2057_rev9_5g;
+ break;
case 3 ... 6:
return b43_ntab_tx_gain_ipa_rev3_5g;
- default:
- b43err(dev->wl,
- "No 5GHz IPA gain table available for this device\n");
- return NULL;
}
+
+ b43err(dev->wl,
+ "No 5GHz IPA gain table available for this device\n");
+ return NULL;
}
}
@@ -3530,7 +3682,7 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev)
case 4:
return sprom->fem.ghz5.extpa_gain == 3 ?
b43_ntab_tx_gain_epa_rev4_5g :
- b43_ntab_tx_gain_epa_rev4_5g; /* FIXME */
+ b43_ntab_tx_gain_epa_rev4_hi_pwr_5g;
case 3:
return b43_ntab_tx_gain_epa_rev3_5g;
default:
@@ -3543,7 +3695,7 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev)
case 6:
case 5:
if (sprom->fem.ghz5.extpa_gain == 3)
- return b43_ntab_tx_gain_epa_rev3_2g; /* FIXME */
+ return b43_ntab_tx_gain_epa_rev3_hi_pwr_2g;
/* fall through */
case 4:
case 3:
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index 6e6ef3fc2247..426dc13c44cd 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -80,9 +80,10 @@ static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp)
}
/* Extract the bitrate index out of an OFDM PLCP header. */
-static int b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy)
+static int b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool ghz5)
{
- int base = aphy ? 0 : 4;
+ /* For 2 GHz band first OFDM rate is at index 4, see main.c */
+ int base = ghz5 ? 0 : 4;
switch (plcp->raw[0] & 0xF) {
case 0xB:
@@ -767,7 +768,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
if (phystat0 & B43_RX_PHYST0_OFDM)
rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp,
- phytype == B43_PHYTYPE_A);
+ !!(chanstat & B43_RX_CHAN_5GHZ));
else
rate_idx = b43_plcp_get_bitrate_idx_cck(plcp);
if (unlikely(rate_idx == -1)) {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
index 4cffb2ee3673..de0cff3df389 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -34,6 +34,7 @@ brcmfmac-objs += \
dhd_common.o \
dhd_linux.o \
firmware.o \
+ feature.o \
btcoex.o \
vendor.o
brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index a16e644e7c08..f467cafe3e8f 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -25,7 +25,6 @@
#include <linux/mmc/sdio.h>
#include <linux/mmc/core.h>
#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/platform_device.h>
@@ -979,18 +978,20 @@ out:
return ret;
}
+#define BRCMF_SDIO_DEVICE(dev_id) \
+ {SDIO_DEVICE(BRCM_SDIO_VENDOR_ID_BROADCOM, dev_id)}
+
/* devices we support, null terminated */
static const struct sdio_device_id brcmf_sdmmc_ids[] = {
- {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43143)},
- {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43241)},
- {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
- {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
- {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)},
- {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43362)},
- {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM,
- SDIO_DEVICE_ID_BROADCOM_4335_4339)},
- {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4354)},
- { /* end: all zeroes */ },
+ BRCMF_SDIO_DEVICE(BRCM_SDIO_43143_DEVICE_ID),
+ BRCMF_SDIO_DEVICE(BRCM_SDIO_43241_DEVICE_ID),
+ BRCMF_SDIO_DEVICE(BRCM_SDIO_4329_DEVICE_ID),
+ BRCMF_SDIO_DEVICE(BRCM_SDIO_4330_DEVICE_ID),
+ BRCMF_SDIO_DEVICE(BRCM_SDIO_4334_DEVICE_ID),
+ BRCMF_SDIO_DEVICE(BRCM_SDIO_43362_DEVICE_ID),
+ BRCMF_SDIO_DEVICE(BRCM_SDIO_4335_4339_DEVICE_ID),
+ BRCMF_SDIO_DEVICE(BRCM_SDIO_4354_DEVICE_ID),
+ { /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
index c7c9f15c0fe0..96800db0536b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
@@ -482,30 +482,30 @@ static inline int brcmf_chip_cores_check(struct brcmf_chip_priv *ci)
static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci)
{
switch (ci->pub.chip) {
- case BCM4329_CHIP_ID:
+ case BRCM_CC_4329_CHIP_ID:
ci->pub.ramsize = BCM4329_RAMSIZE;
break;
- case BCM43143_CHIP_ID:
+ case BRCM_CC_43143_CHIP_ID:
ci->pub.ramsize = BCM43143_RAMSIZE;
break;
- case BCM43241_CHIP_ID:
+ case BRCM_CC_43241_CHIP_ID:
ci->pub.ramsize = 0x90000;
break;
- case BCM4330_CHIP_ID:
+ case BRCM_CC_4330_CHIP_ID:
ci->pub.ramsize = 0x48000;
break;
- case BCM4334_CHIP_ID:
+ case BRCM_CC_4334_CHIP_ID:
ci->pub.ramsize = 0x80000;
break;
- case BCM4335_CHIP_ID:
+ case BRCM_CC_4335_CHIP_ID:
ci->pub.ramsize = 0xc0000;
ci->pub.rambase = 0x180000;
break;
- case BCM43362_CHIP_ID:
+ case BRCM_CC_43362_CHIP_ID:
ci->pub.ramsize = 0x3c000;
break;
- case BCM4339_CHIP_ID:
- case BCM4354_CHIP_ID:
+ case BRCM_CC_4339_CHIP_ID:
+ case BRCM_CC_4354_CHIP_ID:
ci->pub.ramsize = 0xc0000;
ci->pub.rambase = 0x180000;
break;
@@ -682,7 +682,7 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci)
ci->pub.chiprev);
if (socitype == SOCI_SB) {
- if (ci->pub.chip != BCM4329_CHIP_ID) {
+ if (ci->pub.chip != BRCM_CC_4329_CHIP_ID) {
brcmf_err("SB chip is not supported\n");
return -ENODEV;
}
@@ -1008,13 +1008,13 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
chip = container_of(pub, struct brcmf_chip_priv, pub);
switch (pub->chip) {
- case BCM4354_CHIP_ID:
+ case BRCM_CC_4354_CHIP_ID:
/* explicitly check SR engine enable bit */
pmu_cc3_mask = BIT(2);
/* fall-through */
- case BCM43241_CHIP_ID:
- case BCM4335_CHIP_ID:
- case BCM4339_CHIP_ID:
+ case BRCM_CC_43241_CHIP_ID:
+ case BRCM_CC_4335_CHIP_ID:
+ case BRCM_CC_4339_CHIP_ID:
/* read PMU chipcontrol register 3 */
addr = CORE_CC_REG(base, chipcontrol_addr);
chip->ops->write32(chip->ctx, addr, 3);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index a8998eb60d22..7da6441bcfa8 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -103,6 +103,10 @@ struct brcmf_pub {
struct brcmf_ampdu_rx_reorder
*reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS];
+
+ u32 feat_flags;
+ u32 chip_quirks;
+
#ifdef DEBUG
struct dentry *dbgfs_dir;
#endif
@@ -175,7 +179,6 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
void brcmf_txflowblock_if(struct brcmf_if *ifp,
enum brcmf_netif_stop_reason reason, bool state);
-u32 brcmf_get_chip_info(struct brcmf_if *ifp);
void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
bool success);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
index 03fe8aca4d32..be9f4f829192 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
@@ -41,37 +41,12 @@ void brcmf_debugfs_exit(void)
root_folder = NULL;
}
-static
-ssize_t brcmf_debugfs_chipinfo_read(struct file *f, char __user *data,
- size_t count, loff_t *ppos)
+static int brcmf_debugfs_chipinfo_read(struct seq_file *seq, void *data)
{
- struct brcmf_pub *drvr = f->private_data;
- struct brcmf_bus *bus = drvr->bus_if;
- char buf[40];
- int res;
-
- /* only allow read from start */
- if (*ppos > 0)
- return 0;
-
- res = scnprintf(buf, sizeof(buf), "chip: %x(%u) rev %u\n",
- bus->chip, bus->chip, bus->chiprev);
- return simple_read_from_buffer(data, count, ppos, buf, res);
-}
-
-static const struct file_operations brcmf_debugfs_chipinfo_ops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = brcmf_debugfs_chipinfo_read
-};
-
-static int brcmf_debugfs_create_chipinfo(struct brcmf_pub *drvr)
-{
- struct dentry *dentry = drvr->dbgfs_dir;
+ struct brcmf_bus *bus = dev_get_drvdata(seq->private);
- if (!IS_ERR_OR_NULL(dentry))
- debugfs_create_file("chipinfo", S_IRUGO, dentry, drvr,
- &brcmf_debugfs_chipinfo_ops);
+ seq_printf(seq, "chip: %x(%u) rev %u\n",
+ bus->chip, bus->chip, bus->chiprev);
return 0;
}
@@ -83,7 +58,8 @@ int brcmf_debugfs_attach(struct brcmf_pub *drvr)
return -ENODEV;
drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
- brcmf_debugfs_create_chipinfo(drvr);
+ brcmf_debugfs_add_entry(drvr, "chipinfo", brcmf_debugfs_chipinfo_read);
+
return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
}
@@ -98,148 +74,44 @@ struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr)
return drvr->dbgfs_dir;
}
-static
-ssize_t brcmf_debugfs_sdio_counter_read(struct file *f, char __user *data,
- size_t count, loff_t *ppos)
-{
- struct brcmf_sdio_count *sdcnt = f->private_data;
- char buf[750];
- int res;
-
- /* only allow read from start */
- if (*ppos > 0)
- return 0;
-
- res = scnprintf(buf, sizeof(buf),
- "intrcount: %u\nlastintrs: %u\n"
- "pollcnt: %u\nregfails: %u\n"
- "tx_sderrs: %u\nfcqueued: %u\n"
- "rxrtx: %u\nrx_toolong: %u\n"
- "rxc_errors: %u\nrx_hdrfail: %u\n"
- "rx_badhdr: %u\nrx_badseq: %u\n"
- "fc_rcvd: %u\nfc_xoff: %u\n"
- "fc_xon: %u\nrxglomfail: %u\n"
- "rxglomframes: %u\nrxglompkts: %u\n"
- "f2rxhdrs: %u\nf2rxdata: %u\n"
- "f2txdata: %u\nf1regdata: %u\n"
- "tickcnt: %u\ntx_ctlerrs: %lu\n"
- "tx_ctlpkts: %lu\nrx_ctlerrs: %lu\n"
- "rx_ctlpkts: %lu\nrx_readahead: %lu\n",
- sdcnt->intrcount, sdcnt->lastintrs,
- sdcnt->pollcnt, sdcnt->regfails,
- sdcnt->tx_sderrs, sdcnt->fcqueued,
- sdcnt->rxrtx, sdcnt->rx_toolong,
- sdcnt->rxc_errors, sdcnt->rx_hdrfail,
- sdcnt->rx_badhdr, sdcnt->rx_badseq,
- sdcnt->fc_rcvd, sdcnt->fc_xoff,
- sdcnt->fc_xon, sdcnt->rxglomfail,
- sdcnt->rxglomframes, sdcnt->rxglompkts,
- sdcnt->f2rxhdrs, sdcnt->f2rxdata,
- sdcnt->f2txdata, sdcnt->f1regdata,
- sdcnt->tickcnt, sdcnt->tx_ctlerrs,
- sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs,
- sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt);
-
- return simple_read_from_buffer(data, count, ppos, buf, res);
-}
-
-static const struct file_operations brcmf_debugfs_sdio_counter_ops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = brcmf_debugfs_sdio_counter_read
+struct brcmf_debugfs_entry {
+ int (*read)(struct seq_file *seq, void *data);
+ struct brcmf_pub *drvr;
};
-void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
- struct brcmf_sdio_count *sdcnt)
+static int brcmf_debugfs_entry_open(struct inode *inode, struct file *f)
{
- struct dentry *dentry = drvr->dbgfs_dir;
+ struct brcmf_debugfs_entry *entry = inode->i_private;
- if (!IS_ERR_OR_NULL(dentry))
- debugfs_create_file("counters", S_IRUGO, dentry,
- sdcnt, &brcmf_debugfs_sdio_counter_ops);
-}
-
-static
-ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data,
- size_t count, loff_t *ppos)
-{
- struct brcmf_fws_stats *fwstats = f->private_data;
- char buf[650];
- int res;
-
- /* only allow read from start */
- if (*ppos > 0)
- return 0;
-
- res = scnprintf(buf, sizeof(buf),
- "header_pulls: %u\n"
- "header_only_pkt: %u\n"
- "tlv_parse_failed: %u\n"
- "tlv_invalid_type: %u\n"
- "mac_update_fails: %u\n"
- "ps_update_fails: %u\n"
- "if_update_fails: %u\n"
- "pkt2bus: %u\n"
- "generic_error: %u\n"
- "rollback_success: %u\n"
- "rollback_failed: %u\n"
- "delayq_full: %u\n"
- "supprq_full: %u\n"
- "txs_indicate: %u\n"
- "txs_discard: %u\n"
- "txs_suppr_core: %u\n"
- "txs_suppr_ps: %u\n"
- "txs_tossed: %u\n"
- "txs_host_tossed: %u\n"
- "bus_flow_block: %u\n"
- "fws_flow_block: %u\n"
- "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n"
- "requested_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n",
- fwstats->header_pulls,
- fwstats->header_only_pkt,
- fwstats->tlv_parse_failed,
- fwstats->tlv_invalid_type,
- fwstats->mac_update_failed,
- fwstats->mac_ps_update_failed,
- fwstats->if_update_failed,
- fwstats->pkt2bus,
- fwstats->generic_error,
- fwstats->rollback_success,
- fwstats->rollback_failed,
- fwstats->delayq_full_error,
- fwstats->supprq_full_error,
- fwstats->txs_indicate,
- fwstats->txs_discard,
- fwstats->txs_supp_core,
- fwstats->txs_supp_ps,
- fwstats->txs_tossed,
- fwstats->txs_host_tossed,
- fwstats->bus_flow_block,
- fwstats->fws_flow_block,
- fwstats->send_pkts[0], fwstats->send_pkts[1],
- fwstats->send_pkts[2], fwstats->send_pkts[3],
- fwstats->send_pkts[4],
- fwstats->requested_sent[0],
- fwstats->requested_sent[1],
- fwstats->requested_sent[2],
- fwstats->requested_sent[3],
- fwstats->requested_sent[4]);
-
- return simple_read_from_buffer(data, count, ppos, buf, res);
+ return single_open(f, entry->read, entry->drvr->bus_if->dev);
}
-static const struct file_operations brcmf_debugfs_fws_stats_ops = {
+static const struct file_operations brcmf_debugfs_def_ops = {
.owner = THIS_MODULE,
- .open = simple_open,
- .read = brcmf_debugfs_fws_stats_read
+ .open = brcmf_debugfs_entry_open,
+ .release = single_release,
+ .read = seq_read,
+ .llseek = seq_lseek
};
-void brcmf_debugfs_create_fws_stats(struct brcmf_pub *drvr,
- struct brcmf_fws_stats *stats)
+int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
+ int (*read_fn)(struct seq_file *seq, void *data))
{
struct dentry *dentry = drvr->dbgfs_dir;
+ struct brcmf_debugfs_entry *entry;
+
+ if (IS_ERR_OR_NULL(dentry))
+ return -ENOENT;
+
+ entry = devm_kzalloc(drvr->bus_if->dev, sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->read = read_fn;
+ entry->drvr = drvr;
+
+ dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry,
+ &brcmf_debugfs_def_ops);
- if (!IS_ERR_OR_NULL(dentry))
- debugfs_create_file("fws_stats", S_IRUGO, dentry,
- stats, &brcmf_debugfs_fws_stats_ops);
+ return PTR_ERR_OR_ZERO(dentry);
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
index ef52ed7abc69..6eade7c60c63 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
@@ -100,68 +100,6 @@ do { \
extern int brcmf_msg_level;
-/*
- * hold counter variables used in brcmfmac sdio driver.
- */
-struct brcmf_sdio_count {
- uint intrcount; /* Count of device interrupt callbacks */
- uint lastintrs; /* Count as of last watchdog timer */
- uint pollcnt; /* Count of active polls */
- uint regfails; /* Count of R_REG failures */
- uint tx_sderrs; /* Count of tx attempts with sd errors */
- uint fcqueued; /* Tx packets that got queued */
- uint rxrtx; /* Count of rtx requests (NAK to dongle) */
- uint rx_toolong; /* Receive frames too long to receive */
- uint rxc_errors; /* SDIO errors when reading control frames */
- uint rx_hdrfail; /* SDIO errors on header reads */
- uint rx_badhdr; /* Bad received headers (roosync?) */
- uint rx_badseq; /* Mismatched rx sequence number */
- uint fc_rcvd; /* Number of flow-control events received */
- uint fc_xoff; /* Number which turned on flow-control */
- uint fc_xon; /* Number which turned off flow-control */
- uint rxglomfail; /* Failed deglom attempts */
- uint rxglomframes; /* Number of glom frames (superframes) */
- uint rxglompkts; /* Number of packets from glom frames */
- uint f2rxhdrs; /* Number of header reads */
- uint f2rxdata; /* Number of frame data reads */
- uint f2txdata; /* Number of f2 frame writes */
- uint f1regdata; /* Number of f1 register accesses */
- uint tickcnt; /* Number of watchdog been schedule */
- ulong tx_ctlerrs; /* Err of sending ctrl frames */
- ulong tx_ctlpkts; /* Ctrl frames sent to dongle */
- ulong rx_ctlerrs; /* Err of processing rx ctrl frames */
- ulong rx_ctlpkts; /* Ctrl frames processed from dongle */
- ulong rx_readahead_cnt; /* packets where header read-ahead was used */
-};
-
-struct brcmf_fws_stats {
- u32 tlv_parse_failed;
- u32 tlv_invalid_type;
- u32 header_only_pkt;
- u32 header_pulls;
- u32 pkt2bus;
- u32 send_pkts[5];
- u32 requested_sent[5];
- u32 generic_error;
- u32 mac_update_failed;
- u32 mac_ps_update_failed;
- u32 if_update_failed;
- u32 packet_request_failed;
- u32 credit_request_failed;
- u32 rollback_success;
- u32 rollback_failed;
- u32 delayq_full_error;
- u32 supprq_full_error;
- u32 txs_indicate;
- u32 txs_discard;
- u32 txs_supp_core;
- u32 txs_supp_ps;
- u32 txs_tossed;
- u32 txs_host_tossed;
- u32 bus_flow_block;
- u32 fws_flow_block;
-};
-
struct brcmf_pub;
#ifdef DEBUG
void brcmf_debugfs_init(void);
@@ -169,10 +107,8 @@ void brcmf_debugfs_exit(void);
int brcmf_debugfs_attach(struct brcmf_pub *drvr);
void brcmf_debugfs_detach(struct brcmf_pub *drvr);
struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
-void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
- struct brcmf_sdio_count *sdcnt);
-void brcmf_debugfs_create_fws_stats(struct brcmf_pub *drvr,
- struct brcmf_fws_stats *stats);
+int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
+ int (*read_fn)(struct seq_file *seq, void *data));
#else
static inline void brcmf_debugfs_init(void)
{
@@ -187,9 +123,11 @@ static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr)
static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr)
{
}
-static inline void brcmf_debugfs_create_fws_stats(struct brcmf_pub *drvr,
- struct brcmf_fws_stats *stats)
+static inline
+int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
+ int (*read_fn)(struct seq_file *seq, void *data))
{
+ return 0;
}
#endif
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index 2699441d4f41..347b4260f45b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -30,6 +30,7 @@
#include "wl_cfg80211.h"
#include "fwil.h"
#include "fwsignal.h"
+#include "feature.h"
#include "proto.h"
MODULE_AUTHOR("Broadcom Corporation");
@@ -937,6 +938,8 @@ int brcmf_bus_start(struct device *dev)
if (ret < 0)
goto fail;
+ brcmf_feat_attach(drvr);
+
ret = brcmf_fws_init(drvr);
if (ret < 0)
goto fail;
@@ -1074,16 +1077,6 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
return !err;
}
-/*
- * return chip id and rev of the device encoded in u32.
- */
-u32 brcmf_get_chip_info(struct brcmf_if *ifp)
-{
- struct brcmf_bus *bus = ifp->drvr->bus_if;
-
- return bus->chip << 4 | bus->chiprev;
-}
-
static void brcmf_driver_register(struct work_struct *work)
{
#ifdef CONFIG_BRCMFMAC_SDIO
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 8fa0dbbbda72..67d91d5cc13d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -391,6 +391,40 @@ struct brcmf_sdio_hdrinfo {
u16 tail_pad;
};
+/*
+ * hold counter variables
+ */
+struct brcmf_sdio_count {
+ uint intrcount; /* Count of device interrupt callbacks */
+ uint lastintrs; /* Count as of last watchdog timer */
+ uint pollcnt; /* Count of active polls */
+ uint regfails; /* Count of R_REG failures */
+ uint tx_sderrs; /* Count of tx attempts with sd errors */
+ uint fcqueued; /* Tx packets that got queued */
+ uint rxrtx; /* Count of rtx requests (NAK to dongle) */
+ uint rx_toolong; /* Receive frames too long to receive */
+ uint rxc_errors; /* SDIO errors when reading control frames */
+ uint rx_hdrfail; /* SDIO errors on header reads */
+ uint rx_badhdr; /* Bad received headers (roosync?) */
+ uint rx_badseq; /* Mismatched rx sequence number */
+ uint fc_rcvd; /* Number of flow-control events received */
+ uint fc_xoff; /* Number which turned on flow-control */
+ uint fc_xon; /* Number which turned off flow-control */
+ uint rxglomfail; /* Failed deglom attempts */
+ uint rxglomframes; /* Number of glom frames (superframes) */
+ uint rxglompkts; /* Number of packets from glom frames */
+ uint f2rxhdrs; /* Number of header reads */
+ uint f2rxdata; /* Number of frame data reads */
+ uint f2txdata; /* Number of f2 frame writes */
+ uint f1regdata; /* Number of f1 register accesses */
+ uint tickcnt; /* Number of watchdog been schedule */
+ ulong tx_ctlerrs; /* Err of sending ctrl frames */
+ ulong tx_ctlpkts; /* Ctrl frames sent to dongle */
+ ulong rx_ctlerrs; /* Err of processing rx ctrl frames */
+ ulong rx_ctlpkts; /* Ctrl frames processed from dongle */
+ ulong rx_readahead_cnt; /* packets where header read-ahead was used */
+};
+
/* misc chip info needed by some of the routines */
/* Private data for SDIO bus interaction */
struct brcmf_sdio {
@@ -620,40 +654,46 @@ enum brcmf_firmware_type {
name ## _FIRMWARE_NAME, name ## _NVRAM_NAME
static const struct brcmf_firmware_names brcmf_fwname_data[] = {
- { BCM43143_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43143) },
- { BCM43241_CHIP_ID, 0x0000001F, BRCMF_FIRMWARE_NVRAM(BCM43241B0) },
- { BCM43241_CHIP_ID, 0xFFFFFFE0, BRCMF_FIRMWARE_NVRAM(BCM43241B4) },
- { BCM4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) },
- { BCM4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) },
- { BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
- { BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) },
- { BCM43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) },
- { BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) },
- { BCM4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) }
+ { BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43143) },
+ { BRCM_CC_43241_CHIP_ID, 0x0000001F, BRCMF_FIRMWARE_NVRAM(BCM43241B0) },
+ { BRCM_CC_43241_CHIP_ID, 0xFFFFFFE0, BRCMF_FIRMWARE_NVRAM(BCM43241B4) },
+ { BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) },
+ { BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) },
+ { BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
+ { BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) },
+ { BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) },
+ { BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) },
+ { BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) }
};
-static const char *brcmf_sdio_get_fwname(struct brcmf_chip *ci,
- enum brcmf_firmware_type type)
+static int brcmf_sdio_get_fwnames(struct brcmf_chip *ci,
+ struct brcmf_sdio_dev *sdiodev)
{
int i;
for (i = 0; i < ARRAY_SIZE(brcmf_fwname_data); i++) {
if (brcmf_fwname_data[i].chipid == ci->chip &&
- brcmf_fwname_data[i].revmsk & BIT(ci->chiprev)) {
- switch (type) {
- case BRCMF_FIRMWARE_BIN:
- return brcmf_fwname_data[i].bin;
- case BRCMF_FIRMWARE_NVRAM:
- return brcmf_fwname_data[i].nv;
- default:
- brcmf_err("invalid firmware type (%d)\n", type);
- return NULL;
- }
- }
+ brcmf_fwname_data[i].revmsk & BIT(ci->chiprev))
+ break;
}
- brcmf_err("Unknown chipid %d [%d]\n",
- ci->chip, ci->chiprev);
- return NULL;
+
+ if (i == ARRAY_SIZE(brcmf_fwname_data)) {
+ brcmf_err("Unknown chipid %d [%d]\n", ci->chip, ci->chiprev);
+ return -ENODEV;
+ }
+
+ /* check if firmware path is provided by module parameter */
+ if (brcmf_firmware_path[0] != '\0') {
+ if (brcmf_firmware_path[strlen(brcmf_firmware_path) - 1] != '/')
+ strcat(brcmf_firmware_path, "/");
+
+ strcpy(sdiodev->fw_name, brcmf_firmware_path);
+ strcpy(sdiodev->nvram_name, brcmf_firmware_path);
+ }
+ strcat(sdiodev->fw_name, brcmf_fwname_data[i].bin);
+ strcat(sdiodev->nvram_name, brcmf_fwname_data[i].nv);
+
+ return 0;
}
static void pkt_align(struct sk_buff *p, int len, int align)
@@ -2898,16 +2938,13 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
}
#ifdef DEBUG
-static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,
- struct sdpcm_shared *sh, char __user *data,
- size_t count)
+static int brcmf_sdio_dump_console(struct seq_file *seq, struct brcmf_sdio *bus,
+ struct sdpcm_shared *sh)
{
u32 addr, console_ptr, console_size, console_index;
char *conbuf = NULL;
__le32 sh_val;
int rv;
- loff_t pos = 0;
- int nbytes = 0;
/* obtain console information from device memory */
addr = sh->console_addr + offsetof(struct rte_console, log_le);
@@ -2945,33 +2982,24 @@ static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,
if (rv < 0)
goto done;
- rv = simple_read_from_buffer(data, count, &pos,
- conbuf + console_index,
- console_size - console_index);
+ rv = seq_write(seq, conbuf + console_index,
+ console_size - console_index);
if (rv < 0)
goto done;
- nbytes = rv;
- if (console_index > 0) {
- pos = 0;
- rv = simple_read_from_buffer(data+nbytes, count, &pos,
- conbuf, console_index - 1);
- if (rv < 0)
- goto done;
- rv += nbytes;
- }
+ if (console_index > 0)
+ rv = seq_write(seq, conbuf, console_index - 1);
+
done:
vfree(conbuf);
return rv;
}
-static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
- char __user *data, size_t count)
+static int brcmf_sdio_trap_info(struct seq_file *seq, struct brcmf_sdio *bus,
+ struct sdpcm_shared *sh)
{
- int error, res;
- char buf[350];
+ int error;
struct brcmf_trap_info tr;
- loff_t pos = 0;
if ((sh->flags & SDPCM_SHARED_TRAP) == 0) {
brcmf_dbg(INFO, "no trap in firmware\n");
@@ -2983,34 +3011,30 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
if (error < 0)
return error;
- res = scnprintf(buf, sizeof(buf),
- "dongle trap info: type 0x%x @ epc 0x%08x\n"
- " cpsr 0x%08x spsr 0x%08x sp 0x%08x\n"
- " lr 0x%08x pc 0x%08x offset 0x%x\n"
- " r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n"
- " r4 0x%08x r5 0x%08x r6 0x%08x r7 0x%08x\n",
- le32_to_cpu(tr.type), le32_to_cpu(tr.epc),
- le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr),
- le32_to_cpu(tr.r13), le32_to_cpu(tr.r14),
- le32_to_cpu(tr.pc), sh->trap_addr,
- le32_to_cpu(tr.r0), le32_to_cpu(tr.r1),
- le32_to_cpu(tr.r2), le32_to_cpu(tr.r3),
- le32_to_cpu(tr.r4), le32_to_cpu(tr.r5),
- le32_to_cpu(tr.r6), le32_to_cpu(tr.r7));
-
- return simple_read_from_buffer(data, count, &pos, buf, res);
+ seq_printf(seq,
+ "dongle trap info: type 0x%x @ epc 0x%08x\n"
+ " cpsr 0x%08x spsr 0x%08x sp 0x%08x\n"
+ " lr 0x%08x pc 0x%08x offset 0x%x\n"
+ " r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n"
+ " r4 0x%08x r5 0x%08x r6 0x%08x r7 0x%08x\n",
+ le32_to_cpu(tr.type), le32_to_cpu(tr.epc),
+ le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr),
+ le32_to_cpu(tr.r13), le32_to_cpu(tr.r14),
+ le32_to_cpu(tr.pc), sh->trap_addr,
+ le32_to_cpu(tr.r0), le32_to_cpu(tr.r1),
+ le32_to_cpu(tr.r2), le32_to_cpu(tr.r3),
+ le32_to_cpu(tr.r4), le32_to_cpu(tr.r5),
+ le32_to_cpu(tr.r6), le32_to_cpu(tr.r7));
+
+ return 0;
}
-static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
- struct sdpcm_shared *sh, char __user *data,
- size_t count)
+static int brcmf_sdio_assert_info(struct seq_file *seq, struct brcmf_sdio *bus,
+ struct sdpcm_shared *sh)
{
int error = 0;
- char buf[200];
char file[80] = "?";
char expr[80] = "<???>";
- int res;
- loff_t pos = 0;
if ((sh->flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
brcmf_dbg(INFO, "firmware not built with -assert\n");
@@ -3035,10 +3059,9 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
}
sdio_release_host(bus->sdiodev->func[1]);
- res = scnprintf(buf, sizeof(buf),
- "dongle assert: %s:%d: assert(%s)\n",
- file, sh->assert_line, expr);
- return simple_read_from_buffer(data, count, &pos, buf, res);
+ seq_printf(seq, "dongle assert: %s:%d: assert(%s)\n",
+ file, sh->assert_line, expr);
+ return 0;
}
static int brcmf_sdio_checkdied(struct brcmf_sdio *bus)
@@ -3062,59 +3085,75 @@ static int brcmf_sdio_checkdied(struct brcmf_sdio *bus)
return 0;
}
-static int brcmf_sdio_died_dump(struct brcmf_sdio *bus, char __user *data,
- size_t count, loff_t *ppos)
+static int brcmf_sdio_died_dump(struct seq_file *seq, struct brcmf_sdio *bus)
{
int error = 0;
struct sdpcm_shared sh;
- int nbytes = 0;
- loff_t pos = *ppos;
-
- if (pos != 0)
- return 0;
error = brcmf_sdio_readshared(bus, &sh);
if (error < 0)
goto done;
- error = brcmf_sdio_assert_info(bus, &sh, data, count);
+ error = brcmf_sdio_assert_info(seq, bus, &sh);
if (error < 0)
goto done;
- nbytes = error;
- error = brcmf_sdio_trap_info(bus, &sh, data+nbytes, count);
+ error = brcmf_sdio_trap_info(seq, bus, &sh);
if (error < 0)
goto done;
- nbytes += error;
- error = brcmf_sdio_dump_console(bus, &sh, data+nbytes, count);
- if (error < 0)
- goto done;
- nbytes += error;
+ error = brcmf_sdio_dump_console(seq, bus, &sh);
- error = nbytes;
- *ppos += nbytes;
done:
return error;
}
-static ssize_t brcmf_sdio_forensic_read(struct file *f, char __user *data,
- size_t count, loff_t *ppos)
+static int brcmf_sdio_forensic_read(struct seq_file *seq, void *data)
{
- struct brcmf_sdio *bus = f->private_data;
- int res;
+ struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
+ struct brcmf_sdio *bus = bus_if->bus_priv.sdio->bus;
- res = brcmf_sdio_died_dump(bus, data, count, ppos);
- if (res > 0)
- *ppos += res;
- return (ssize_t)res;
+ return brcmf_sdio_died_dump(seq, bus);
}
-static const struct file_operations brcmf_sdio_forensic_ops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = brcmf_sdio_forensic_read
-};
+static int brcmf_debugfs_sdio_count_read(struct seq_file *seq, void *data)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_sdio_count *sdcnt = &sdiodev->bus->sdcnt;
+
+ seq_printf(seq,
+ "intrcount: %u\nlastintrs: %u\n"
+ "pollcnt: %u\nregfails: %u\n"
+ "tx_sderrs: %u\nfcqueued: %u\n"
+ "rxrtx: %u\nrx_toolong: %u\n"
+ "rxc_errors: %u\nrx_hdrfail: %u\n"
+ "rx_badhdr: %u\nrx_badseq: %u\n"
+ "fc_rcvd: %u\nfc_xoff: %u\n"
+ "fc_xon: %u\nrxglomfail: %u\n"
+ "rxglomframes: %u\nrxglompkts: %u\n"
+ "f2rxhdrs: %u\nf2rxdata: %u\n"
+ "f2txdata: %u\nf1regdata: %u\n"
+ "tickcnt: %u\ntx_ctlerrs: %lu\n"
+ "tx_ctlpkts: %lu\nrx_ctlerrs: %lu\n"
+ "rx_ctlpkts: %lu\nrx_readahead: %lu\n",
+ sdcnt->intrcount, sdcnt->lastintrs,
+ sdcnt->pollcnt, sdcnt->regfails,
+ sdcnt->tx_sderrs, sdcnt->fcqueued,
+ sdcnt->rxrtx, sdcnt->rx_toolong,
+ sdcnt->rxc_errors, sdcnt->rx_hdrfail,
+ sdcnt->rx_badhdr, sdcnt->rx_badseq,
+ sdcnt->fc_rcvd, sdcnt->fc_xoff,
+ sdcnt->fc_xon, sdcnt->rxglomfail,
+ sdcnt->rxglomframes, sdcnt->rxglompkts,
+ sdcnt->f2rxhdrs, sdcnt->f2rxdata,
+ sdcnt->f2txdata, sdcnt->f1regdata,
+ sdcnt->tickcnt, sdcnt->tx_ctlerrs,
+ sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs,
+ sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt);
+
+ return 0;
+}
static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
{
@@ -3124,9 +3163,9 @@ static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
if (IS_ERR_OR_NULL(dentry))
return;
- debugfs_create_file("forensics", S_IRUGO, dentry, bus,
- &brcmf_sdio_forensic_ops);
- brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt);
+ brcmf_debugfs_add_entry(drvr, "forensics", brcmf_sdio_forensic_read);
+ brcmf_debugfs_add_entry(drvr, "counters",
+ brcmf_debugfs_sdio_count_read);
debugfs_create_u32("console_interval", 0644, dentry,
&bus->console_interval);
}
@@ -3598,17 +3637,17 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
return;
switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
- case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
+ case SDIOD_DRVSTR_KEY(BRCM_CC_4330_CHIP_ID, 12):
str_tab = sdiod_drvstr_tab1_1v8;
str_mask = 0x00003800;
str_shift = 11;
break;
- case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17):
+ case SDIOD_DRVSTR_KEY(BRCM_CC_4334_CHIP_ID, 17):
str_tab = sdiod_drvstr_tab6_1v8;
str_mask = 0x00001800;
str_shift = 11;
break;
- case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
+ case SDIOD_DRVSTR_KEY(BRCM_CC_43143_CHIP_ID, 17):
/* note: 43143 does not support tristate */
i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1;
if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) {
@@ -3619,7 +3658,7 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n",
ci->name, drivestrength);
break;
- case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
+ case SDIOD_DRVSTR_KEY(BRCM_CC_43362_CHIP_ID, 13):
str_tab = sdiod_drive_strength_tab5_1v8;
str_mask = 0x00003800;
str_shift = 11;
@@ -3720,12 +3759,12 @@ static u32 brcmf_sdio_buscore_read32(void *ctx, u32 addr)
u32 val, rev;
val = brcmf_sdiod_regrl(sdiodev, addr, NULL);
- if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
+ if (sdiodev->func[0]->device == BRCM_SDIO_4335_4339_DEVICE_ID &&
addr == CORE_CC_REG(SI_ENUM_BASE, chipid)) {
rev = (val & CID_REV_MASK) >> CID_REV_SHIFT;
if (rev >= 2) {
val &= ~CID_ID_MASK;
- val |= BCM4339_CHIP_ID;
+ val |= BRCM_CC_4339_CHIP_ID;
}
}
return val;
@@ -4127,11 +4166,12 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
brcmf_sdio_debugfs_create(bus);
brcmf_dbg(INFO, "completed!!\n");
+ ret = brcmf_sdio_get_fwnames(bus->ci, sdiodev);
+ if (ret)
+ goto fail;
+
ret = brcmf_fw_get_firmwares(sdiodev->dev, BRCMF_FW_REQUEST_NVRAM,
- brcmf_sdio_get_fwname(bus->ci,
- BRCMF_FIRMWARE_BIN),
- brcmf_sdio_get_fwname(bus->ci,
- BRCMF_FIRMWARE_NVRAM),
+ sdiodev->fw_name, sdiodev->nvram_name,
brcmf_sdio_firmware_callback);
if (ret != 0) {
brcmf_err("async firmware request failed: %d\n", ret);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
new file mode 100644
index 000000000000..50877e3c5d2f
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/netdevice.h>
+
+#include <brcm_hw_ids.h>
+#include "dhd.h"
+#include "dhd_bus.h"
+#include "dhd_dbg.h"
+#include "fwil.h"
+#include "feature.h"
+
+/*
+ * firmware error code received if iovar is unsupported.
+ */
+#define EBRCMF_FEAT_UNSUPPORTED 23
+
+/*
+ * expand feature list to array of feature strings.
+ */
+#define BRCMF_FEAT_DEF(_f) \
+ #_f,
+static const char *brcmf_feat_names[] = {
+ BRCMF_FEAT_LIST
+};
+#undef BRCMF_FEAT_DEF
+
+#ifdef DEBUG
+/*
+ * expand quirk list to array of quirk strings.
+ */
+#define BRCMF_QUIRK_DEF(_q) \
+ #_q,
+static const char * const brcmf_quirk_names[] = {
+ BRCMF_QUIRK_LIST
+};
+#undef BRCMF_QUIRK_DEF
+
+/**
+ * brcmf_feat_debugfs_read() - expose feature info to debugfs.
+ *
+ * @seq: sequence for debugfs entry.
+ * @data: raw data pointer.
+ */
+static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
+ u32 feats = bus_if->drvr->feat_flags;
+ u32 quirks = bus_if->drvr->chip_quirks;
+ int id;
+
+ seq_printf(seq, "Features: %08x\n", feats);
+ for (id = 0; id < BRCMF_FEAT_LAST; id++)
+ if (feats & BIT(id))
+ seq_printf(seq, "\t%s\n", brcmf_feat_names[id]);
+ seq_printf(seq, "\nQuirks: %08x\n", quirks);
+ for (id = 0; id < BRCMF_FEAT_QUIRK_LAST; id++)
+ if (quirks & BIT(id))
+ seq_printf(seq, "\t%s\n", brcmf_quirk_names[id]);
+ return 0;
+}
+#else
+static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data)
+{
+ return 0;
+}
+#endif /* DEBUG */
+
+/**
+ * brcmf_feat_iovar_int_get() - determine feature through iovar query.
+ *
+ * @ifp: interface to query.
+ * @id: feature id.
+ * @name: iovar name.
+ */
+static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
+ enum brcmf_feat_id id, char *name)
+{
+ u32 data;
+ int err;
+
+ err = brcmf_fil_iovar_int_get(ifp, name, &data);
+ if (err == 0) {
+ brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
+ ifp->drvr->feat_flags |= BIT(id);
+ } else {
+ brcmf_dbg(TRACE, "%s feature check failed: %d\n",
+ brcmf_feat_names[id], err);
+ }
+}
+
+void brcmf_feat_attach(struct brcmf_pub *drvr)
+{
+ struct brcmf_if *ifp = drvr->iflist[0];
+
+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
+
+ /* set chip related quirks */
+ switch (drvr->bus_if->chip) {
+ case BRCM_CC_43236_CHIP_ID:
+ drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_AUTO_AUTH);
+ break;
+ case BRCM_CC_4329_CHIP_ID:
+ drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_NEED_MPC);
+ break;
+ default:
+ /* no quirks */
+ break;
+ }
+
+ brcmf_debugfs_add_entry(drvr, "features", brcmf_feat_debugfs_read);
+}
+
+bool brcmf_feat_is_enabled(struct brcmf_if *ifp, enum brcmf_feat_id id)
+{
+ return (ifp->drvr->feat_flags & BIT(id));
+}
+
+bool brcmf_feat_is_quirk_enabled(struct brcmf_if *ifp,
+ enum brcmf_feat_quirk quirk)
+{
+ return (ifp->drvr->chip_quirks & BIT(quirk));
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/brcm80211/brcmfmac/feature.h
new file mode 100644
index 000000000000..961d175f8afb
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _BRCMF_FEATURE_H
+#define _BRCMF_FEATURE_H
+
+/*
+ * Features:
+ *
+ * MCHAN: multi-channel for concurrent P2P.
+ */
+#define BRCMF_FEAT_LIST \
+ BRCMF_FEAT_DEF(MCHAN)
+/*
+ * Quirks:
+ *
+ * AUTO_AUTH: workaround needed for automatic authentication type.
+ * NEED_MPC: driver needs to disable MPC during scanning operation.
+ */
+#define BRCMF_QUIRK_LIST \
+ BRCMF_QUIRK_DEF(AUTO_AUTH) \
+ BRCMF_QUIRK_DEF(NEED_MPC)
+
+#define BRCMF_FEAT_DEF(_f) \
+ BRCMF_FEAT_ ## _f,
+/*
+ * expand feature list to enumeration.
+ */
+enum brcmf_feat_id {
+ BRCMF_FEAT_LIST
+ BRCMF_FEAT_LAST
+};
+#undef BRCMF_FEAT_DEF
+
+#define BRCMF_QUIRK_DEF(_q) \
+ BRCMF_FEAT_QUIRK_ ## _q,
+/*
+ * expand quirk list to enumeration.
+ */
+enum brcmf_feat_quirk {
+ BRCMF_QUIRK_LIST
+ BRCMF_FEAT_QUIRK_LAST
+};
+#undef BRCMF_QUIRK_DEF
+
+/**
+ * brcmf_feat_attach() - determine features and quirks.
+ *
+ * @drvr: driver instance.
+ */
+void brcmf_feat_attach(struct brcmf_pub *drvr);
+
+/**
+ * brcmf_feat_is_enabled() - query feature.
+ *
+ * @ifp: interface instance.
+ * @id: feature id to check.
+ *
+ * Return: true is feature is enabled; otherwise false.
+ */
+bool brcmf_feat_is_enabled(struct brcmf_if *ifp, enum brcmf_feat_id id);
+
+/**
+ * brcmf_feat_is_quirk_enabled() - query chip quirk.
+ *
+ * @ifp: interface instance.
+ * @quirk: quirk id to check.
+ *
+ * Return: true is quirk is enabled; otherwise false.
+ */
+bool brcmf_feat_is_quirk_enabled(struct brcmf_if *ifp,
+ enum brcmf_feat_quirk quirk);
+
+#endif /* _BRCMF_FEATURE_H */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
index 7b7d237c1ddb..8ea9f283d2b8 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
@@ -18,10 +18,15 @@
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/firmware.h>
+#include <linux/module.h>
#include "dhd_dbg.h"
#include "firmware.h"
+char brcmf_firmware_path[BRCMF_FW_PATH_LEN];
+module_param_string(firmware_path, brcmf_firmware_path,
+ BRCMF_FW_PATH_LEN, 0440);
+
enum nvram_parser_state {
IDLE,
KEY,
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/brcm80211/brcmfmac/firmware.h
index 6431bfd7afff..4d3482356b77 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.h
@@ -21,6 +21,11 @@
#define BRCMF_FW_REQ_FLAGS 0x00F0
#define BRCMF_FW_REQ_NV_OPTIONAL 0x0010
+#define BRCMF_FW_PATH_LEN 256
+#define BRCMF_FW_NAME_LEN 32
+
+extern char brcmf_firmware_path[];
+
void brcmf_fw_nvram_free(void *nvram);
/*
* Request firmware(s) asynchronously. When the asynchronous request
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index 699908de314a..d42f7d04b65f 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -454,6 +454,34 @@ struct brcmf_fws_macdesc_table {
struct brcmf_fws_mac_descriptor other;
};
+struct brcmf_fws_stats {
+ u32 tlv_parse_failed;
+ u32 tlv_invalid_type;
+ u32 header_only_pkt;
+ u32 header_pulls;
+ u32 pkt2bus;
+ u32 send_pkts[5];
+ u32 requested_sent[5];
+ u32 generic_error;
+ u32 mac_update_failed;
+ u32 mac_ps_update_failed;
+ u32 if_update_failed;
+ u32 packet_request_failed;
+ u32 credit_request_failed;
+ u32 rollback_success;
+ u32 rollback_failed;
+ u32 delayq_full_error;
+ u32 supprq_full_error;
+ u32 txs_indicate;
+ u32 txs_discard;
+ u32 txs_supp_core;
+ u32 txs_supp_ps;
+ u32 txs_tossed;
+ u32 txs_host_tossed;
+ u32 bus_flow_block;
+ u32 fws_flow_block;
+};
+
struct brcmf_fws_info {
struct brcmf_pub *drvr;
spinlock_t spinlock;
@@ -2017,6 +2045,75 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
brcmf_fws_unlock(fws);
}
+#ifdef DEBUG
+static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
+ struct brcmf_fws_stats *fwstats = &bus_if->drvr->fws->stats;
+
+ seq_printf(seq,
+ "header_pulls: %u\n"
+ "header_only_pkt: %u\n"
+ "tlv_parse_failed: %u\n"
+ "tlv_invalid_type: %u\n"
+ "mac_update_fails: %u\n"
+ "ps_update_fails: %u\n"
+ "if_update_fails: %u\n"
+ "pkt2bus: %u\n"
+ "generic_error: %u\n"
+ "rollback_success: %u\n"
+ "rollback_failed: %u\n"
+ "delayq_full: %u\n"
+ "supprq_full: %u\n"
+ "txs_indicate: %u\n"
+ "txs_discard: %u\n"
+ "txs_suppr_core: %u\n"
+ "txs_suppr_ps: %u\n"
+ "txs_tossed: %u\n"
+ "txs_host_tossed: %u\n"
+ "bus_flow_block: %u\n"
+ "fws_flow_block: %u\n"
+ "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n"
+ "requested_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n",
+ fwstats->header_pulls,
+ fwstats->header_only_pkt,
+ fwstats->tlv_parse_failed,
+ fwstats->tlv_invalid_type,
+ fwstats->mac_update_failed,
+ fwstats->mac_ps_update_failed,
+ fwstats->if_update_failed,
+ fwstats->pkt2bus,
+ fwstats->generic_error,
+ fwstats->rollback_success,
+ fwstats->rollback_failed,
+ fwstats->delayq_full_error,
+ fwstats->supprq_full_error,
+ fwstats->txs_indicate,
+ fwstats->txs_discard,
+ fwstats->txs_supp_core,
+ fwstats->txs_supp_ps,
+ fwstats->txs_tossed,
+ fwstats->txs_host_tossed,
+ fwstats->bus_flow_block,
+ fwstats->fws_flow_block,
+ fwstats->send_pkts[0], fwstats->send_pkts[1],
+ fwstats->send_pkts[2], fwstats->send_pkts[3],
+ fwstats->send_pkts[4],
+ fwstats->requested_sent[0],
+ fwstats->requested_sent[1],
+ fwstats->requested_sent[2],
+ fwstats->requested_sent[3],
+ fwstats->requested_sent[4]);
+
+ return 0;
+}
+#else
+static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data)
+{
+ return 0;
+}
+#endif
+
int brcmf_fws_init(struct brcmf_pub *drvr)
{
struct brcmf_fws_info *fws;
@@ -2107,7 +2204,8 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
BRCMF_FWS_PSQ_LEN);
/* create debugfs file for statistics */
- brcmf_debugfs_create_fws_stats(drvr, &fws->stats);
+ brcmf_debugfs_add_entry(drvr, "fws_stats",
+ brcmf_debugfs_fws_stats_read);
brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n",
fws->fw_signals ? "enabled" : "disabled", tlv);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
index 3deab7959a0d..6c5e585ccda9 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
@@ -18,6 +18,8 @@
#define _BRCM_SDH_H_
#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include "firmware.h"
#define SDIO_FUNC_0 0
#define SDIO_FUNC_1 1
@@ -182,6 +184,8 @@ struct brcmf_sdio_dev {
uint max_segment_size;
uint txglomsz;
struct sg_table sgtable;
+ char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
+ char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
};
/* sdio core registers */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index b732a99e402c..dc135915470d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -21,6 +21,7 @@
#include <linux/vmalloc.h>
#include <brcmu_utils.h>
+#include <brcm_hw_ids.h>
#include <brcmu_wifi.h>
#include <dhd_bus.h>
#include <dhd_dbg.h>
@@ -913,16 +914,16 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)
static bool brcmf_usb_chip_support(int chipid, int chiprev)
{
switch(chipid) {
- case 43143:
+ case BRCM_CC_43143_CHIP_ID:
return true;
- case 43235:
- case 43236:
- case 43238:
+ case BRCM_CC_43235_CHIP_ID:
+ case BRCM_CC_43236_CHIP_ID:
+ case BRCM_CC_43238_CHIP_ID:
return (chiprev == 3);
- case 43242:
+ case BRCM_CC_43242_CHIP_ID:
return true;
- case 43566:
- case 43569:
+ case BRCM_CC_43566_CHIP_ID:
+ case BRCM_CC_43569_CHIP_ID:
return true;
default:
break;
@@ -1016,16 +1017,16 @@ static int check_file(const u8 *headers)
static const char *brcmf_usb_get_fwname(struct brcmf_usbdev_info *devinfo)
{
switch (devinfo->bus_pub.devid) {
- case 43143:
+ case BRCM_CC_43143_CHIP_ID:
return BRCMF_USB_43143_FW_NAME;
- case 43235:
- case 43236:
- case 43238:
+ case BRCM_CC_43235_CHIP_ID:
+ case BRCM_CC_43236_CHIP_ID:
+ case BRCM_CC_43238_CHIP_ID:
return BRCMF_USB_43236_FW_NAME;
- case 43242:
+ case BRCM_CC_43242_CHIP_ID:
return BRCMF_USB_43242_FW_NAME;
- case 43566:
- case 43569:
+ case BRCM_CC_43566_CHIP_ID:
+ case BRCM_CC_43569_CHIP_ID:
return BRCMF_USB_43569_FW_NAME;
default:
return NULL;
@@ -1366,21 +1367,17 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf)
brcmf_usb_probe_phase2);
}
-#define BRCMF_USB_VENDOR_ID_BROADCOM 0x0a5c
-#define BRCMF_USB_DEVICE_ID_43143 0xbd1e
-#define BRCMF_USB_DEVICE_ID_43236 0xbd17
-#define BRCMF_USB_DEVICE_ID_43242 0xbd1f
-#define BRCMF_USB_DEVICE_ID_43569 0xbd27
-#define BRCMF_USB_DEVICE_ID_BCMFW 0x0bdc
+#define BRCMF_USB_DEVICE(dev_id) \
+ { USB_DEVICE(BRCM_USB_VENDOR_ID_BROADCOM, dev_id) }
static struct usb_device_id brcmf_usb_devid_table[] = {
- { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43143) },
- { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43236) },
- { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43242) },
- { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43569) },
+ BRCMF_USB_DEVICE(BRCM_USB_43143_DEVICE_ID),
+ BRCMF_USB_DEVICE(BRCM_USB_43236_DEVICE_ID),
+ BRCMF_USB_DEVICE(BRCM_USB_43242_DEVICE_ID),
+ BRCMF_USB_DEVICE(BRCM_USB_43569_DEVICE_ID),
/* special entry for device with firmware loaded and running */
- { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_BCMFW) },
- { }
+ BRCMF_USB_DEVICE(BRCM_USB_BCMFW_DEVICE_ID),
+ { /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(usb, brcmf_usb_devid_table);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 9682cf213ec4..48078a321716 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -33,6 +33,7 @@
#include "p2p.h"
#include "btcoex.h"
#include "wl_cfg80211.h"
+#include "feature.h"
#include "fwil.h"
#include "vendor.h"
@@ -102,24 +103,6 @@ static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
return true;
}
-#define CHAN2G(_channel, _freq, _flags) { \
- .band = IEEE80211_BAND_2GHZ, \
- .center_freq = (_freq), \
- .hw_value = (_channel), \
- .flags = (_flags), \
- .max_antenna_gain = 0, \
- .max_power = 30, \
-}
-
-#define CHAN5G(_channel, _flags) { \
- .band = IEEE80211_BAND_5GHZ, \
- .center_freq = 5000 + (5 * (_channel)), \
- .hw_value = (_channel), \
- .flags = (_flags), \
- .max_antenna_gain = 0, \
- .max_power = 30, \
-}
-
#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
#define RATETAB_ENT(_rateid, _flags) \
{ \
@@ -148,58 +131,17 @@ static struct ieee80211_rate __wl_rates[] = {
#define wl_g_rates (__wl_rates + 0)
#define wl_g_rates_size 12
-static struct ieee80211_channel __wl_2ghz_channels[] = {
- CHAN2G(1, 2412, 0),
- CHAN2G(2, 2417, 0),
- CHAN2G(3, 2422, 0),
- CHAN2G(4, 2427, 0),
- CHAN2G(5, 2432, 0),
- CHAN2G(6, 2437, 0),
- CHAN2G(7, 2442, 0),
- CHAN2G(8, 2447, 0),
- CHAN2G(9, 2452, 0),
- CHAN2G(10, 2457, 0),
- CHAN2G(11, 2462, 0),
- CHAN2G(12, 2467, 0),
- CHAN2G(13, 2472, 0),
- CHAN2G(14, 2484, 0),
-};
-
-static struct ieee80211_channel __wl_5ghz_a_channels[] = {
- CHAN5G(34, 0), CHAN5G(36, 0),
- CHAN5G(38, 0), CHAN5G(40, 0),
- CHAN5G(42, 0), CHAN5G(44, 0),
- CHAN5G(46, 0), CHAN5G(48, 0),
- CHAN5G(52, 0), CHAN5G(56, 0),
- CHAN5G(60, 0), CHAN5G(64, 0),
- CHAN5G(100, 0), CHAN5G(104, 0),
- CHAN5G(108, 0), CHAN5G(112, 0),
- CHAN5G(116, 0), CHAN5G(120, 0),
- CHAN5G(124, 0), CHAN5G(128, 0),
- CHAN5G(132, 0), CHAN5G(136, 0),
- CHAN5G(140, 0), CHAN5G(149, 0),
- CHAN5G(153, 0), CHAN5G(157, 0),
- CHAN5G(161, 0), CHAN5G(165, 0),
- CHAN5G(184, 0), CHAN5G(188, 0),
- CHAN5G(192, 0), CHAN5G(196, 0),
- CHAN5G(200, 0), CHAN5G(204, 0),
- CHAN5G(208, 0), CHAN5G(212, 0),
- CHAN5G(216, 0),
-};
-
-static struct ieee80211_supported_band __wl_band_2ghz = {
+/* Band templates duplicated per wiphy. The channel info
+ * is filled in after querying the device.
+ */
+static const struct ieee80211_supported_band __wl_band_2ghz = {
.band = IEEE80211_BAND_2GHZ,
- .channels = __wl_2ghz_channels,
- .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
.bitrates = wl_g_rates,
.n_bitrates = wl_g_rates_size,
- .ht_cap = {IEEE80211_HT_CAP_SUP_WIDTH_20_40, true},
};
-static struct ieee80211_supported_band __wl_band_5ghz_a = {
+static const struct ieee80211_supported_band __wl_band_5ghz_a = {
.band = IEEE80211_BAND_5GHZ,
- .channels = __wl_5ghz_a_channels,
- .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
.bitrates = wl_a_rates,
.n_bitrates = wl_a_rates_size,
};
@@ -592,7 +534,7 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
{
- if ((brcmf_get_chip_info(ifp) >> 4) == 0x4329)
+ if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
brcmf_set_mpc(ifp, mpc);
}
@@ -1619,17 +1561,10 @@ static
enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
enum nl80211_auth_type type)
{
- u32 ci;
- if (type == NL80211_AUTHTYPE_AUTOMATIC) {
- /* shift to ignore chip revision */
- ci = brcmf_get_chip_info(ifp) >> 4;
- switch (ci) {
- case 43236:
- brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
- return NL80211_AUTHTYPE_OPEN_SYSTEM;
- default:
- break;
- }
+ if (type == NL80211_AUTHTYPE_AUTOMATIC &&
+ brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
+ brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
+ type = NL80211_AUTHTYPE_OPEN_SYSTEM;
}
return type;
}
@@ -4284,122 +4219,6 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.tdls_oper = brcmf_cfg80211_tdls_oper,
};
-static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
-{
- /* scheduled scan settings */
- wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
- wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
- wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
- wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
-}
-
-static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
- {
- .max = 2,
- .types = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
- }
-};
-static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
- {
- .max_interfaces = BRCMF_IFACE_MAX_CNT,
- .num_different_channels = 2,
- .n_limits = ARRAY_SIZE(brcmf_iface_limits),
- .limits = brcmf_iface_limits
- }
-};
-
-static const struct ieee80211_txrx_stypes
-brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
- [NL80211_IFTYPE_STATION] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
- },
- [NL80211_IFTYPE_P2P_CLIENT] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
- },
- [NL80211_IFTYPE_P2P_GO] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
- BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
- BIT(IEEE80211_STYPE_DISASSOC >> 4) |
- BIT(IEEE80211_STYPE_AUTH >> 4) |
- BIT(IEEE80211_STYPE_DEAUTH >> 4) |
- BIT(IEEE80211_STYPE_ACTION >> 4)
- },
- [NL80211_IFTYPE_P2P_DEVICE] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
- }
-};
-
-static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
-{
- struct wiphy *wiphy;
- s32 err = 0;
-
- wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
- if (!wiphy) {
- brcmf_err("Could not allocate wiphy device\n");
- return ERR_PTR(-ENOMEM);
- }
- set_wiphy_dev(wiphy, phydev);
- wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
- wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
- wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
- wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO) |
- BIT(NL80211_IFTYPE_P2P_DEVICE);
- wiphy->iface_combinations = brcmf_iface_combos;
- wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
- wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
- wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
- wiphy->cipher_suites = __wl_cipher_suites;
- wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
- wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
- WIPHY_FLAG_OFFCHAN_TX |
- WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
- WIPHY_FLAG_SUPPORTS_TDLS;
- if (!brcmf_roamoff)
- wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
- wiphy->mgmt_stypes = brcmf_txrx_stypes;
- wiphy->max_remain_on_channel_duration = 5000;
- brcmf_wiphy_pno_params(wiphy);
- brcmf_dbg(INFO, "Registering custom regulatory\n");
- wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
- wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
-
- /* vendor commands/events support */
- wiphy->vendor_commands = brcmf_vendor_cmds;
- wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
-
- err = wiphy_register(wiphy);
- if (err < 0) {
- brcmf_err("Could not register wiphy device (%d)\n", err);
- wiphy_free(wiphy);
- return ERR_PTR(err);
- }
- return wiphy;
-}
-
struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
enum nl80211_iftype type,
bool pm_block)
@@ -4943,138 +4762,6 @@ static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
mutex_init(&event->vif_event_lock);
}
-static int brcmf_enable_bw40_2g(struct brcmf_if *ifp)
-{
- struct brcmf_fil_bwcap_le band_bwcap;
- u32 val;
- int err;
-
- /* verify support for bw_cap command */
- val = WLC_BAND_5G;
- err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
-
- if (!err) {
- /* only set 2G bandwidth using bw_cap command */
- band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
- band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
- err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
- sizeof(band_bwcap));
- } else {
- brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
- val = WLC_N_BW_40ALL;
- err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
- }
- return err;
-}
-
-struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
- struct device *busdev)
-{
- struct net_device *ndev = drvr->iflist[0]->ndev;
- struct brcmf_cfg80211_info *cfg;
- struct wiphy *wiphy;
- struct brcmf_cfg80211_vif *vif;
- struct brcmf_if *ifp;
- s32 err = 0;
- s32 io_type;
-
- if (!ndev) {
- brcmf_err("ndev is invalid\n");
- return NULL;
- }
-
- ifp = netdev_priv(ndev);
- wiphy = brcmf_setup_wiphy(busdev);
- if (IS_ERR(wiphy))
- return NULL;
-
- cfg = wiphy_priv(wiphy);
- cfg->wiphy = wiphy;
- cfg->pub = drvr;
- init_vif_event(&cfg->vif_event);
- INIT_LIST_HEAD(&cfg->vif_list);
-
- vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
- if (IS_ERR(vif)) {
- wiphy_free(wiphy);
- return NULL;
- }
-
- vif->ifp = ifp;
- vif->wdev.netdev = ndev;
- ndev->ieee80211_ptr = &vif->wdev;
- SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
-
- err = wl_init_priv(cfg);
- if (err) {
- brcmf_err("Failed to init iwm_priv (%d)\n", err);
- goto cfg80211_attach_out;
- }
- ifp->vif = vif;
-
- err = brcmf_p2p_attach(cfg);
- if (err) {
- brcmf_err("P2P initilisation failed (%d)\n", err);
- goto cfg80211_p2p_attach_out;
- }
- err = brcmf_btcoex_attach(cfg);
- if (err) {
- brcmf_err("BT-coex initialisation failed (%d)\n", err);
- brcmf_p2p_detach(&cfg->p2p);
- goto cfg80211_p2p_attach_out;
- }
-
- /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
- * setup 40MHz in 2GHz band and enable OBSS scanning.
- */
- if (wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap &
- IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
- err = brcmf_enable_bw40_2g(ifp);
- if (!err)
- err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
- BRCMF_OBSS_COEX_AUTO);
- }
- /* clear for now and rely on update later */
- wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.ht_supported = false;
- wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap = 0;
-
- err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
- if (err) {
- brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
- wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
- }
-
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION,
- &io_type);
- if (err) {
- brcmf_err("Failed to get D11 version (%d)\n", err);
- goto cfg80211_p2p_attach_out;
- }
- cfg->d11inf.io_type = (u8)io_type;
- brcmu_d11_attach(&cfg->d11inf);
-
- return cfg;
-
-cfg80211_p2p_attach_out:
- wl_deinit_priv(cfg);
-
-cfg80211_attach_out:
- brcmf_free_vif(vif);
- return NULL;
-}
-
-void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
-{
- if (!cfg)
- return;
-
- WARN_ON(!list_empty(&cfg->vif_list));
- wiphy_unregister(cfg->wiphy);
- brcmf_btcoex_detach(cfg);
- wl_deinit_priv(cfg);
- wiphy_free(cfg->wiphy);
-}
-
static s32
brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
{
@@ -5167,25 +4854,77 @@ dongle_scantime_out:
return err;
}
+/* Filter the list of channels received from firmware counting only
+ * the 20MHz channels. The wiphy band data only needs those which get
+ * flagged to indicate if they can take part in higher bandwidth.
+ */
+static void brcmf_count_20mhz_channels(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_chanspec_list *chlist,
+ u32 chcnt[])
+{
+ u32 total = le32_to_cpu(chlist->count);
+ struct brcmu_chan ch;
+ int i;
+
+ for (i = 0; i <= total; i++) {
+ ch.chspec = (u16)le32_to_cpu(chlist->element[i]);
+ cfg->d11inf.decchspec(&ch);
+
+ /* Firmware gives a ordered list. We skip non-20MHz
+ * channels is 2G. For 5G we can abort upon reaching
+ * a non-20MHz channel in the list.
+ */
+ if (ch.bw != BRCMU_CHAN_BW_20) {
+ if (ch.band == BRCMU_CHAN_BAND_5G)
+ break;
+ else
+ continue;
+ }
+
+ if (ch.band == BRCMU_CHAN_BAND_2G)
+ chcnt[0] += 1;
+ else if (ch.band == BRCMU_CHAN_BAND_5G)
+ chcnt[1] += 1;
+ }
+}
+
+static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
+ struct brcmu_chan *ch)
+{
+ u32 ht40_flag;
-static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,
- u32 bw_cap[])
+ ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
+ if (ch->sb == BRCMU_CHAN_SB_U) {
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ channel->flags &= ~IEEE80211_CHAN_NO_HT40;
+ channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
+ } else {
+ /* It should be one of
+ * IEEE80211_CHAN_NO_HT40 or
+ * IEEE80211_CHAN_NO_HT40PLUS
+ */
+ channel->flags &= ~IEEE80211_CHAN_NO_HT40;
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
+ }
+}
+
+static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
+ u32 bw_cap[])
{
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
- struct ieee80211_channel *band_chan_arr;
+ struct ieee80211_supported_band *band;
+ struct ieee80211_channel *channel;
+ struct wiphy *wiphy;
struct brcmf_chanspec_list *list;
struct brcmu_chan ch;
- s32 err;
+ int err;
u8 *pbuf;
u32 i, j;
u32 total;
- enum ieee80211_band band;
- u32 channel;
- u32 *n_cnt;
+ u32 chaninfo;
+ u32 chcnt[2] = { 0, 0 };
u32 index;
- u32 ht40_flag;
- bool update;
- u32 array_size;
pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
@@ -5198,11 +4937,45 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,
BRCMF_DCMD_MEDLEN);
if (err) {
brcmf_err("get chanspecs error (%d)\n", err);
- goto exit;
+ goto fail_pbuf;
}
- __wl_band_2ghz.n_channels = 0;
- __wl_band_5ghz_a.n_channels = 0;
+ brcmf_count_20mhz_channels(cfg, list, chcnt);
+ wiphy = cfg_to_wiphy(cfg);
+ if (chcnt[0]) {
+ band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
+ GFP_KERNEL);
+ if (band == NULL) {
+ err = -ENOMEM;
+ goto fail_pbuf;
+ }
+ band->channels = kcalloc(chcnt[0], sizeof(*channel),
+ GFP_KERNEL);
+ if (band->channels == NULL) {
+ kfree(band);
+ err = -ENOMEM;
+ goto fail_pbuf;
+ }
+ band->n_channels = 0;
+ wiphy->bands[IEEE80211_BAND_2GHZ] = band;
+ }
+ if (chcnt[1]) {
+ band = kmemdup(&__wl_band_5ghz_a, sizeof(__wl_band_5ghz_a),
+ GFP_KERNEL);
+ if (band == NULL) {
+ err = -ENOMEM;
+ goto fail_band2g;
+ }
+ band->channels = kcalloc(chcnt[1], sizeof(*channel),
+ GFP_KERNEL);
+ if (band->channels == NULL) {
+ kfree(band);
+ err = -ENOMEM;
+ goto fail_band2g;
+ }
+ band->n_channels = 0;
+ wiphy->bands[IEEE80211_BAND_5GHZ] = band;
+ }
total = le32_to_cpu(list->count);
for (i = 0; i < total; i++) {
@@ -5210,100 +4983,151 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,
cfg->d11inf.decchspec(&ch);
if (ch.band == BRCMU_CHAN_BAND_2G) {
- band_chan_arr = __wl_2ghz_channels;
- array_size = ARRAY_SIZE(__wl_2ghz_channels);
- n_cnt = &__wl_band_2ghz.n_channels;
- band = IEEE80211_BAND_2GHZ;
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
} else if (ch.band == BRCMU_CHAN_BAND_5G) {
- band_chan_arr = __wl_5ghz_a_channels;
- array_size = ARRAY_SIZE(__wl_5ghz_a_channels);
- n_cnt = &__wl_band_5ghz_a.n_channels;
- band = IEEE80211_BAND_5GHZ;
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
} else {
brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
continue;
}
- if (!(bw_cap[band] & WLC_BW_40MHZ_BIT) &&
+ if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
ch.bw == BRCMU_CHAN_BW_40)
continue;
- if (!(bw_cap[band] & WLC_BW_80MHZ_BIT) &&
+ if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
ch.bw == BRCMU_CHAN_BW_80)
continue;
- update = false;
- for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
- if (band_chan_arr[j].hw_value == ch.chnum) {
- update = true;
+
+ channel = band->channels;
+ index = band->n_channels;
+ for (j = 0; j < band->n_channels; j++) {
+ if (channel[j].hw_value == ch.chnum) {
+ index = j;
break;
}
}
- if (update)
- index = j;
- else
- index = *n_cnt;
- if (index < array_size) {
- band_chan_arr[index].center_freq =
- ieee80211_channel_to_frequency(ch.chnum, band);
- band_chan_arr[index].hw_value = ch.chnum;
-
- /* assuming the chanspecs order is HT20,
- * HT40 upper, HT40 lower, and VHT80.
+ channel[index].center_freq =
+ ieee80211_channel_to_frequency(ch.chnum, band->band);
+ channel[index].hw_value = ch.chnum;
+
+ /* assuming the chanspecs order is HT20,
+ * HT40 upper, HT40 lower, and VHT80.
+ */
+ if (ch.bw == BRCMU_CHAN_BW_80) {
+ channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
+ } else if (ch.bw == BRCMU_CHAN_BW_40) {
+ brcmf_update_bw40_channel_flag(&channel[index], &ch);
+ } else {
+ /* disable other bandwidths for now as mentioned
+ * order assure they are enabled for subsequent
+ * chanspecs.
*/
- if (ch.bw == BRCMU_CHAN_BW_80) {
- band_chan_arr[index].flags &=
- ~IEEE80211_CHAN_NO_80MHZ;
- } else if (ch.bw == BRCMU_CHAN_BW_40) {
- ht40_flag = band_chan_arr[index].flags &
- IEEE80211_CHAN_NO_HT40;
- if (ch.sb == BRCMU_CHAN_SB_U) {
- if (ht40_flag == IEEE80211_CHAN_NO_HT40)
- band_chan_arr[index].flags &=
- ~IEEE80211_CHAN_NO_HT40;
- band_chan_arr[index].flags |=
- IEEE80211_CHAN_NO_HT40PLUS;
- } else {
- /* It should be one of
- * IEEE80211_CHAN_NO_HT40 or
- * IEEE80211_CHAN_NO_HT40PLUS
- */
- band_chan_arr[index].flags &=
- ~IEEE80211_CHAN_NO_HT40;
- if (ht40_flag == IEEE80211_CHAN_NO_HT40)
- band_chan_arr[index].flags |=
- IEEE80211_CHAN_NO_HT40MINUS;
- }
- } else {
- /* disable other bandwidths for now as mentioned
- * order assure they are enabled for subsequent
- * chanspecs.
- */
- band_chan_arr[index].flags =
- IEEE80211_CHAN_NO_HT40 |
- IEEE80211_CHAN_NO_80MHZ;
- ch.bw = BRCMU_CHAN_BW_20;
- cfg->d11inf.encchspec(&ch);
- channel = ch.chspec;
- err = brcmf_fil_bsscfg_int_get(ifp,
- "per_chan_info",
- &channel);
- if (!err) {
- if (channel & WL_CHAN_RADAR)
- band_chan_arr[index].flags |=
- (IEEE80211_CHAN_RADAR |
- IEEE80211_CHAN_NO_IR);
- if (channel & WL_CHAN_PASSIVE)
- band_chan_arr[index].flags |=
- IEEE80211_CHAN_NO_IR;
- }
+ channel[index].flags = IEEE80211_CHAN_NO_HT40 |
+ IEEE80211_CHAN_NO_80MHZ;
+ ch.bw = BRCMU_CHAN_BW_20;
+ cfg->d11inf.encchspec(&ch);
+ chaninfo = ch.chspec;
+ err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
+ &chaninfo);
+ if (!err) {
+ if (chaninfo & WL_CHAN_RADAR)
+ channel[index].flags |=
+ (IEEE80211_CHAN_RADAR |
+ IEEE80211_CHAN_NO_IR);
+ if (chaninfo & WL_CHAN_PASSIVE)
+ channel[index].flags |=
+ IEEE80211_CHAN_NO_IR;
}
- if (!update)
- (*n_cnt)++;
}
+ if (index == band->n_channels)
+ band->n_channels++;
}
-exit:
+ kfree(pbuf);
+ return 0;
+
+fail_band2g:
+ kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
+ kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
+ wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
+fail_pbuf:
kfree(pbuf);
return err;
}
+static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+ struct ieee80211_supported_band *band;
+ struct brcmf_fil_bwcap_le band_bwcap;
+ struct brcmf_chanspec_list *list;
+ u8 *pbuf;
+ u32 val;
+ int err;
+ struct brcmu_chan ch;
+ u32 num_chan;
+ int i, j;
+
+ /* verify support for bw_cap command */
+ val = WLC_BAND_5G;
+ err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
+
+ if (!err) {
+ /* only set 2G bandwidth using bw_cap command */
+ band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
+ band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
+ err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
+ sizeof(band_bwcap));
+ } else {
+ brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
+ val = WLC_N_BW_40ALL;
+ err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
+ }
+
+ if (!err) {
+ /* update channel info in 2G band */
+ pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
+
+ if (pbuf == NULL)
+ return -ENOMEM;
+
+ ch.band = BRCMU_CHAN_BAND_2G;
+ ch.bw = BRCMU_CHAN_BW_40;
+ ch.chnum = 0;
+ cfg->d11inf.encchspec(&ch);
+
+ /* pass encoded chanspec in query */
+ *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
+
+ err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
+ BRCMF_DCMD_MEDLEN);
+ if (err) {
+ brcmf_err("get chanspecs error (%d)\n", err);
+ kfree(pbuf);
+ return err;
+ }
+
+ band = cfg_to_wiphy(cfg)->bands[IEEE80211_BAND_2GHZ];
+ list = (struct brcmf_chanspec_list *)pbuf;
+ num_chan = le32_to_cpu(list->count);
+ for (i = 0; i < num_chan; i++) {
+ ch.chspec = (u16)le32_to_cpu(list->element[i]);
+ cfg->d11inf.decchspec(&ch);
+ if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
+ continue;
+ if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
+ continue;
+ for (j = 0; j < band->n_channels; j++) {
+ if (band->channels[j].hw_value == ch.chnum)
+ break;
+ }
+ if (WARN_ON(j == band->n_channels))
+ continue;
+
+ brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
+ }
+ }
+ return err;
+}
+
static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
{
u32 band, mimo_bwcap;
@@ -5394,44 +5218,19 @@ static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
}
-static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
+static int brcmf_setup_wiphybands(struct wiphy *wiphy)
{
+ struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
- struct wiphy *wiphy;
- s32 phy_list;
- u32 band_list[3];
u32 nmode = 0;
u32 vhtmode = 0;
- u32 bw_cap[2] = { 0, 0 };
+ u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
u32 rxchain;
u32 nchain;
- s8 phy;
- s32 err;
- u32 nband;
+ int err;
s32 i;
- struct ieee80211_supported_band *bands[2] = { NULL, NULL };
struct ieee80211_supported_band *band;
- err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
- &phy_list, sizeof(phy_list));
- if (err) {
- brcmf_err("BRCMF_C_GET_PHYLIST error (%d)\n", err);
- return err;
- }
-
- phy = ((char *)&phy_list)[0];
- brcmf_dbg(INFO, "BRCMF_C_GET_PHYLIST reported: %c phy\n", phy);
-
-
- err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST,
- &band_list, sizeof(band_list));
- if (err) {
- brcmf_err("BRCMF_C_GET_BANDLIST error (%d)\n", err);
- return err;
- }
- brcmf_dbg(INFO, "BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n",
- band_list[0], band_list[1], band_list[2]);
-
(void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
if (err) {
@@ -5453,44 +5252,129 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
}
brcmf_dbg(INFO, "nchain=%d\n", nchain);
- err = brcmf_construct_reginfo(cfg, bw_cap);
+ err = brcmf_construct_chaninfo(cfg, bw_cap);
if (err) {
- brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
+ brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
return err;
}
- nband = band_list[0];
-
- for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) {
- band = NULL;
- if ((band_list[i] == WLC_BAND_5G) &&
- (__wl_band_5ghz_a.n_channels > 0))
- band = &__wl_band_5ghz_a;
- else if ((band_list[i] == WLC_BAND_2G) &&
- (__wl_band_2ghz.n_channels > 0))
- band = &__wl_band_2ghz;
- else
+ wiphy = cfg_to_wiphy(cfg);
+ for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
+ band = wiphy->bands[i];
+ if (band == NULL)
continue;
if (nmode)
brcmf_update_ht_cap(band, bw_cap, nchain);
if (vhtmode)
brcmf_update_vht_cap(band, bw_cap, nchain);
- bands[band->band] = band;
}
- wiphy = cfg_to_wiphy(cfg);
- wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
- wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
- wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
-
- return err;
+ return 0;
}
+static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP)
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO)
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
+ }
+};
+static struct ieee80211_iface_combination brcmf_iface_combos[] = {
+ {
+ .max_interfaces = BRCMF_IFACE_MAX_CNT,
+ .num_different_channels = 1,
+ .n_limits = ARRAY_SIZE(brcmf_iface_limits),
+ .limits = brcmf_iface_limits
+ }
+};
+
+static const struct ieee80211_txrx_stypes
+brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_STATION] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_P2P_DEVICE] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ }
+};
-static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
+static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
{
- return brcmf_update_wiphybands(cfg);
+ /* scheduled scan settings */
+ wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
+ wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
+ wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
+ wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+}
+
+static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
+{
+ struct ieee80211_iface_combination ifc_combo;
+ wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
+ wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
+ wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_DEVICE);
+ /* need VSDB firmware feature for concurrent channels */
+ ifc_combo = brcmf_iface_combos[0];
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
+ ifc_combo.num_different_channels = 2;
+ wiphy->iface_combinations = kmemdup(&ifc_combo,
+ sizeof(ifc_combo),
+ GFP_KERNEL);
+ wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wiphy->cipher_suites = __wl_cipher_suites;
+ wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
+ wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
+ WIPHY_FLAG_OFFCHAN_TX |
+ WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+ WIPHY_FLAG_SUPPORTS_TDLS;
+ if (!brcmf_roamoff)
+ wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+ wiphy->mgmt_stypes = brcmf_txrx_stypes;
+ wiphy->max_remain_on_channel_duration = 5000;
+ brcmf_wiphy_pno_params(wiphy);
+
+ /* vendor commands/events support */
+ wiphy->vendor_commands = brcmf_vendor_cmds;
+ wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
+
+ return brcmf_setup_wiphybands(wiphy);
}
static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
@@ -5528,9 +5412,6 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
NULL, NULL);
if (err)
goto default_conf_out;
- err = brcmf_dongle_probecap(cfg);
- if (err)
- goto default_conf_out;
brcmf_configure_arp_offload(ifp, true);
@@ -5658,3 +5539,150 @@ int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
vif_event_equals(event, action), timeout);
}
+static void brcmf_free_wiphy(struct wiphy *wiphy)
+{
+ kfree(wiphy->iface_combinations);
+ if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
+ kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
+ kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
+ }
+ if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
+ kfree(wiphy->bands[IEEE80211_BAND_5GHZ]->channels);
+ kfree(wiphy->bands[IEEE80211_BAND_5GHZ]);
+ }
+ wiphy_free(wiphy);
+}
+
+struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
+ struct device *busdev)
+{
+ struct net_device *ndev = drvr->iflist[0]->ndev;
+ struct brcmf_cfg80211_info *cfg;
+ struct wiphy *wiphy;
+ struct brcmf_cfg80211_vif *vif;
+ struct brcmf_if *ifp;
+ s32 err = 0;
+ s32 io_type;
+ u16 *cap = NULL;
+
+ if (!ndev) {
+ brcmf_err("ndev is invalid\n");
+ return NULL;
+ }
+
+ ifp = netdev_priv(ndev);
+ wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
+ if (!wiphy) {
+ brcmf_err("Could not allocate wiphy device\n");
+ return NULL;
+ }
+ set_wiphy_dev(wiphy, busdev);
+
+ cfg = wiphy_priv(wiphy);
+ cfg->wiphy = wiphy;
+ cfg->pub = drvr;
+ init_vif_event(&cfg->vif_event);
+ INIT_LIST_HEAD(&cfg->vif_list);
+
+ vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
+ if (IS_ERR(vif))
+ goto wiphy_out;
+
+ vif->ifp = ifp;
+ vif->wdev.netdev = ndev;
+ ndev->ieee80211_ptr = &vif->wdev;
+ SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
+
+ err = wl_init_priv(cfg);
+ if (err) {
+ brcmf_err("Failed to init iwm_priv (%d)\n", err);
+ brcmf_free_vif(vif);
+ goto wiphy_out;
+ }
+ ifp->vif = vif;
+
+ /* determine d11 io type before wiphy setup */
+ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
+ if (err) {
+ brcmf_err("Failed to get D11 version (%d)\n", err);
+ goto priv_out;
+ }
+ cfg->d11inf.io_type = (u8)io_type;
+ brcmu_d11_attach(&cfg->d11inf);
+
+ err = brcmf_setup_wiphy(wiphy, ifp);
+ if (err < 0)
+ goto priv_out;
+
+ brcmf_dbg(INFO, "Registering custom regulatory\n");
+ wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
+ wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
+
+ /* firmware defaults to 40MHz disabled in 2G band. We signal
+ * cfg80211 here that we do and have it decide we can enable
+ * it. But first check if device does support 2G operation.
+ */
+ if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
+ cap = &wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap;
+ *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ }
+ err = wiphy_register(wiphy);
+ if (err < 0) {
+ brcmf_err("Could not register wiphy device (%d)\n", err);
+ goto priv_out;
+ }
+
+ /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
+ * setup 40MHz in 2GHz band and enable OBSS scanning.
+ */
+ if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
+ err = brcmf_enable_bw40_2g(cfg);
+ if (!err)
+ err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
+ BRCMF_OBSS_COEX_AUTO);
+ else
+ *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ }
+
+ err = brcmf_p2p_attach(cfg);
+ if (err) {
+ brcmf_err("P2P initilisation failed (%d)\n", err);
+ goto wiphy_unreg_out;
+ }
+ err = brcmf_btcoex_attach(cfg);
+ if (err) {
+ brcmf_err("BT-coex initialisation failed (%d)\n", err);
+ brcmf_p2p_detach(&cfg->p2p);
+ goto wiphy_unreg_out;
+ }
+
+ err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
+ if (err) {
+ brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
+ wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
+ }
+
+ return cfg;
+
+wiphy_unreg_out:
+ wiphy_unregister(cfg->wiphy);
+priv_out:
+ wl_deinit_priv(cfg);
+ brcmf_free_vif(vif);
+wiphy_out:
+ brcmf_free_wiphy(wiphy);
+ return NULL;
+}
+
+void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
+{
+ if (!cfg)
+ return;
+
+ WARN_ON(!list_empty(&cfg->vif_list));
+ wiphy_unregister(cfg->wiphy);
+ brcmf_btcoex_detach(cfg);
+ brcmf_p2p_detach(&cfg->p2p);
+ wl_deinit_priv(cfg);
+ brcmf_free_wiphy(cfg->wiphy);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index af8ba64ace39..1b474828d5b8 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -4707,41 +4707,6 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
return err;
}
-static void brcms_c_attach_antgain_init(struct brcms_c_info *wlc)
-{
- uint unit;
- unit = wlc->pub->unit;
-
- if ((wlc->band->antgain == -1) && (wlc->pub->sromrev == 1)) {
- /* default antenna gain for srom rev 1 is 2 dBm (8 qdbm) */
- wlc->band->antgain = 8;
- } else if (wlc->band->antgain == -1) {
- wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
- " srom, using 2dB\n", unit, __func__);
- wlc->band->antgain = 8;
- } else {
- s8 gain, fract;
- /* Older sroms specified gain in whole dbm only. In order
- * be able to specify qdbm granularity and remain backward
- * compatible the whole dbms are now encoded in only
- * low 6 bits and remaining qdbms are encoded in the hi 2 bits.
- * 6 bit signed number ranges from -32 - 31.
- *
- * Examples:
- * 0x1 = 1 db,
- * 0xc1 = 1.75 db (1 + 3 quarters),
- * 0x3f = -1 (-1 + 0 quarters),
- * 0x7f = -.75 (-1 + 1 quarters) = -3 qdbm.
- * 0xbf = -.50 (-1 + 2 quarters) = -2 qdbm.
- */
- gain = wlc->band->antgain & 0x3f;
- gain <<= 2; /* Sign extend */
- gain >>= 2;
- fract = (wlc->band->antgain & 0xc0) >> 6;
- wlc->band->antgain = 4 * gain + fract;
- }
-}
-
static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
{
int aa;
@@ -4780,8 +4745,6 @@ static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
else
wlc->band->antgain = sprom->antenna_gain.a0;
- brcms_c_attach_antgain_init(wlc);
-
return true;
}
diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
index d816270db3be..64d1a7ba040c 100644
--- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
+++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
@@ -17,32 +17,56 @@
#ifndef _BRCM_HW_IDS_H_
#define _BRCM_HW_IDS_H_
-#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */
+#include <linux/pci_ids.h>
+#include <linux/mmc/sdio_ids.h>
+
+#define BRCM_USB_VENDOR_ID_BROADCOM 0x0a5c
+#define BRCM_PCIE_VENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM
+#define BRCM_SDIO_VENDOR_ID_BROADCOM SDIO_VENDOR_ID_BROADCOM
+
+/* Chipcommon Core Chip IDs */
+#define BRCM_CC_43143_CHIP_ID 43143
+#define BRCM_CC_43235_CHIP_ID 43235
+#define BRCM_CC_43236_CHIP_ID 43236
+#define BRCM_CC_43238_CHIP_ID 43238
+#define BRCM_CC_43241_CHIP_ID 0x4324
+#define BRCM_CC_43242_CHIP_ID 43242
+#define BRCM_CC_4329_CHIP_ID 0x4329
+#define BRCM_CC_4330_CHIP_ID 0x4330
+#define BRCM_CC_4334_CHIP_ID 0x4334
+#define BRCM_CC_43362_CHIP_ID 43362
+#define BRCM_CC_4335_CHIP_ID 0x4335
+#define BRCM_CC_4339_CHIP_ID 0x4339
+#define BRCM_CC_4354_CHIP_ID 0x4354
+#define BRCM_CC_43566_CHIP_ID 43566
+#define BRCM_CC_43569_CHIP_ID 43569
+
+/* SDIO Device IDs */
+#define BRCM_SDIO_43143_DEVICE_ID BRCM_CC_43143_CHIP_ID
+#define BRCM_SDIO_43241_DEVICE_ID BRCM_CC_43241_CHIP_ID
+#define BRCM_SDIO_4329_DEVICE_ID BRCM_CC_4329_CHIP_ID
+#define BRCM_SDIO_4330_DEVICE_ID BRCM_CC_4330_CHIP_ID
+#define BRCM_SDIO_4334_DEVICE_ID BRCM_CC_4334_CHIP_ID
+#define BRCM_SDIO_43362_DEVICE_ID BRCM_CC_43362_CHIP_ID
+#define BRCM_SDIO_4335_4339_DEVICE_ID BRCM_CC_4335_CHIP_ID
+#define BRCM_SDIO_4354_DEVICE_ID BRCM_CC_4354_CHIP_ID
+/* USB Device IDs */
+#define BRCM_USB_43143_DEVICE_ID 0xbd1e
+#define BRCM_USB_43236_DEVICE_ID 0xbd17
+#define BRCM_USB_43242_DEVICE_ID 0xbd1f
+#define BRCM_USB_43569_DEVICE_ID 0xbd27
+#define BRCM_USB_BCMFW_DEVICE_ID 0x0bdc
+
+/* brcmsmac IDs */
+#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */
#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */
#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db */
-
#define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */
-
#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */
#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */
-/* Chipcommon Core Chip IDs */
#define BCM4313_CHIP_ID 0x4313
-#define BCM43143_CHIP_ID 43143
#define BCM43224_CHIP_ID 43224
-#define BCM43225_CHIP_ID 43225
-#define BCM43235_CHIP_ID 43235
-#define BCM43236_CHIP_ID 43236
-#define BCM43238_CHIP_ID 43238
-#define BCM43241_CHIP_ID 0x4324
-#define BCM4329_CHIP_ID 0x4329
-#define BCM4330_CHIP_ID 0x4330
-#define BCM4331_CHIP_ID 0x4331
-#define BCM4334_CHIP_ID 0x4334
-#define BCM4335_CHIP_ID 0x4335
-#define BCM43362_CHIP_ID 43362
-#define BCM4339_CHIP_ID 0x4339
-#define BCM4354_CHIP_ID 0x4354
#endif /* _BRCM_HW_IDS_H_ */
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 7fd50428b934..6451d2b6abcf 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -20,16 +20,17 @@ config IWLWIFI
Intel 2000 Series Wi-Fi Adapters
Intel 7260 Wi-Fi Adapter
Intel 3160 Wi-Fi Adapter
+ Intel 7265 Wi-Fi Adapter
This driver uses the kernel's mac80211 subsystem.
- In order to use this driver, you will need a microcode (uCode)
+ In order to use this driver, you will need a firmware
image for it. You can obtain the microcode from:
- <http://intellinuxwireless.org/>.
+ <http://wireless.kernel.org/en/users/Drivers/iwlwifi>.
- The microcode is typically installed in /lib/firmware. You can
+ The firmware is typically installed in /lib/firmware. You can
look in the hotplug script /etc/hotplug/firmware.agent to
determine which directory FIRMWARE_DIR is set to when the script
runs.
@@ -39,9 +40,10 @@ config IWLWIFI
say M here and read <file:Documentation/kbuild/modules.txt>. The
module will be called iwlwifi.
+if IWLWIFI
+
config IWLWIFI_LEDS
bool
- depends on IWLWIFI
depends on LEDS_CLASS=y || LEDS_CLASS=IWLWIFI
select LEDS_TRIGGERS
select MAC80211_LEDS
@@ -49,7 +51,7 @@ config IWLWIFI_LEDS
config IWLDVM
tristate "Intel Wireless WiFi DVM Firmware support"
- depends on IWLWIFI
+ depends on m
default IWLWIFI
help
This is the driver that supports the DVM firmware which is
@@ -58,7 +60,7 @@ config IWLDVM
config IWLMVM
tristate "Intel Wireless WiFi MVM Firmware support"
- depends on IWLWIFI
+ depends on m
help
This is the driver that supports the MVM firmware which is
currently only available for 7260 and 3160 devices.
@@ -70,7 +72,7 @@ config IWLWIFI_OPMODE_MODULAR
default y if IWLMVM=m
comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM"
- depends on IWLWIFI && IWLDVM=n && IWLMVM=n
+ depends on IWLDVM=n && IWLMVM=n
config IWLWIFI_BCAST_FILTERING
bool "Enable broadcast filtering"
@@ -86,11 +88,9 @@ config IWLWIFI_BCAST_FILTERING
expect incoming broadcasts for their normal operations.
menu "Debugging Options"
- depends on IWLWIFI
config IWLWIFI_DEBUG
bool "Enable full debugging output in the iwlwifi driver"
- depends on IWLWIFI
---help---
This option will enable debug tracing output for the iwlwifi drivers
@@ -115,7 +115,7 @@ config IWLWIFI_DEBUG
config IWLWIFI_DEBUGFS
bool "iwlwifi debugfs support"
- depends on IWLWIFI && MAC80211_DEBUGFS
+ depends on MAC80211_DEBUGFS
---help---
Enable creation of debugfs files for the iwlwifi drivers. This
is a low-impact option that allows getting insight into the
@@ -123,13 +123,12 @@ config IWLWIFI_DEBUGFS
config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
bool "Experimental uCode support"
- depends on IWLWIFI && IWLWIFI_DEBUG
+ depends on IWLWIFI_DEBUG
---help---
Enable use of experimental ucode for testing and debugging.
config IWLWIFI_DEVICE_TRACING
bool "iwlwifi device access tracing"
- depends on IWLWIFI
depends on EVENT_TRACING
help
Say Y here to trace all commands, including TX frames and IO
@@ -145,3 +144,5 @@ config IWLWIFI_DEVICE_TRACING
If unsure, say Y so we can help you better when problems
occur.
endmenu
+
+endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c
index 51486cc9d943..44b19e015102 100644
--- a/drivers/net/wireless/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-8000.c
@@ -85,6 +85,9 @@
#define NVM_HW_SECTION_NUM_FAMILY_8000 10
#define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin"
+/* Max SDIO RX aggregation size of the ADDBA request/response */
+#define MAX_RX_AGG_SIZE_8260_SDIO 28
+
static const struct iwl_base_params iwl8000_base_params = {
.eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000,
.num_of_queues = IWLAGN_NUM_QUEUES,
@@ -129,6 +132,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
.nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
.default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000,
+ .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
};
MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 034c2fc4b69f..8da596db9abe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -240,6 +240,7 @@ struct iwl_pwr_tx_backoff {
* @d0i3: device uses d0i3 instead of d3
* @nvm_hw_section_num: the ID of the HW NVM section
* @pwr_tx_backoffs: translation table between power limits and backoffs
+ * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response
*
* We enable the driver to be backward compatible wrt. hardware features.
* API differences in uCode shouldn't be handled here but through TLVs
@@ -276,6 +277,7 @@ struct iwl_cfg {
const struct iwl_pwr_tx_backoff *pwr_tx_backoffs;
bool no_power_up_nic_in_init;
const char *default_nvm_file;
+ unsigned int max_rx_agg_size;
};
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index c39a0b899e83..de5994a776c7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -70,21 +70,24 @@
/**
* enum iwl_fw_error_dump_type - types of data in the dump file
* @IWL_FW_ERROR_DUMP_SRAM:
- * @IWL_FW_ERROR_DUMP_REG:
+ * @IWL_FW_ERROR_DUMP_CSR: Control Status Registers - from offset 0
* @IWL_FW_ERROR_DUMP_RXF:
* @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as
* &struct iwl_fw_error_dump_txcmd packets
* @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info
* info on the device / firmware.
* @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor
+ * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several
+ * sections like this in a single file.
*/
enum iwl_fw_error_dump_type {
IWL_FW_ERROR_DUMP_SRAM = 0,
- IWL_FW_ERROR_DUMP_REG = 1,
+ IWL_FW_ERROR_DUMP_CSR = 1,
IWL_FW_ERROR_DUMP_RXF = 2,
IWL_FW_ERROR_DUMP_TXCMD = 3,
IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4,
IWL_FW_ERROR_DUMP_FW_MONITOR = 5,
+ IWL_FW_ERROR_DUMP_PRPH = 6,
IWL_FW_ERROR_DUMP_MAX,
};
@@ -163,6 +166,16 @@ struct iwl_fw_error_dump_fw_mon {
} __packed;
/**
+ * struct iwl_fw_error_dump_prph - periphery registers data
+ * @prph_start: address of the first register in this chunk
+ * @data: the content of the registers
+ */
+struct iwl_fw_error_dump_prph {
+ __le32 prph_start;
+ __le32 data[];
+};
+
+/**
* iwl_fw_error_next_data - advance fw error dump data pointer
* @data: previous data block
* Returns: next data block
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h
index f2d39cb011fc..71507cf490e6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-modparams.h
+++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h
@@ -99,7 +99,7 @@ enum iwl_disable_11n {
* @wd_disable: disable stuck queue check, default = 1
* @bt_coex_active: enable bt coex, default = true
* @led_mode: system default, default = 0
- * @power_save: disable power save, default = false
+ * @power_save: enable power save, default = false
* @power_level: power level, default = 1
* @debug_level: levels are IWL_DL_*
* @ant_coupling: antenna coupling in dB, default = 0
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 34d49e171fb4..656371a668da 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -394,6 +394,11 @@ struct iwl_trans_config {
const char *const *command_names;
};
+struct iwl_trans_dump_data {
+ u32 len;
+ u8 data[];
+};
+
struct iwl_trans;
/**
@@ -461,10 +466,8 @@ struct iwl_trans;
* @unref: release a reference previously taken with @ref. Note that
* initially the reference count is 1, making an initial @unref
* necessary to allow low power states.
- * @dump_data: fill a data dump with debug data, maybe containing last
- * TX'ed commands and similar. When called with a NULL buffer and
- * zero buffer length, provide only the (estimated) required buffer
- * length. Return the used buffer length.
+ * @dump_data: return a vmalloc'ed buffer with debug data, maybe containing last
+ * TX'ed commands and similar. The buffer will be vfree'd by the caller.
* Note that the transport must fill in the proper file headers.
*/
struct iwl_trans_ops {
@@ -518,7 +521,7 @@ struct iwl_trans_ops {
void (*unref)(struct iwl_trans *trans);
#ifdef CONFIG_IWLWIFI_DEBUGFS
- u32 (*dump_data)(struct iwl_trans *trans, void *buf, u32 buflen);
+ struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans);
#endif
};
@@ -685,12 +688,12 @@ static inline void iwl_trans_unref(struct iwl_trans *trans)
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
-static inline u32 iwl_trans_dump_data(struct iwl_trans *trans,
- void *buf, u32 buflen)
+static inline struct iwl_trans_dump_data *
+iwl_trans_dump_data(struct iwl_trans *trans)
{
if (!trans->ops->dump_data)
- return 0;
- return trans->ops->dump_data(trans, buf, buflen);
+ return NULL;
+ return trans->ops->dump_data(trans);
}
#endif
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c
index 8110fe00bf55..2291bbcaaeab 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex.c
@@ -72,16 +72,56 @@
#define BT_ANTENNA_COUPLING_THRESHOLD (30)
-const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = {
- [BT_KILL_MSK_DEFAULT] = 0xffff0000,
- [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff,
- [BT_KILL_MSK_REDUCED_TXPOW] = 0,
+const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = {
+ [BT_KILL_MSK_DEFAULT] = 0xfffffc00,
+ [BT_KILL_MSK_NEVER] = 0xffffffff,
+ [BT_KILL_MSK_ALWAYS] = 0,
};
-const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = {
- [BT_KILL_MSK_DEFAULT] = 0xffff0000,
- [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff,
- [BT_KILL_MSK_REDUCED_TXPOW] = 0,
+const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
+ {
+ BT_KILL_MSK_ALWAYS,
+ BT_KILL_MSK_ALWAYS,
+ BT_KILL_MSK_ALWAYS,
+ },
+ {
+ BT_KILL_MSK_NEVER,
+ BT_KILL_MSK_NEVER,
+ BT_KILL_MSK_NEVER,
+ },
+ {
+ BT_KILL_MSK_NEVER,
+ BT_KILL_MSK_NEVER,
+ BT_KILL_MSK_NEVER,
+ },
+ {
+ BT_KILL_MSK_DEFAULT,
+ BT_KILL_MSK_NEVER,
+ BT_KILL_MSK_DEFAULT,
+ },
+};
+
+const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
+ {
+ BT_KILL_MSK_ALWAYS,
+ BT_KILL_MSK_ALWAYS,
+ BT_KILL_MSK_ALWAYS,
+ },
+ {
+ BT_KILL_MSK_ALWAYS,
+ BT_KILL_MSK_ALWAYS,
+ BT_KILL_MSK_ALWAYS,
+ },
+ {
+ BT_KILL_MSK_ALWAYS,
+ BT_KILL_MSK_ALWAYS,
+ BT_KILL_MSK_ALWAYS,
+ },
+ {
+ BT_KILL_MSK_DEFAULT,
+ BT_KILL_MSK_ALWAYS,
+ BT_KILL_MSK_DEFAULT,
+ },
};
static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = {
@@ -611,54 +651,43 @@ send_cmd:
return ret;
}
-static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm,
- bool reduced_tx_power)
+static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm)
{
- enum iwl_bt_kill_msk bt_kill_msk;
- struct iwl_bt_coex_sw_boost_update_cmd cmd = {};
struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
+ u32 primary_lut = le32_to_cpu(notif->primary_ch_lut);
+ u32 secondary_lut = le32_to_cpu(notif->secondary_ch_lut);
+ u32 ag = le32_to_cpu(notif->bt_activity_grading);
+ struct iwl_bt_coex_sw_boost_update_cmd cmd = {};
+ u8 ack_kill_msk[NUM_PHY_CTX] = {};
+ u8 cts_kill_msk[NUM_PHY_CTX] = {};
+ int i;
lockdep_assert_held(&mvm->mutex);
- if (reduced_tx_power) {
- /* Reduced Tx power has precedence on the type of the profile */
- bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW;
- } else {
- /* Low latency BT profile is active: give higher prio to BT */
- if (BT_MBOX_MSG(notif, 3, SCO_STATE) ||
- BT_MBOX_MSG(notif, 3, A2DP_STATE) ||
- BT_MBOX_MSG(notif, 3, SNIFF_STATE))
- bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP;
- else
- bt_kill_msk = BT_KILL_MSK_DEFAULT;
- }
+ ack_kill_msk[0] = iwl_bt_ack_kill_msk[ag][primary_lut];
+ cts_kill_msk[0] = iwl_bt_cts_kill_msk[ag][primary_lut];
- IWL_DEBUG_COEX(mvm,
- "Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n",
- bt_kill_msk,
- BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in",
- BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in",
- BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in");
+ ack_kill_msk[1] = iwl_bt_ack_kill_msk[ag][secondary_lut];
+ cts_kill_msk[1] = iwl_bt_cts_kill_msk[ag][secondary_lut];
/* Don't send HCMD if there is no update */
- if (bt_kill_msk == mvm->bt_kill_msk)
+ if (!memcmp(ack_kill_msk, mvm->bt_ack_kill_msk, sizeof(ack_kill_msk)) ||
+ !memcmp(cts_kill_msk, mvm->bt_cts_kill_msk, sizeof(cts_kill_msk)))
return 0;
- mvm->bt_kill_msk = bt_kill_msk;
+ memcpy(mvm->bt_ack_kill_msk, ack_kill_msk,
+ sizeof(mvm->bt_ack_kill_msk));
+ memcpy(mvm->bt_cts_kill_msk, cts_kill_msk,
+ sizeof(mvm->bt_cts_kill_msk));
- cmd.boost_values[0].kill_ack_msk =
- cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]);
- cmd.boost_values[0].kill_cts_msk =
- cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]);
+ BUILD_BUG_ON(ARRAY_SIZE(ack_kill_msk) < ARRAY_SIZE(cmd.boost_values));
- cmd.boost_values[1].kill_ack_msk = cmd.boost_values[0].kill_ack_msk;
- cmd.boost_values[2].kill_cts_msk = cmd.boost_values[0].kill_cts_msk;
- cmd.boost_values[1].kill_ack_msk = cmd.boost_values[0].kill_ack_msk;
- cmd.boost_values[2].kill_cts_msk = cmd.boost_values[0].kill_cts_msk;
-
- IWL_DEBUG_COEX(mvm, "ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x\n",
- iwl_bt_ack_kill_msk[bt_kill_msk],
- iwl_bt_cts_kill_msk[bt_kill_msk]);
+ for (i = 0; i < ARRAY_SIZE(cmd.boost_values); i++) {
+ cmd.boost_values[i].kill_ack_msk =
+ cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk[i]]);
+ cmd.boost_values[i].kill_cts_msk =
+ cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk[i]]);
+ }
return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_SW_BOOST, 0,
sizeof(cmd), &cmd);
@@ -700,8 +729,6 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
struct iwl_bt_iterator_data {
struct iwl_bt_coex_profile_notif *notif;
struct iwl_mvm *mvm;
- u32 num_bss_ifaces;
- bool reduced_tx_power;
struct ieee80211_chanctx_conf *primary;
struct ieee80211_chanctx_conf *secondary;
bool primary_ll;
@@ -737,22 +764,12 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
switch (vif->type) {
case NL80211_IFTYPE_STATION:
- /* Count BSSes vifs */
- data->num_bss_ifaces++;
/* default smps_mode for BSS / P2P client is AUTOMATIC */
smps_mode = IEEE80211_SMPS_AUTOMATIC;
break;
case NL80211_IFTYPE_AP:
- /* default smps_mode for AP / GO is OFF */
- smps_mode = IEEE80211_SMPS_OFF;
- if (!mvmvif->ap_ibss_active) {
- iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
- smps_mode);
+ if (!mvmvif->ap_ibss_active)
return;
- }
-
- /* the Ack / Cts kill mask must be default if AP / GO */
- data->reduced_tx_power = false;
break;
default:
return;
@@ -763,11 +780,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
/* If channel context is invalid or not on 2.4GHz .. */
if ((!chanctx_conf ||
chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) {
- /* ... relax constraints and disable rssi events */
- iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
- smps_mode);
- data->reduced_tx_power = false;
if (vif->type == NL80211_IFTYPE_STATION) {
+ /* ... relax constraints and disable rssi events */
+ iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
+ smps_mode);
iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
false);
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
@@ -779,9 +795,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (bt_activity_grading >= BT_HIGH_TRAFFIC)
smps_mode = IEEE80211_SMPS_STATIC;
else if (bt_activity_grading >= BT_LOW_TRAFFIC)
- smps_mode = vif->type == NL80211_IFTYPE_AP ?
- IEEE80211_SMPS_OFF :
- IEEE80211_SMPS_DYNAMIC;
+ smps_mode = IEEE80211_SMPS_DYNAMIC;
/* relax SMPS contraints for next association */
if (!vif->bss_conf.assoc)
@@ -795,7 +809,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
"mac %d: bt_activity_grading %d smps_req %d\n",
mvmvif->id, bt_activity_grading, smps_mode);
- iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode);
+ if (vif->type == NL80211_IFTYPE_STATION)
+ iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
+ smps_mode);
/* low latency is always primary */
if (iwl_mvm_vif_low_latency(mvmvif)) {
@@ -846,7 +862,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc ||
le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) {
- data->reduced_tx_power = false;
iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false);
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
return;
@@ -861,23 +876,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) {
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
-
- /*
- * bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the
- * BSS / P2P clients have rssi above threshold.
- * We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before
- * the iteration, if one interface's rssi isn't good enough,
- * bt_kill_msk will be set to default values.
- */
} else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) {
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
-
- /*
- * One interface hasn't rssi above threshold, bt_kill_msk must
- * be set to default values.
- */
- data->reduced_tx_power = false;
}
/* Begin to monitor the RSSI: it may influence the reduced Tx power */
@@ -889,7 +890,6 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
struct iwl_bt_iterator_data data = {
.mvm = mvm,
.notif = &mvm->last_bt_notif,
- .reduced_tx_power = true,
};
struct iwl_bt_coex_ci_cmd cmd = {};
u8 ci_bw_idx;
@@ -959,14 +959,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd));
}
- /*
- * If there are no BSS / P2P client interfaces, reduced Tx Power is
- * irrelevant since it is based on the RSSI coming from the beacon.
- * Use BT_KILL_MSK_DEFAULT in that case.
- */
- data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
-
- if (iwl_mvm_bt_udpate_sw_boost(mvm, data.reduced_tx_power))
+ if (iwl_mvm_bt_udpate_sw_boost(mvm))
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
}
@@ -1035,16 +1028,6 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
return;
mvmsta = iwl_mvm_sta_from_mac80211(sta);
-
- data->num_bss_ifaces++;
-
- /*
- * This interface doesn't support reduced Tx power (because of low
- * RSSI probably), then set bt_kill_msk to default values.
- */
- if (!mvmsta->bt_reduced_txpower)
- data->reduced_tx_power = false;
- /* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */
}
void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@@ -1053,7 +1036,6 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
struct iwl_bt_iterator_data data = {
.mvm = mvm,
- .reduced_tx_power = true,
};
int ret;
@@ -1100,14 +1082,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_bt_rssi_iterator, &data);
- /*
- * If there are no BSS / P2P client interfaces, reduced Tx Power is
- * irrelevant since it is based on the RSSI coming from the beacon.
- * Use BT_KILL_MSK_DEFAULT in that case.
- */
- data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
-
- if (iwl_mvm_bt_udpate_sw_boost(mvm, data.reduced_tx_power))
+ if (iwl_mvm_bt_udpate_sw_boost(mvm))
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
}
@@ -1150,7 +1125,7 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
enum iwl_bt_coex_lut_type lut_type;
if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
- return iwl_mvm_coex_agg_time_limit_old(mvm, sta);
+ return iwl_mvm_bt_coex_is_mimo_allowed_old(mvm, sta);
if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id))
return true;
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
index ce50363d314b..a3be33359927 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
@@ -649,10 +649,6 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
sizeof(iwl_bt_prio_boost));
memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut,
sizeof(iwl_bt_mprio_lut));
- bt_cmd->kill_ack_msk =
- cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]);
- bt_cmd->kill_cts_msk =
- cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]);
send_cmd:
memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
@@ -664,12 +660,13 @@ send_cmd:
return ret;
}
-static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
- bool reduced_tx_power)
+static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm)
{
- enum iwl_bt_kill_msk bt_kill_msk;
- struct iwl_bt_coex_cmd_old *bt_cmd;
struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif_old;
+ u32 primary_lut = le32_to_cpu(notif->primary_ch_lut);
+ u32 ag = le32_to_cpu(notif->bt_activity_grading);
+ struct iwl_bt_coex_cmd_old *bt_cmd;
+ u8 ack_kill_msk, cts_kill_msk;
struct iwl_host_cmd cmd = {
.id = BT_CONFIG,
.data[0] = &bt_cmd,
@@ -680,31 +677,15 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
- if (reduced_tx_power) {
- /* Reduced Tx power has precedence on the type of the profile */
- bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW;
- } else {
- /* Low latency BT profile is active: give higher prio to BT */
- if (BT_MBOX_MSG(notif, 3, SCO_STATE) ||
- BT_MBOX_MSG(notif, 3, A2DP_STATE) ||
- BT_MBOX_MSG(notif, 3, SNIFF_STATE))
- bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP;
- else
- bt_kill_msk = BT_KILL_MSK_DEFAULT;
- }
-
- IWL_DEBUG_COEX(mvm,
- "Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n",
- bt_kill_msk,
- BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in",
- BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in",
- BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in");
+ ack_kill_msk = iwl_bt_ack_kill_msk[ag][primary_lut];
+ cts_kill_msk = iwl_bt_cts_kill_msk[ag][primary_lut];
- /* Don't send HCMD if there is no update */
- if (bt_kill_msk == mvm->bt_kill_msk)
+ if (mvm->bt_ack_kill_msk[0] == ack_kill_msk &&
+ mvm->bt_cts_kill_msk[0] == cts_kill_msk)
return 0;
- mvm->bt_kill_msk = bt_kill_msk;
+ mvm->bt_ack_kill_msk[0] = ack_kill_msk;
+ mvm->bt_cts_kill_msk[0] = cts_kill_msk;
bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL);
if (!bt_cmd)
@@ -712,16 +693,12 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
cmd.data[0] = bt_cmd;
bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD);
- bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]);
- bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]);
+ bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk]);
+ bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk]);
bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE |
BT_VALID_KILL_ACK |
BT_VALID_KILL_CTS);
- IWL_DEBUG_COEX(mvm, "ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x\n",
- iwl_bt_ack_kill_msk[bt_kill_msk],
- iwl_bt_cts_kill_msk[bt_kill_msk]);
-
ret = iwl_mvm_send_cmd(mvm, &cmd);
kfree(bt_cmd);
@@ -777,8 +754,6 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
struct iwl_bt_iterator_data {
struct iwl_bt_coex_profile_notif_old *notif;
struct iwl_mvm *mvm;
- u32 num_bss_ifaces;
- bool reduced_tx_power;
struct ieee80211_chanctx_conf *primary;
struct ieee80211_chanctx_conf *secondary;
bool primary_ll;
@@ -814,22 +789,12 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
switch (vif->type) {
case NL80211_IFTYPE_STATION:
- /* Count BSSes vifs */
- data->num_bss_ifaces++;
/* default smps_mode for BSS / P2P client is AUTOMATIC */
smps_mode = IEEE80211_SMPS_AUTOMATIC;
break;
case NL80211_IFTYPE_AP:
- /* default smps_mode for AP / GO is OFF */
- smps_mode = IEEE80211_SMPS_OFF;
- if (!mvmvif->ap_ibss_active) {
- iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
- smps_mode);
+ if (!mvmvif->ap_ibss_active)
return;
- }
-
- /* the Ack / Cts kill mask must be default if AP / GO */
- data->reduced_tx_power = false;
break;
default:
return;
@@ -840,11 +805,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
/* If channel context is invalid or not on 2.4GHz .. */
if ((!chanctx_conf ||
chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) {
- /* ... relax constraints and disable rssi events */
- iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
- smps_mode);
- data->reduced_tx_power = false;
if (vif->type == NL80211_IFTYPE_STATION) {
+ /* ... relax constraints and disable rssi events */
+ iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
+ smps_mode);
iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
false);
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
@@ -869,7 +833,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
mvmvif->id, data->notif->bt_status, bt_activity_grading,
smps_mode);
- iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode);
+ if (vif->type == NL80211_IFTYPE_STATION)
+ iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
+ smps_mode);
/* low latency is always primary */
if (iwl_mvm_vif_low_latency(mvmvif)) {
@@ -920,7 +886,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc ||
!data->notif->bt_status) {
- data->reduced_tx_power = false;
iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false);
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
return;
@@ -935,23 +900,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) {
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
-
- /*
- * bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the
- * BSS / P2P clients have rssi above threshold.
- * We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before
- * the iteration, if one interface's rssi isn't good enough,
- * bt_kill_msk will be set to default values.
- */
} else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) {
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
-
- /*
- * One interface hasn't rssi above threshold, bt_kill_msk must
- * be set to default values.
- */
- data->reduced_tx_power = false;
}
/* Begin to monitor the RSSI: it may influence the reduced Tx power */
@@ -963,7 +914,6 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
struct iwl_bt_iterator_data data = {
.mvm = mvm,
.notif = &mvm->last_bt_notif_old,
- .reduced_tx_power = true,
};
struct iwl_bt_coex_ci_cmd_old cmd = {};
u8 ci_bw_idx;
@@ -1037,14 +987,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
memcpy(&mvm->last_bt_ci_cmd_old, &cmd, sizeof(cmd));
}
- /*
- * If there are no BSS / P2P client interfaces, reduced Tx Power is
- * irrelevant since it is based on the RSSI coming from the beacon.
- * Use BT_KILL_MSK_DEFAULT in that case.
- */
- data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
-
- if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power))
+ if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm))
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
}
@@ -1115,16 +1058,6 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
return;
mvmsta = iwl_mvm_sta_from_mac80211(sta);
-
- data->num_bss_ifaces++;
-
- /*
- * This interface doesn't support reduced Tx power (because of low
- * RSSI probably), then set bt_kill_msk to default values.
- */
- if (!mvmsta->bt_reduced_txpower)
- data->reduced_tx_power = false;
- /* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */
}
void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@@ -1133,7 +1066,6 @@ void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
struct iwl_bt_iterator_data data = {
.mvm = mvm,
- .reduced_tx_power = true,
};
int ret;
@@ -1175,14 +1107,7 @@ void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_bt_rssi_iterator, &data);
- /*
- * If there are no BSS / P2P client interfaces, reduced Tx Power is
- * irrelevant since it is based on the RSSI coming from the beacon.
- * Use BT_KILL_MSK_DEFAULT in that case.
- */
- data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
-
- if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power))
+ if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm))
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index f131ef0ec5b3..7d18f466fbb3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -146,17 +146,47 @@ static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_fw_error_dump_file *dump_file = file->private_data;
+ struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
+ ssize_t bytes_read = 0;
+ ssize_t bytes_read_trans = 0;
+
+ if (*ppos < dump_ptrs->op_mode_len)
+ bytes_read +=
+ simple_read_from_buffer(user_buf, count, ppos,
+ dump_ptrs->op_mode_ptr,
+ dump_ptrs->op_mode_len);
+
+ if (bytes_read < 0 || *ppos < dump_ptrs->op_mode_len)
+ return bytes_read;
+
+ if (dump_ptrs->trans_ptr) {
+ *ppos -= dump_ptrs->op_mode_len;
+ bytes_read_trans =
+ simple_read_from_buffer(user_buf + bytes_read,
+ count - bytes_read, ppos,
+ dump_ptrs->trans_ptr->data,
+ dump_ptrs->trans_ptr->len);
+ *ppos += dump_ptrs->op_mode_len;
+
+ if (bytes_read_trans >= 0)
+ bytes_read += bytes_read_trans;
+ else if (!bytes_read)
+ /* propagate the failure */
+ return bytes_read_trans;
+ }
+
+ return bytes_read;
- return simple_read_from_buffer(user_buf, count, ppos,
- dump_file,
- le32_to_cpu(dump_file->file_len));
}
static int iwl_dbgfs_fw_error_dump_release(struct inode *inode,
struct file *file)
{
- vfree(file->private_data);
+ struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
+
+ vfree(dump_ptrs->op_mode_ptr);
+ vfree(dump_ptrs->trans_ptr);
+ kfree(dump_ptrs);
return 0;
}
@@ -514,9 +544,9 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n");
pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n",
- iwl_bt_ack_kill_msk[mvm->bt_kill_msk]);
+ iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]);
pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n",
- iwl_bt_cts_kill_msk[mvm->bt_kill_msk]);
+ iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]);
} else {
struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd;
@@ -531,10 +561,19 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
le64_to_cpu(cmd->bt_secondary_ci));
pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n");
- pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n",
- iwl_bt_ack_kill_msk[mvm->bt_kill_msk]);
- pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n",
- iwl_bt_cts_kill_msk[mvm->bt_kill_msk]);
+ pos += scnprintf(buf+pos, bufsz-pos,
+ "\tPrimary: ACK Kill Mask 0x%08x\n",
+ iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]);
+ pos += scnprintf(buf+pos, bufsz-pos,
+ "\tPrimary: CTS Kill Mask 0x%08x\n",
+ iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]);
+ pos += scnprintf(buf+pos, bufsz-pos,
+ "\tSecondary: ACK Kill Mask 0x%08x\n",
+ iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[1]]);
+ pos += scnprintf(buf+pos, bufsz-pos,
+ "\tSecondary: CTS Kill Mask 0x%08x\n",
+ iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[1]]);
+
}
mutex_unlock(&mvm->mutex);
@@ -830,8 +869,14 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
+ int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI);
+ if (ret)
+ return ret;
+
iwl_force_nmi(mvm->trans);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_NMI);
+
return count;
}
@@ -1115,11 +1160,11 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
}
#endif
-#define PRINT_MVM_REF(ref) do { \
- if (test_bit(ref, mvm->ref_bitmap)) \
- pos += scnprintf(buf + pos, bufsz - pos, \
- "\t(0x%lx) %s\n", \
- BIT(ref), #ref); \
+#define PRINT_MVM_REF(ref) do { \
+ if (mvm->refs[ref]) \
+ pos += scnprintf(buf + pos, bufsz - pos, \
+ "\t(0x%lx): %d %s\n", \
+ BIT(ref), mvm->refs[ref], #ref); \
} while (0)
static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
@@ -1127,12 +1172,17 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
- int pos = 0;
+ int i, pos = 0;
char buf[256];
const size_t bufsz = sizeof(buf);
+ u32 refs = 0;
- pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%lx\n",
- mvm->ref_bitmap[0]);
+ for (i = 0; i < IWL_MVM_REF_COUNT; i++)
+ if (mvm->refs[i])
+ refs |= BIT(i);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%x\n",
+ refs);
PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN);
PRINT_MVM_REF(IWL_MVM_REF_SCAN);
@@ -1158,7 +1208,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf,
mutex_lock(&mvm->mutex);
- taken = test_bit(IWL_MVM_REF_USER, mvm->ref_bitmap);
+ taken = mvm->refs[IWL_MVM_REF_USER];
if (value == 1 && !taken)
iwl_mvm_ref(mvm, IWL_MVM_REF_USER);
else if (value == 0 && taken)
@@ -1194,14 +1244,21 @@ iwl_dbgfs_prph_reg_read(struct file *file,
int pos = 0;
char buf[32];
const size_t bufsz = sizeof(buf);
+ int ret;
if (!mvm->dbgfs_prph_reg_addr)
return -EINVAL;
+ ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_READ);
+ if (ret)
+ return ret;
+
pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n",
mvm->dbgfs_prph_reg_addr,
iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr));
+ iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_READ);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
@@ -1211,6 +1268,7 @@ iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
{
u8 args;
u32 value;
+ int ret;
args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value);
/* if we only want to set the reg address - nothing more to do */
@@ -1221,7 +1279,13 @@ iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
if (args != 2)
return -EINVAL;
+ ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
+ if (ret)
+ return ret;
+
iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value);
+
+ iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);
out:
return count;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
index ab12aaa43034..69875716dcdb 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
@@ -385,6 +385,8 @@ enum iwl_bt_activity_grading {
BT_ON_NO_CONNECTION = 1,
BT_LOW_TRAFFIC = 2,
BT_HIGH_TRAFFIC = 3,
+
+ BT_MAX_AG,
}; /* BT_COEX_BT_ACTIVITY_GRADING_API_E_VER_1 */
enum iwl_bt_ci_compliance {
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index b8e4e78d601b..95f5b3274efb 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -133,6 +133,7 @@ enum {
/* Scan offload */
SCAN_OFFLOAD_REQUEST_CMD = 0x51,
SCAN_OFFLOAD_ABORT_CMD = 0x52,
+ HOT_SPOT_CMD = 0x53,
SCAN_OFFLOAD_COMPLETE = 0x6D,
SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
SCAN_OFFLOAD_CONFIG_CMD = 0x6f,
@@ -910,6 +911,72 @@ struct iwl_phy_context_cmd {
__le32 dsp_cfg_flags;
} __packed; /* PHY_CONTEXT_CMD_API_VER_1 */
+/*
+ * Aux ROC command
+ *
+ * Command requests the firmware to create a time event for a certain duration
+ * and remain on the given channel. This is done by using the Aux framework in
+ * the FW.
+ * The command was first used for Hot Spot issues - but can be used regardless
+ * to Hot Spot.
+ *
+ * ( HOT_SPOT_CMD 0x53 )
+ *
+ * @id_and_color: ID and color of the MAC
+ * @action: action to perform, one of FW_CTXT_ACTION_*
+ * @event_unique_id: If the action FW_CTXT_ACTION_REMOVE then the
+ * event_unique_id should be the id of the time event assigned by ucode.
+ * Otherwise ignore the event_unique_id.
+ * @sta_id_and_color: station id and color, resumed during "Remain On Channel"
+ * activity.
+ * @channel_info: channel info
+ * @node_addr: Our MAC Address
+ * @reserved: reserved for alignment
+ * @apply_time: GP2 value to start (should always be the current GP2 value)
+ * @apply_time_max_delay: Maximum apply time delay value in TU. Defines max
+ * time by which start of the event is allowed to be postponed.
+ * @duration: event duration in TU To calculate event duration:
+ * timeEventDuration = min(duration, remainingQuota)
+ */
+struct iwl_hs20_roc_req {
+ /* COMMON_INDEX_HDR_API_S_VER_1 hdr */
+ __le32 id_and_color;
+ __le32 action;
+ __le32 event_unique_id;
+ __le32 sta_id_and_color;
+ struct iwl_fw_channel_info channel_info;
+ u8 node_addr[ETH_ALEN];
+ __le16 reserved;
+ __le32 apply_time;
+ __le32 apply_time_max_delay;
+ __le32 duration;
+} __packed; /* HOT_SPOT_CMD_API_S_VER_1 */
+
+/*
+ * values for AUX ROC result values
+ */
+enum iwl_mvm_hot_spot {
+ HOT_SPOT_RSP_STATUS_OK,
+ HOT_SPOT_RSP_STATUS_TOO_MANY_EVENTS,
+ HOT_SPOT_MAX_NUM_OF_SESSIONS,
+};
+
+/*
+ * Aux ROC command response
+ *
+ * In response to iwl_hs20_roc_req the FW sends this command to notify the
+ * driver the uid of the timevent.
+ *
+ * ( HOT_SPOT_CMD 0x53 )
+ *
+ * @event_unique_id: Unique ID of time event assigned by ucode
+ * @status: Return status 0 is success, all the rest used for specific errors
+ */
+struct iwl_hs20_roc_res {
+ __le32 event_unique_id;
+ __le32 status;
+} __packed; /* HOT_SPOT_RSP_API_S_VER_1 */
+
#define IWL_RX_INFO_PHY_CNT 8
#define IWL_RX_INFO_ENERGY_ANT_ABC_IDX 1
#define IWL_RX_INFO_ENERGY_ANT_A_MSK 0x000000ff
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 96b9cf8137e7..0e523e28cabf 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -1074,8 +1074,12 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
/* Fill the common data for all mac context types */
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
- /* Also enable probe requests to pass */
- cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
+ /*
+ * pass probe requests and beacons from other APs (needed
+ * for ht protection)
+ */
+ cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST |
+ MAC_FILTER_IN_BEACON);
/* Fill the data specific for ap mode */
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap,
@@ -1096,6 +1100,13 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
/* Fill the common data for all mac context types */
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ /*
+ * pass probe requests and beacons from other APs (needed
+ * for ht protection)
+ */
+ cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST |
+ MAC_FILTER_IN_BEACON);
+
/* Fill the data specific for GO mode */
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap,
action == FW_CTXT_ACTION_ADD);
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 2eb6ebee4467..0d6a8b768a68 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -211,7 +211,9 @@ void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
return;
IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type);
- WARN_ON(test_and_set_bit(ref_type, mvm->ref_bitmap));
+ spin_lock_bh(&mvm->refs_lock);
+ mvm->refs[ref_type]++;
+ spin_unlock_bh(&mvm->refs_lock);
iwl_trans_ref(mvm->trans);
}
@@ -221,29 +223,35 @@ void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
return;
IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type);
- WARN_ON(!test_and_clear_bit(ref_type, mvm->ref_bitmap));
+ spin_lock_bh(&mvm->refs_lock);
+ WARN_ON(!mvm->refs[ref_type]--);
+ spin_unlock_bh(&mvm->refs_lock);
iwl_trans_unref(mvm->trans);
}
-static void
-iwl_mvm_unref_all_except(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref)
+static void iwl_mvm_unref_all_except(struct iwl_mvm *mvm,
+ enum iwl_mvm_ref_type except_ref)
{
- int i;
+ int i, j;
if (!iwl_mvm_is_d0i3_supported(mvm))
return;
- for_each_set_bit(i, mvm->ref_bitmap, IWL_MVM_REF_COUNT) {
- if (ref == i)
+ spin_lock_bh(&mvm->refs_lock);
+ for (i = 0; i < IWL_MVM_REF_COUNT; i++) {
+ if (except_ref == i || !mvm->refs[i])
continue;
- IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d\n", i);
- clear_bit(i, mvm->ref_bitmap);
- iwl_trans_unref(mvm->trans);
+ IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d (%d)\n",
+ i, mvm->refs[i]);
+ for (j = 0; j < mvm->refs[i]; j++)
+ iwl_trans_unref(mvm->trans);
+ mvm->refs[i] = 0;
}
+ spin_unlock_bh(&mvm->refs_lock);
}
-static int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
+int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
{
iwl_mvm_ref(mvm, ref_type);
@@ -321,13 +329,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
}
- if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT &&
- !iwlwifi_mod_params.uapsd_disable) {
- hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD;
- hw->uapsd_queues = IWL_UAPSD_AC_INFO;
- hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
- }
-
if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS;
@@ -660,6 +661,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
spin_unlock_bh(&mvm->time_event_lock);
mvmvif->phy_ctxt = NULL;
+ memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data));
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -668,11 +670,11 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
struct iwl_fw_error_dump_file *dump_file;
struct iwl_fw_error_dump_data *dump_data;
struct iwl_fw_error_dump_info *dump_info;
+ struct iwl_mvm_dump_ptrs *fw_error_dump;
const struct fw_img *img;
u32 sram_len, sram_ofs;
u32 file_len, rxf_len;
unsigned long flags;
- u32 trans_len;
int reg_val;
lockdep_assert_held(&mvm->mutex);
@@ -680,6 +682,10 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
if (mvm->fw_error_dump)
return;
+ fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL);
+ if (!fw_error_dump)
+ return;
+
img = &mvm->fw->img[mvm->cur_ucode];
sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
@@ -697,18 +703,15 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
rxf_len +
sizeof(*dump_info);
- trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0);
- if (trans_len)
- file_len += trans_len;
-
dump_file = vzalloc(file_len);
- if (!dump_file)
+ if (!dump_file) {
+ kfree(fw_error_dump);
return;
+ }
- mvm->fw_error_dump = dump_file;
+ fw_error_dump->op_mode_ptr = dump_file;
dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
- dump_file->file_len = cpu_to_le32(file_len);
dump_data = (void *)dump_file->data;
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO);
@@ -749,14 +752,12 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data,
sram_len);
- if (trans_len) {
- void *buf = iwl_fw_error_next_data(dump_data);
- u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf,
- trans_len);
- dump_data = (void *)((u8 *)buf + real_trans_len);
- dump_file->file_len =
- cpu_to_le32(file_len - trans_len + real_trans_len);
- }
+ fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans);
+ fw_error_dump->op_mode_len = file_len;
+ if (fw_error_dump->trans_ptr)
+ file_len += fw_error_dump->trans_ptr->len;
+ dump_file->file_len = cpu_to_le32(file_len);
+ mvm->fw_error_dump = fw_error_dump;
}
#endif
@@ -788,6 +789,12 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
iwl_mvm_reset_phy_ctxts(mvm);
memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
+ memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
+ memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
+ memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
+ memset(&mvm->last_bt_ci_cmd_old, 0, sizeof(mvm->last_bt_ci_cmd_old));
+ memset(&mvm->bt_ack_kill_msk, 0, sizeof(mvm->bt_ack_kill_msk));
+ memset(&mvm->bt_cts_kill_msk, 0, sizeof(mvm->bt_cts_kill_msk));
ieee80211_wake_queues(mvm->hw);
@@ -1399,6 +1406,28 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
}
#endif
+static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)
+{
+ struct ieee80211_sta *sta;
+ struct iwl_mvm_sta *mvmsta;
+ int i;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
+ lockdep_is_held(&mvm->mutex));
+ if (!sta || IS_ERR(sta) || !sta->tdls)
+ continue;
+
+ mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,
+ NL80211_TDLS_TEARDOWN,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,
+ GFP_KERNEL);
+ }
+}
+
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -1494,14 +1523,18 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
*/
iwl_mvm_remove_time_event(mvm, mvmvif,
&mvmvif->time_event_data);
- iwl_mvm_sf_update(mvm, vif, false);
- WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
} else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS |
BSS_CHANGED_QOS)) {
ret = iwl_mvm_power_update_mac(mvm);
if (ret)
IWL_ERR(mvm, "failed to update power mode\n");
}
+
+ if (changes & BSS_CHANGED_BEACON_INFO) {
+ iwl_mvm_sf_update(mvm, vif, false);
+ WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
+ }
+
if (changes & BSS_CHANGED_TXPOWER) {
IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n",
bss_conf->txpower);
@@ -1533,6 +1566,14 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
+ /*
+ * iwl_mvm_mac_ctxt_add() might read directly from the device
+ * (the system time), so make sure it is available.
+ */
+ ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_START_AP);
+ if (ret)
+ return ret;
+
mutex_lock(&mvm->mutex);
/* Send the beacon template */
@@ -1581,6 +1622,10 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
iwl_mvm_bt_coex_vif_change(mvm);
+ /* we don't support TDLS during DCM */
+ if (iwl_mvm_phy_ctx_count(mvm) > 1)
+ iwl_mvm_teardown_tdls_peers(mvm);
+
mutex_unlock(&mvm->mutex);
return 0;
@@ -1594,6 +1639,7 @@ out_remove:
iwl_mvm_mac_ctxt_remove(mvm, vif);
out_unlock:
mutex_unlock(&mvm->mutex);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_START_AP);
return ret;
}
@@ -1671,6 +1717,14 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ /*
+ * iwl_mvm_bss_info_changed_station() might call
+ * iwl_mvm_protect_session(), which reads directly from
+ * the device (the system time), so make sure it is available.
+ */
+ if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_BSS_CHANGED))
+ return;
+
mutex_lock(&mvm->mutex);
if (changes & BSS_CHANGED_IDLE && !bss_conf->idle)
@@ -1690,8 +1744,50 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
}
mutex_unlock(&mvm->mutex);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED);
}
+static int iwl_mvm_cancel_scan_wait_notif(struct iwl_mvm *mvm,
+ enum iwl_scan_status scan_type)
+{
+ int ret;
+ bool wait_for_handlers = false;
+
+ mutex_lock(&mvm->mutex);
+
+ if (mvm->scan_status != scan_type) {
+ ret = 0;
+ /* make sure there are no pending notifications */
+ wait_for_handlers = true;
+ goto out;
+ }
+
+ switch (scan_type) {
+ case IWL_MVM_SCAN_SCHED:
+ ret = iwl_mvm_scan_offload_stop(mvm, true);
+ break;
+ case IWL_MVM_SCAN_OS:
+ ret = iwl_mvm_cancel_scan(mvm);
+ break;
+ case IWL_MVM_SCAN_NONE:
+ default:
+ WARN_ON_ONCE(1);
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto out;
+
+ wait_for_handlers = true;
+out:
+ mutex_unlock(&mvm->mutex);
+
+ /* make sure we consume the completion notification */
+ if (wait_for_handlers)
+ iwl_mvm_wait_for_async_handlers(mvm);
+
+ return ret;
+}
static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req)
@@ -1704,19 +1800,13 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
req->n_channels > mvm->fw->ucode_capa.n_scan_channels)
return -EINVAL;
+ ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED);
+ if (ret)
+ return ret;
+
mutex_lock(&mvm->mutex);
- switch (mvm->scan_status) {
- case IWL_MVM_SCAN_SCHED:
- ret = iwl_mvm_scan_offload_stop(mvm, true);
- if (ret) {
- ret = -EBUSY;
- goto out;
- }
- break;
- case IWL_MVM_SCAN_NONE:
- break;
- default:
+ if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
ret = -EBUSY;
goto out;
}
@@ -1732,8 +1822,6 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
out:
mutex_unlock(&mvm->mutex);
- /* make sure to flush the Rx handler before the next scan arrives */
- iwl_mvm_wait_for_async_handlers(mvm);
return ret;
}
@@ -1885,28 +1973,6 @@ static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm,
iwl_mvm_power_update_mac(mvm);
}
-static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)
-{
- struct ieee80211_sta *sta;
- struct iwl_mvm_sta *mvmsta;
- int i;
-
- lockdep_assert_held(&mvm->mutex);
-
- for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
- sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
- lockdep_is_held(&mvm->mutex));
- if (!sta || IS_ERR(sta) || !sta->tdls)
- continue;
-
- mvmsta = iwl_mvm_sta_from_mac80211(sta);
- ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,
- NL80211_TDLS_TEARDOWN,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,
- GFP_KERNEL);
- }
-}
-
static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -2065,10 +2131,19 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
if (WARN_ON_ONCE(vif->bss_conf.assoc))
return;
+ /*
+ * iwl_mvm_protect_session() reads directly from the device
+ * (the system time), so make sure it is available.
+ */
+ if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PREPARE_TX))
+ return;
+
mutex_lock(&mvm->mutex);
/* Try really hard to protect the session and hear a beacon */
iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500);
mutex_unlock(&mvm->mutex);
+
+ iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX);
}
static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
@@ -2077,10 +2152,19 @@ static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int;
+ /*
+ * iwl_mvm_protect_session() reads directly from the device
+ * (the system time), so make sure it is available.
+ */
+ if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS))
+ return;
+
mutex_lock(&mvm->mutex);
/* Protect the session to hear the TDLS setup response on the channel */
iwl_mvm_protect_session(mvm, vif, duration, duration, 100);
mutex_unlock(&mvm->mutex);
+
+ iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS);
}
static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
@@ -2091,6 +2175,10 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret;
+ ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS);
+ if (ret)
+ return ret;
+
mutex_lock(&mvm->mutex);
if (!iwl_mvm_is_idle(mvm)) {
@@ -2098,26 +2186,7 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
goto out;
}
- switch (mvm->scan_status) {
- case IWL_MVM_SCAN_OS:
- IWL_DEBUG_SCAN(mvm, "Stopping previous scan for sched_scan\n");
- ret = iwl_mvm_cancel_scan(mvm);
- if (ret) {
- ret = -EBUSY;
- goto out;
- }
-
- /*
- * iwl_mvm_rx_scan_complete() will be called soon but will
- * not reset the scan status as it won't be IWL_MVM_SCAN_OS
- * any more since we queue the next scan immediately (below).
- * We make sure it is called before the next scan starts by
- * flushing the async-handlers work.
- */
- break;
- case IWL_MVM_SCAN_NONE:
- break;
- default:
+ if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
ret = -EBUSY;
goto out;
}
@@ -2145,8 +2214,6 @@ err:
mvm->scan_status = IWL_MVM_SCAN_NONE;
out:
mutex_unlock(&mvm->mutex);
- /* make sure to flush the Rx handler before the next scan arrives */
- iwl_mvm_wait_for_async_handlers(mvm);
return ret;
}
@@ -2266,6 +2333,119 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,
}
+static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait,
+ struct iwl_rx_packet *pkt, void *data)
+{
+ struct iwl_mvm *mvm =
+ container_of(notif_wait, struct iwl_mvm, notif_wait);
+ struct iwl_hs20_roc_res *resp;
+ int resp_len = iwl_rx_packet_payload_len(pkt);
+ struct iwl_mvm_time_event_data *te_data = data;
+
+ if (WARN_ON(pkt->hdr.cmd != HOT_SPOT_CMD))
+ return true;
+
+ if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
+ IWL_ERR(mvm, "Invalid HOT_SPOT_CMD response\n");
+ return true;
+ }
+
+ resp = (void *)pkt->data;
+
+ IWL_DEBUG_TE(mvm,
+ "Aux ROC: Recieved response from ucode: status=%d uid=%d\n",
+ resp->status, resp->event_unique_id);
+
+ te_data->uid = le32_to_cpu(resp->event_unique_id);
+ IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n",
+ te_data->uid);
+
+ spin_lock_bh(&mvm->time_event_lock);
+ list_add_tail(&te_data->list, &mvm->aux_roc_te_list);
+ spin_unlock_bh(&mvm->time_event_lock);
+
+ return true;
+}
+
+#define AUX_ROC_MAX_DELAY_ON_CHANNEL 5000
+static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,
+ struct ieee80211_channel *channel,
+ struct ieee80211_vif *vif,
+ int duration)
+{
+ int res, time_reg = DEVICE_SYSTEM_TIME_REG;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_time_event_data *te_data = &mvmvif->hs_time_event_data;
+ static const u8 time_event_response[] = { HOT_SPOT_CMD };
+ struct iwl_notification_wait wait_time_event;
+ struct iwl_hs20_roc_req aux_roc_req = {
+ .action = cpu_to_le32(FW_CTXT_ACTION_ADD),
+ .id_and_color =
+ cpu_to_le32(FW_CMD_ID_AND_COLOR(MAC_INDEX_AUX, 0)),
+ .sta_id_and_color = cpu_to_le32(mvm->aux_sta.sta_id),
+ /* Set the channel info data */
+ .channel_info.band = (channel->band == IEEE80211_BAND_2GHZ) ?
+ PHY_BAND_24 : PHY_BAND_5,
+ .channel_info.channel = channel->hw_value,
+ .channel_info.width = PHY_VHT_CHANNEL_MODE20,
+ /* Set the time and duration */
+ .apply_time = cpu_to_le32(iwl_read_prph(mvm->trans, time_reg)),
+ .apply_time_max_delay =
+ cpu_to_le32(MSEC_TO_TU(AUX_ROC_MAX_DELAY_ON_CHANNEL)),
+ .duration = cpu_to_le32(MSEC_TO_TU(duration)),
+ };
+
+ /* Set the node address */
+ memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN);
+
+ te_data->vif = vif;
+ te_data->duration = duration;
+ te_data->id = HOT_SPOT_CMD;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ spin_lock_bh(&mvm->time_event_lock);
+ list_add_tail(&te_data->list, &mvm->time_event_list);
+ spin_unlock_bh(&mvm->time_event_lock);
+
+ /*
+ * Use a notification wait, which really just processes the
+ * command response and doesn't wait for anything, in order
+ * to be able to process the response and get the UID inside
+ * the RX path. Using CMD_WANT_SKB doesn't work because it
+ * stores the buffer and then wakes up this thread, by which
+ * time another notification (that the time event started)
+ * might already be processed unsuccessfully.
+ */
+ iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event,
+ time_event_response,
+ ARRAY_SIZE(time_event_response),
+ iwl_mvm_rx_aux_roc, te_data);
+
+ res = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, sizeof(aux_roc_req),
+ &aux_roc_req);
+
+ if (res) {
+ IWL_ERR(mvm, "Couldn't send HOT_SPOT_CMD: %d\n", res);
+ iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
+ goto out_clear_te;
+ }
+
+ /* No need to wait for anything, so just pass 1 (0 isn't valid) */
+ res = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1);
+ /* should never fail */
+ WARN_ON_ONCE(res);
+
+ if (res) {
+ out_clear_te:
+ spin_lock_bh(&mvm->time_event_lock);
+ iwl_mvm_te_clear_data(mvm, te_data);
+ spin_unlock_bh(&mvm->time_event_lock);
+ }
+
+ return res;
+}
+
static int iwl_mvm_roc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel *channel,
@@ -2281,8 +2461,17 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
duration, type);
- if (vif->type != NL80211_IFTYPE_P2P_DEVICE) {
- IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type);
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ /* Use aux roc framework (HS20) */
+ ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
+ vif, duration);
+ return ret;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ /* handle below */
+ break;
+ default:
+ IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type);
return -EINVAL;
}
@@ -2661,6 +2850,10 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw,
goto out_remove;
}
+ /* we don't support TDLS during DCM - can be caused by channel switch */
+ if (iwl_mvm_phy_ctx_count(mvm) > 1)
+ iwl_mvm_teardown_tdls_peers(mvm);
+
goto out;
out_remove:
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 785e5232c757..2e73d3bd7757 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -82,6 +82,8 @@
/* RSSI offset for WkP */
#define IWL_RSSI_OFFSET 50
#define IWL_MVM_MISSED_BEACONS_THRESHOLD 8
+/* A TimeUnit is 1024 microsecond */
+#define MSEC_TO_TU(_msec) (_msec*1000/1024)
/*
* The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0"
@@ -126,6 +128,21 @@ struct iwl_mvm_mod_params {
};
extern struct iwl_mvm_mod_params iwlmvm_mod_params;
+/**
+ * struct iwl_mvm_dump_ptrs - set of pointers needed for the fw-error-dump
+ *
+ * @op_mode_ptr: pointer to the buffer coming from the mvm op_mode
+ * @trans_ptr: pointer to struct %iwl_trans_dump_data which contains the
+ * transport's data.
+ * @trans_len: length of the valid data in trans_ptr
+ * @op_mode_len: length of the valid data in op_mode_ptr
+ */
+struct iwl_mvm_dump_ptrs {
+ struct iwl_trans_dump_data *trans_ptr;
+ void *op_mode_ptr;
+ u32 op_mode_len;
+};
+
struct iwl_mvm_phy_ctxt {
u16 id;
u16 color;
@@ -249,6 +266,15 @@ enum iwl_mvm_ref_type {
IWL_MVM_REF_TX,
IWL_MVM_REF_TX_AGG,
IWL_MVM_REF_ADD_IF,
+ IWL_MVM_REF_START_AP,
+ IWL_MVM_REF_BSS_CHANGED,
+ IWL_MVM_REF_PREPARE_TX,
+ IWL_MVM_REF_PROTECT_TDLS,
+ IWL_MVM_REF_CHECK_CTKILL,
+ IWL_MVM_REF_PRPH_READ,
+ IWL_MVM_REF_PRPH_WRITE,
+ IWL_MVM_REF_NMI,
+ IWL_MVM_REF_TM_CMD,
IWL_MVM_REF_EXIT_WORK,
IWL_MVM_REF_COUNT,
@@ -327,6 +353,7 @@ struct iwl_mvm_vif {
*/
struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
struct iwl_mvm_time_event_data time_event_data;
+ struct iwl_mvm_time_event_data hs_time_event_data;
struct iwl_mvm_int_sta bcast_sta;
@@ -606,14 +633,15 @@ struct iwl_mvm {
*/
unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)];
- /* A bitmap of reference types taken by the driver. */
- unsigned long ref_bitmap[BITS_TO_LONGS(IWL_MVM_REF_COUNT)];
+ /* references taken by the driver and spinlock protecting them */
+ spinlock_t refs_lock;
+ u8 refs[IWL_MVM_REF_COUNT];
u8 vif_count;
/* -1 for always, 0 for never, >0 for that many times */
s8 restart_fw;
- void *fw_error_dump;
+ struct iwl_mvm_dump_ptrs *fw_error_dump;
#ifdef CONFIG_IWLWIFI_LEDS
struct led_classdev led;
@@ -647,7 +675,8 @@ struct iwl_mvm {
wait_queue_head_t d0i3_exit_waitq;
/* BT-Coex */
- u8 bt_kill_msk;
+ u8 bt_ack_kill_msk[NUM_PHY_CTX];
+ u8 bt_cts_kill_msk[NUM_PHY_CTX];
struct iwl_bt_coex_profile_notif_old last_bt_notif_old;
struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd_old;
@@ -659,6 +688,9 @@ struct iwl_mvm {
u8 bt_tx_prio;
enum iwl_bt_force_ant_mode bt_force_ant_mode;
+ /* Aux ROC */
+ struct list_head aux_roc_te_list;
+
/* Thermal Throttling and CTkill */
struct iwl_mvm_tt_mgmt thermal_throttle;
s32 temperature; /* Celsius */
@@ -697,6 +729,7 @@ enum iwl_mvm_status {
IWL_MVM_STATUS_ROC_RUNNING,
IWL_MVM_STATUS_IN_HW_RESTART,
IWL_MVM_STATUS_IN_D0I3,
+ IWL_MVM_STATUS_ROC_AUX_RUNNING,
};
static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm)
@@ -988,6 +1021,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
/* D0i3 */
void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
+int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq);
int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm);
@@ -1029,12 +1063,14 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm,
enum iwl_bt_kill_msk {
BT_KILL_MSK_DEFAULT,
- BT_KILL_MSK_SCO_HID_A2DP,
- BT_KILL_MSK_REDUCED_TXPOW,
+ BT_KILL_MSK_NEVER,
+ BT_KILL_MSK_ALWAYS,
BT_KILL_MSK_MAX,
};
-extern const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX];
-extern const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX];
+
+extern const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT];
+extern const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT];
+extern const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX];
/* beacon filtering */
#ifdef CONFIG_IWLWIFI_DEBUGFS
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index b04805ccb443..cfdd314fdd5d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -265,7 +265,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
!mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) {
- IWL_ERR(mvm, "Can't parse empty NVM sections\n");
+ IWL_ERR(mvm, "Can't parse empty OTP/NVM sections\n");
return NULL;
}
} else {
@@ -273,7 +273,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
!mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) {
IWL_ERR(mvm,
- "Can't parse empty family 8000 NVM sections\n");
+ "Can't parse empty family 8000 OTP/NVM sections\n");
return NULL;
}
/* MAC_OVERRIDE or at least HW section must exist */
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 7d7b2fbe7cd1..610dbcb0dc27 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -289,6 +289,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(MATCH_FOUND_NOTIFICATION),
CMD(SCAN_OFFLOAD_REQUEST_CMD),
CMD(SCAN_OFFLOAD_ABORT_CMD),
+ CMD(HOT_SPOT_CMD),
CMD(SCAN_OFFLOAD_COMPLETE),
CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD),
CMD(SCAN_ITERATION_COMPLETE),
@@ -391,6 +392,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if (!hw)
return NULL;
+ if (cfg->max_rx_agg_size)
+ hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size;
+
op_mode = hw->priv;
op_mode->ops = &iwl_mvm_ops;
@@ -416,6 +420,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mutex_init(&mvm->d0i3_suspend_mutex);
spin_lock_init(&mvm->async_handlers_lock);
INIT_LIST_HEAD(&mvm->time_event_list);
+ INIT_LIST_HEAD(&mvm->aux_roc_te_list);
INIT_LIST_HEAD(&mvm->async_handlers_list);
spin_lock_init(&mvm->time_event_lock);
@@ -425,6 +430,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
spin_lock_init(&mvm->d0i3_tx_lock);
+ spin_lock_init(&mvm->refs_lock);
skb_queue_head_init(&mvm->d0i3_tx);
init_waitqueue_head(&mvm->d0i3_exit_waitq);
@@ -539,7 +545,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx));
/* rpm starts with a taken ref. only set the appropriate bit here. */
- set_bit(IWL_MVM_REF_UCODE_DOWN, mvm->ref_bitmap);
+ mvm->refs[IWL_MVM_REF_UCODE_DOWN] = 1;
return op_mode;
@@ -567,7 +573,11 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
ieee80211_unregister_hw(mvm->hw);
kfree(mvm->scan_cmd);
- vfree(mvm->fw_error_dump);
+ if (mvm->fw_error_dump) {
+ vfree(mvm->fw_error_dump->op_mode_ptr);
+ vfree(mvm->fw_error_dump->trans_ptr);
+ kfree(mvm->fw_error_dump);
+ }
kfree(mvm->mcast_filter_cmd);
mvm->mcast_filter_cmd = NULL;
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 812813964847..763548880399 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -98,23 +98,21 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
bool update)
{
struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
- struct iwl_mvm_add_sta_cmd add_sta_cmd;
+ struct iwl_mvm_add_sta_cmd add_sta_cmd = {
+ .sta_id = mvm_sta->sta_id,
+ .mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color),
+ .add_modify = update ? 1 : 0,
+ .station_flags_msk = cpu_to_le32(STA_FLG_FAT_EN_MSK |
+ STA_FLG_MIMO_EN_MSK),
+ };
int ret;
u32 status;
u32 agg_size = 0, mpdu_dens = 0;
- memset(&add_sta_cmd, 0, sizeof(add_sta_cmd));
-
- add_sta_cmd.sta_id = mvm_sta->sta_id;
- add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
if (!update) {
add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk);
memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN);
}
- add_sta_cmd.add_modify = update ? 1 : 0;
-
- add_sta_cmd.station_flags_msk |= cpu_to_le32(STA_FLG_FAT_EN_MSK |
- STA_FLG_MIMO_EN_MSK);
switch (sta->bandwidth) {
case IEEE80211_STA_RX_BW_160:
@@ -528,8 +526,12 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
lockdep_assert_held(&mvm->mutex);
- /* Add the aux station, but without any queues */
- ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0,
+ /* Map Aux queue to fifo - needs to happen before adding Aux station */
+ iwl_trans_ac_txq_enable(mvm->trans, mvm->aux_queue,
+ IWL_MVM_TX_FIFO_MCAST);
+
+ /* Allocate aux station and assign to it the aux queue */
+ ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue),
NL80211_IFTYPE_UNSPECIFIED);
if (ret)
return ret;
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index ae52613b97f2..33e5041f1efc 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -72,9 +72,6 @@
#include "iwl-io.h"
#include "iwl-prph.h"
-/* A TimeUnit is 1024 microsecond */
-#define MSEC_TO_TU(_msec) (_msec*1000/1024)
-
/*
* For the high priority TE use a time event type that has similar priority to
* the FW's action scan priority.
@@ -100,6 +97,21 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
void iwl_mvm_roc_done_wk(struct work_struct *wk)
{
struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk);
+ u32 queues = 0;
+
+ /*
+ * Clear the ROC_RUNNING /ROC_AUX_RUNNING status bit.
+ * This will cause the TX path to drop offchannel transmissions.
+ * That would also be done by mac80211, but it is racy, in particular
+ * in the case that the time event actually completed in the firmware
+ * (which is handled in iwl_mvm_te_handle_notif).
+ */
+ if (test_and_clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
+ queues |= BIT(IWL_MVM_OFFCHANNEL_QUEUE);
+ if (test_and_clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status))
+ queues |= BIT(mvm->aux_queue);
+
+ iwl_mvm_unref(mvm, IWL_MVM_REF_ROC);
synchronize_net();
@@ -113,22 +125,12 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
* issue as it will have to complete before the next command is
* executed, and a new time event means a new command.
*/
- iwl_mvm_flush_tx_path(mvm, BIT(IWL_MVM_OFFCHANNEL_QUEUE), false);
+ iwl_mvm_flush_tx_path(mvm, queues, false);
}
static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
{
/*
- * First, clear the ROC_RUNNING status bit. This will cause the TX
- * path to drop offchannel transmissions. That would also be done
- * by mac80211, but it is racy, in particular in the case that the
- * time event actually completed in the firmware (which is handled
- * in iwl_mvm_te_handle_notif).
- */
- clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
- iwl_mvm_unref(mvm, IWL_MVM_REF_ROC);
-
- /*
* Of course, our status bit is just as racy as mac80211, so in
* addition, fire off the work struct which will drop all frames
* from the hardware queues that made it through the race. First
@@ -263,6 +265,60 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
}
/*
+ * Handle A Aux ROC time event
+ */
+static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
+ struct iwl_time_event_notif *notif)
+{
+ struct iwl_mvm_time_event_data *te_data, *tmp;
+ bool aux_roc_te = false;
+
+ list_for_each_entry_safe(te_data, tmp, &mvm->aux_roc_te_list, list) {
+ if (le32_to_cpu(notif->unique_id) == te_data->uid) {
+ aux_roc_te = true;
+ break;
+ }
+ }
+ if (!aux_roc_te) /* Not a Aux ROC time event */
+ return -EINVAL;
+
+ if (!le32_to_cpu(notif->status)) {
+ IWL_DEBUG_TE(mvm,
+ "ERROR: Aux ROC Time Event %s notification failure\n",
+ (le32_to_cpu(notif->action) &
+ TE_V2_NOTIF_HOST_EVENT_START) ? "start" : "end");
+ return -EINVAL;
+ }
+
+ IWL_DEBUG_TE(mvm,
+ "Aux ROC time event notification - UID = 0x%x action %d\n",
+ le32_to_cpu(notif->unique_id),
+ le32_to_cpu(notif->action));
+
+ if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_END) {
+ /* End TE, notify mac80211 */
+ ieee80211_remain_on_channel_expired(mvm->hw);
+ iwl_mvm_roc_finished(mvm); /* flush aux queue */
+ list_del(&te_data->list); /* remove from list */
+ te_data->running = false;
+ te_data->vif = NULL;
+ te_data->uid = 0;
+ } else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
+ set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
+ set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
+ te_data->running = true;
+ ieee80211_ready_on_channel(mvm->hw); /* Start TE */
+ } else {
+ IWL_DEBUG_TE(mvm,
+ "ERROR: Unknown Aux ROC Time Event (action = %d)\n",
+ le32_to_cpu(notif->action));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
* The Rx handler for time event notifications
*/
int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
@@ -278,10 +334,15 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
le32_to_cpu(notif->action));
spin_lock_bh(&mvm->time_event_lock);
+ /* This time event is triggered for Aux ROC request */
+ if (!iwl_mvm_aux_roc_te_handle_notif(mvm, notif))
+ goto unlock;
+
list_for_each_entry_safe(te_data, tmp, &mvm->time_event_list, list) {
if (le32_to_cpu(notif->unique_id) == te_data->uid)
iwl_mvm_te_handle_notif(mvm, te_data, notif);
}
+unlock:
spin_unlock_bh(&mvm->time_event_lock);
return 0;
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c
index 868561512783..0464599c111e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tt.c
@@ -140,9 +140,9 @@ static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm)
/* TODO: move parsing to NVM code */
calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data;
- ptat = calib[OTP_DTS_DIODE_DEVIATION];
- pa1 = calib[OTP_DTS_DIODE_DEVIATION + 1];
- pa2 = calib[OTP_DTS_DIODE_DEVIATION + 2];
+ ptat = calib[OTP_DTS_DIODE_DEVIATION * 2];
+ pa1 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 1];
+ pa2 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 2];
/* get the median: */
if (ptat > pa1) {
@@ -338,10 +338,16 @@ static void check_exit_ctkill(struct work_struct *work)
duration = tt->params->ct_kill_duration;
+ /* make sure the device is available for direct read/writes */
+ if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL))
+ goto reschedule;
+
iwl_trans_start_hw(mvm->trans);
temp = check_nic_temperature(mvm);
iwl_trans_stop_device(mvm->trans);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL);
+
if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) {
IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n");
goto reschedule;
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index e9ff38635c21..dbc870713882 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -311,6 +311,16 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
return -1;
/*
+ * IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets that can be used
+ * in 2 different types of vifs, P2P & STATION. P2P uses the offchannel
+ * queue. STATION (HS2.0) uses the auxiliary context of the FW,
+ * and hence needs to be sent on the aux queue
+ */
+ if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE &&
+ info->control.vif->type == NL80211_IFTYPE_STATION)
+ IEEE80211_SKB_CB(skb)->hw_queue = mvm->aux_queue;
+
+ /*
* If the interface on which frame is sent is the P2P_DEVICE
* or an AP/GO interface use the broadcast station associated
* with it; otherwise use the AUX station.
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 5b5b0d8c6f60..06e04aaf61ee 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -67,6 +67,7 @@
#include <linux/sched.h>
#include <linux/bitops.h>
#include <linux/gfp.h>
+#include <linux/vmalloc.h>
#include "iwl-drv.h"
#include "iwl-trans.h"
@@ -1773,28 +1774,207 @@ static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd)
return cmdlen;
}
-static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans,
- void *buf, u32 buflen)
+static const struct {
+ u32 start, end;
+} iwl_prph_dump_addr[] = {
+ { .start = 0x00a00000, .end = 0x00a00000 },
+ { .start = 0x00a0000c, .end = 0x00a00024 },
+ { .start = 0x00a0002c, .end = 0x00a0003c },
+ { .start = 0x00a00410, .end = 0x00a00418 },
+ { .start = 0x00a00420, .end = 0x00a00420 },
+ { .start = 0x00a00428, .end = 0x00a00428 },
+ { .start = 0x00a00430, .end = 0x00a0043c },
+ { .start = 0x00a00444, .end = 0x00a00444 },
+ { .start = 0x00a004c0, .end = 0x00a004cc },
+ { .start = 0x00a004d8, .end = 0x00a004d8 },
+ { .start = 0x00a004e0, .end = 0x00a004f0 },
+ { .start = 0x00a00840, .end = 0x00a00840 },
+ { .start = 0x00a00850, .end = 0x00a00858 },
+ { .start = 0x00a01004, .end = 0x00a01008 },
+ { .start = 0x00a01010, .end = 0x00a01010 },
+ { .start = 0x00a01018, .end = 0x00a01018 },
+ { .start = 0x00a01024, .end = 0x00a01024 },
+ { .start = 0x00a0102c, .end = 0x00a01034 },
+ { .start = 0x00a0103c, .end = 0x00a01040 },
+ { .start = 0x00a01048, .end = 0x00a01094 },
+ { .start = 0x00a01c00, .end = 0x00a01c20 },
+ { .start = 0x00a01c58, .end = 0x00a01c58 },
+ { .start = 0x00a01c7c, .end = 0x00a01c7c },
+ { .start = 0x00a01c28, .end = 0x00a01c54 },
+ { .start = 0x00a01c5c, .end = 0x00a01c5c },
+ { .start = 0x00a01c84, .end = 0x00a01c84 },
+ { .start = 0x00a01ce0, .end = 0x00a01d0c },
+ { .start = 0x00a01d18, .end = 0x00a01d20 },
+ { .start = 0x00a01d2c, .end = 0x00a01d30 },
+ { .start = 0x00a01d40, .end = 0x00a01d5c },
+ { .start = 0x00a01d80, .end = 0x00a01d80 },
+ { .start = 0x00a01d98, .end = 0x00a01d98 },
+ { .start = 0x00a01dc0, .end = 0x00a01dfc },
+ { .start = 0x00a01e00, .end = 0x00a01e2c },
+ { .start = 0x00a01e40, .end = 0x00a01e60 },
+ { .start = 0x00a01e84, .end = 0x00a01e90 },
+ { .start = 0x00a01e9c, .end = 0x00a01ec4 },
+ { .start = 0x00a01ed0, .end = 0x00a01ed0 },
+ { .start = 0x00a01f00, .end = 0x00a01f14 },
+ { .start = 0x00a01f44, .end = 0x00a01f58 },
+ { .start = 0x00a01f80, .end = 0x00a01fa8 },
+ { .start = 0x00a01fb0, .end = 0x00a01fbc },
+ { .start = 0x00a01ff8, .end = 0x00a01ffc },
+ { .start = 0x00a02000, .end = 0x00a02048 },
+ { .start = 0x00a02068, .end = 0x00a020f0 },
+ { .start = 0x00a02100, .end = 0x00a02118 },
+ { .start = 0x00a02140, .end = 0x00a0214c },
+ { .start = 0x00a02168, .end = 0x00a0218c },
+ { .start = 0x00a021c0, .end = 0x00a021c0 },
+ { .start = 0x00a02400, .end = 0x00a02410 },
+ { .start = 0x00a02418, .end = 0x00a02420 },
+ { .start = 0x00a02428, .end = 0x00a0242c },
+ { .start = 0x00a02434, .end = 0x00a02434 },
+ { .start = 0x00a02440, .end = 0x00a02460 },
+ { .start = 0x00a02468, .end = 0x00a024b0 },
+ { .start = 0x00a024c8, .end = 0x00a024cc },
+ { .start = 0x00a02500, .end = 0x00a02504 },
+ { .start = 0x00a0250c, .end = 0x00a02510 },
+ { .start = 0x00a02540, .end = 0x00a02554 },
+ { .start = 0x00a02580, .end = 0x00a025f4 },
+ { .start = 0x00a02600, .end = 0x00a0260c },
+ { .start = 0x00a02648, .end = 0x00a02650 },
+ { .start = 0x00a02680, .end = 0x00a02680 },
+ { .start = 0x00a026c0, .end = 0x00a026d0 },
+ { .start = 0x00a02700, .end = 0x00a0270c },
+ { .start = 0x00a02804, .end = 0x00a02804 },
+ { .start = 0x00a02818, .end = 0x00a0281c },
+ { .start = 0x00a02c00, .end = 0x00a02db4 },
+ { .start = 0x00a02df4, .end = 0x00a02fb0 },
+ { .start = 0x00a03000, .end = 0x00a03014 },
+ { .start = 0x00a0301c, .end = 0x00a0302c },
+ { .start = 0x00a03034, .end = 0x00a03038 },
+ { .start = 0x00a03040, .end = 0x00a03048 },
+ { .start = 0x00a03060, .end = 0x00a03068 },
+ { .start = 0x00a03070, .end = 0x00a03074 },
+ { .start = 0x00a0307c, .end = 0x00a0307c },
+ { .start = 0x00a03080, .end = 0x00a03084 },
+ { .start = 0x00a0308c, .end = 0x00a03090 },
+ { .start = 0x00a03098, .end = 0x00a03098 },
+ { .start = 0x00a030a0, .end = 0x00a030a0 },
+ { .start = 0x00a030a8, .end = 0x00a030b4 },
+ { .start = 0x00a030bc, .end = 0x00a030bc },
+ { .start = 0x00a030c0, .end = 0x00a0312c },
+ { .start = 0x00a03c00, .end = 0x00a03c5c },
+ { .start = 0x00a04400, .end = 0x00a04454 },
+ { .start = 0x00a04460, .end = 0x00a04474 },
+ { .start = 0x00a044c0, .end = 0x00a044ec },
+ { .start = 0x00a04500, .end = 0x00a04504 },
+ { .start = 0x00a04510, .end = 0x00a04538 },
+ { .start = 0x00a04540, .end = 0x00a04548 },
+ { .start = 0x00a04560, .end = 0x00a0457c },
+ { .start = 0x00a04590, .end = 0x00a04598 },
+ { .start = 0x00a045c0, .end = 0x00a045f4 },
+};
+
+static u32 iwl_trans_pcie_dump_prph(struct iwl_trans *trans,
+ struct iwl_fw_error_dump_data **data)
+{
+ struct iwl_fw_error_dump_prph *prph;
+ unsigned long flags;
+ u32 prph_len = 0, i;
+
+ if (!iwl_trans_grab_nic_access(trans, false, &flags))
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) {
+ /* The range includes both boundaries */
+ int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
+ iwl_prph_dump_addr[i].start + 4;
+ int reg;
+ __le32 *val;
+
+ prph_len += sizeof(*data) + sizeof(*prph) +
+ num_bytes_in_chunk;
+
+ (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH);
+ (*data)->len = cpu_to_le32(sizeof(*prph) +
+ num_bytes_in_chunk);
+ prph = (void *)(*data)->data;
+ prph->prph_start = cpu_to_le32(iwl_prph_dump_addr[i].start);
+ val = (void *)prph->data;
+
+ for (reg = iwl_prph_dump_addr[i].start;
+ reg <= iwl_prph_dump_addr[i].end;
+ reg += 4)
+ *val++ = cpu_to_le32(iwl_trans_pcie_read_prph(trans,
+ reg));
+ *data = iwl_fw_error_next_data(*data);
+ }
+
+ iwl_trans_release_nic_access(trans, &flags);
+
+ return prph_len;
+}
+
+#define IWL_CSR_TO_DUMP (0x250)
+
+static u32 iwl_trans_pcie_dump_csr(struct iwl_trans *trans,
+ struct iwl_fw_error_dump_data **data)
+{
+ u32 csr_len = sizeof(**data) + IWL_CSR_TO_DUMP;
+ __le32 *val;
+ int i;
+
+ (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_CSR);
+ (*data)->len = cpu_to_le32(IWL_CSR_TO_DUMP);
+ val = (void *)(*data)->data;
+
+ for (i = 0; i < IWL_CSR_TO_DUMP; i += 4)
+ *val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i));
+
+ *data = iwl_fw_error_next_data(*data);
+
+ return csr_len;
+}
+
+static
+struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_fw_error_dump_data *data;
struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue];
struct iwl_fw_error_dump_txcmd *txcmd;
+ struct iwl_trans_dump_data *dump_data;
u32 len;
int i, ptr;
- len = sizeof(*data) +
+ /* transport dump header */
+ len = sizeof(*dump_data);
+
+ /* host commands */
+ len += sizeof(*data) +
cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE);
+ /* CSR registers */
+ len += sizeof(*data) + IWL_CSR_TO_DUMP;
+
+ /* PRPH registers */
+ for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) {
+ /* The range includes both boundaries */
+ int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
+ iwl_prph_dump_addr[i].start + 4;
+
+ len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_prph) +
+ num_bytes_in_chunk;
+ }
+
+ /* FW monitor */
if (trans_pcie->fw_mon_page)
len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
trans_pcie->fw_mon_size;
- if (!buf)
- return len;
+ dump_data = vzalloc(len);
+ if (!dump_data)
+ return NULL;
len = 0;
- data = buf;
+ data = (void *)dump_data->data;
data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXCMD);
txcmd = (void *)data->data;
spin_lock_bh(&cmdq->lock);
@@ -1820,11 +2000,15 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans,
data->len = cpu_to_le32(len);
len += sizeof(*data);
+ data = iwl_fw_error_next_data(data);
+
+ len += iwl_trans_pcie_dump_prph(trans, &data);
+ len += iwl_trans_pcie_dump_csr(trans, &data);
+ /* data is already pointing to the next section */
if (trans_pcie->fw_mon_page) {
struct iwl_fw_error_dump_fw_mon *fw_mon_data;
- data = iwl_fw_error_next_data(data);
data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR);
data->len = cpu_to_le32(trans_pcie->fw_mon_size +
sizeof(*fw_mon_data));
@@ -1852,7 +2036,9 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans,
trans_pcie->fw_mon_size;
}
- return len;
+ dump_data->len = len;
+
+ return dump_data;
}
#else
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 5ea65fce0b83..1326f6121835 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -685,11 +685,16 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
struct mac80211_hwsim_data *data = hw->priv;
u64 now = mac80211_hwsim_get_tsf(hw, vif);
u32 bcn_int = data->beacon_int;
- s64 delta = tsf - now;
+ u64 delta = abs64(tsf - now);
- data->tsf_offset += delta;
/* adjust after beaconing with new timestamp at old TBTT */
- data->bcn_delta = do_div(delta, bcn_int);
+ if (tsf > now) {
+ data->tsf_offset += delta;
+ data->bcn_delta = do_div(delta, bcn_int);
+ } else {
+ data->tsf_offset -= delta;
+ data->bcn_delta = -do_div(delta, bcn_int);
+ }
}
static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index 9d6d8d9f01e3..62f5dbe602d3 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -541,7 +541,6 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid,
int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
{
struct host_cmd_ds_11n_addba_req add_ba_req;
- struct mwifiex_sta_node *sta_ptr;
u32 tx_win_size = priv->add_ba_param.tx_win_size;
static u8 dialog_tok;
int ret;
@@ -553,6 +552,8 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
priv->adapter->is_hw_11ac_capable &&
memcmp(priv->cfg_bssid, peer_mac, ETH_ALEN)) {
+ struct mwifiex_sta_node *sta_ptr;
+
sta_ptr = mwifiex_get_sta_entry(priv, peer_mac);
if (!sta_ptr) {
dev_warn(priv->adapter->dev,
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index b22bae3d1205..06a2c215ef5e 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -249,13 +249,22 @@ void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta)
* buffered in Rx reordering table.
*/
static int
-mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr)
+mwifiex_11n_find_last_seq_num(struct reorder_tmr_cnxt *ctx)
{
+ struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr = ctx->ptr;
+ struct mwifiex_private *priv = ctx->priv;
+ unsigned long flags;
int i;
- for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i)
- if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
+ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ for (i = rx_reorder_tbl_ptr->win_size - 1; i >= 0; --i) {
+ if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) {
+ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
+ flags);
return i;
+ }
+ }
+ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
return -1;
}
@@ -274,7 +283,7 @@ mwifiex_flush_data(unsigned long context)
(struct reorder_tmr_cnxt *) context;
int start_win, seq_num;
- seq_num = mwifiex_11n_find_last_seq_num(ctx->ptr);
+ seq_num = mwifiex_11n_find_last_seq_num(ctx);
if (seq_num < 0)
return;
@@ -729,9 +738,9 @@ void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
mwifiex_del_rx_reorder_entry(priv, del_tbl_ptr);
spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
}
+ INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
- INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
mwifiex_reset_11n_rx_seq_num(priv);
}
@@ -749,10 +758,14 @@ void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags)
priv = adapter->priv[i];
if (!priv)
continue;
- if (list_empty(&priv->rx_reorder_tbl_ptr))
- continue;
spin_lock_irqsave(&priv->rx_reorder_tbl_lock, lock_flags);
+ if (list_empty(&priv->rx_reorder_tbl_ptr)) {
+ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
+ lock_flags);
+ continue;
+ }
+
list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list)
tbl->flags = flags;
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, lock_flags);
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index ca87f923c61e..e2e6bf13c2d8 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1604,9 +1604,6 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len,
return -EINVAL;
}
- /* disconnect before try to associate */
- mwifiex_deauthenticate(priv, NULL);
-
/* As this is new association, clear locally stored
* keys and security related flags */
priv->sec_info.wpa_enabled = false;
@@ -1744,6 +1741,11 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
return -EINVAL;
}
+ if (priv->wdev && priv->wdev->current_bss) {
+ wiphy_warn(wiphy, "%s: already connected\n", dev->name);
+ return -EALREADY;
+ }
+
wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n",
(char *) sme->ssid, sme->bssid);
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 5899eee87fb1..baf0aab63c04 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -137,7 +137,6 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
struct host_cmd_ds_command *host_cmd;
uint16_t cmd_code;
uint16_t cmd_size;
- struct timeval tstamp;
unsigned long flags;
__le32 tmp;
@@ -198,10 +197,8 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
*/
skb_put(cmd_node->cmd_skb, cmd_size - cmd_node->cmd_skb->len);
- do_gettimeofday(&tstamp);
- dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d,"
- " seqno %#x\n",
- tstamp.tv_sec, tstamp.tv_usec, cmd_code,
+ dev_dbg(adapter->dev,
+ "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n", cmd_code,
le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size,
le16_to_cpu(host_cmd->seq_num));
@@ -273,7 +270,6 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
(struct mwifiex_opt_sleep_confirm *)
adapter->sleep_cfm->data;
struct sk_buff *sleep_cfm_tmp;
- struct timeval ts;
__le32 tmp;
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
@@ -284,10 +280,9 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
(adapter->seq_num, priv->bss_num,
priv->bss_type)));
- do_gettimeofday(&ts);
dev_dbg(adapter->dev,
- "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d, seqno %#x\n",
- ts.tv_sec, ts.tv_usec, le16_to_cpu(sleep_cfm_buf->command),
+ "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n",
+ le16_to_cpu(sleep_cfm_buf->command),
le16_to_cpu(sleep_cfm_buf->action),
le16_to_cpu(sleep_cfm_buf->size),
le16_to_cpu(sleep_cfm_buf->seq_num));
@@ -442,7 +437,6 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
struct sk_buff *skb = adapter->event_skb;
u32 eventcause = adapter->event_cause;
- struct timeval tstamp;
struct mwifiex_rxinfo *rx_info;
/* Save the last event to debug log */
@@ -467,9 +461,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
rx_info->bss_type = priv->bss_type;
}
- do_gettimeofday(&tstamp);
- dev_dbg(adapter->dev, "EVENT: %lu.%lu: cause: %#x\n",
- tstamp.tv_sec, tstamp.tv_usec, eventcause);
+ dev_dbg(adapter->dev, "EVENT: cause: %#x\n", eventcause);
if (eventcause == EVENT_PS_SLEEP || eventcause == EVENT_PS_AWAKE) {
/* Handle PS_SLEEP/AWAKE events on STA */
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
@@ -781,7 +773,6 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
uint16_t orig_cmdresp_no;
uint16_t cmdresp_no;
uint16_t cmdresp_result;
- struct timeval tstamp;
unsigned long flags;
/* Now we got response from FW, cancel the command timer */
@@ -839,11 +830,10 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] =
orig_cmdresp_no;
- do_gettimeofday(&tstamp);
- dev_dbg(adapter->dev, "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d,"
- " len %d, seqno 0x%x\n",
- tstamp.tv_sec, tstamp.tv_usec, orig_cmdresp_no, cmdresp_result,
- le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num));
+ dev_dbg(adapter->dev,
+ "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n",
+ orig_cmdresp_no, cmdresp_result,
+ le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num));
if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n");
@@ -903,7 +893,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
struct mwifiex_adapter *adapter =
(struct mwifiex_adapter *) function_context;
struct cmd_ctrl_node *cmd_node;
- struct timeval tstamp;
adapter->is_cmd_timedout = 1;
if (!adapter->curr_cmd) {
@@ -916,10 +905,8 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index];
adapter->dbg.timeout_cmd_act =
adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index];
- do_gettimeofday(&tstamp);
dev_err(adapter->dev,
- "%s: Timeout cmd id (%lu.%lu) = %#x, act = %#x\n",
- __func__, tstamp.tv_sec, tstamp.tv_usec,
+ "%s: Timeout cmd id = %#x, act = %#x\n", __func__,
adapter->dbg.timeout_cmd_id,
adapter->dbg.timeout_cmd_act);
@@ -1237,18 +1224,15 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter,
uint16_t result = le16_to_cpu(cmd->result);
uint16_t command = le16_to_cpu(cmd->command);
uint16_t seq_num = le16_to_cpu(cmd->seq_num);
- struct timeval ts;
if (!upld_len) {
dev_err(adapter->dev, "%s: cmd size is 0\n", __func__);
return;
}
- do_gettimeofday(&ts);
dev_dbg(adapter->dev,
- "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d, len %d, seqno 0x%x\n",
- ts.tv_sec, ts.tv_usec, command, result, le16_to_cpu(cmd->size),
- seq_num);
+ "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n",
+ command, result, le16_to_cpu(cmd->size), seq_num);
/* Get BSS number and corresponding priv */
priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num),
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 5561573452bb..49da2d53d294 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -713,7 +713,7 @@ struct mwifiex_ie_types_vendor_param_set {
u8 ie[MWIFIEX_MAX_VSIE_LEN];
};
-#define MWIFIEX_TDLS_IDLE_TIMEOUT 60
+#define MWIFIEX_TDLS_IDLE_TIMEOUT_IN_SEC 60
struct mwifiex_ie_types_tdls_idle_timeout {
struct mwifiex_ie_types_header header;
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index fc135649b85f..8d6c25908b6d 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -949,7 +949,7 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
chan_tlv->chan_scan_param[0].radio_type |=
(IEEE80211_HT_PARAM_CHA_SEC_ABOVE << 4);
else if (adapter->sec_chan_offset ==
- IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
+ IEEE80211_HT_PARAM_CHA_SEC_BELOW)
chan_tlv->chan_scan_param[0].radio_type |=
(IEEE80211_HT_PARAM_CHA_SEC_BELOW << 4);
}
@@ -1288,8 +1288,6 @@ done:
int mwifiex_associate(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc)
{
- u8 current_bssid[ETH_ALEN];
-
/* Return error if the adapter is not STA role or table entry
* is not marked as infra.
*/
@@ -1304,10 +1302,6 @@ int mwifiex_associate(struct mwifiex_private *priv,
else
mwifiex_set_ba_params(priv);
- memcpy(&current_bssid,
- &priv->curr_bss_params.bss_descriptor.mac_address,
- sizeof(current_bssid));
-
/* Clear any past association response stored for application
retrieval */
priv->assoc_rsp_size = 0;
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 3e5194fb0b0f..dfa37eadc4db 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -33,6 +33,7 @@ static void scan_delay_timer_fn(unsigned long data)
struct mwifiex_private *priv = (struct mwifiex_private *)data;
struct mwifiex_adapter *adapter = priv->adapter;
struct cmd_ctrl_node *cmd_node, *tmp_node;
+ spinlock_t *scan_q_lock = &adapter->scan_pending_q_lock;
unsigned long flags;
if (adapter->surprise_removed)
@@ -44,13 +45,13 @@ static void scan_delay_timer_fn(unsigned long data)
* Abort scan operation by cancelling all pending scan
* commands
*/
- spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ spin_lock_irqsave(scan_q_lock, flags);
list_for_each_entry_safe(cmd_node, tmp_node,
&adapter->scan_pending_q, list) {
list_del(&cmd_node->list);
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
}
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+ spin_unlock_irqrestore(scan_q_lock, flags);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->scan_processing = false;
@@ -79,12 +80,17 @@ static void scan_delay_timer_fn(unsigned long data)
*/
adapter->scan_delay_cnt = 0;
adapter->empty_tx_q_cnt = 0;
- spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ spin_lock_irqsave(scan_q_lock, flags);
+
+ if (list_empty(&adapter->scan_pending_q)) {
+ spin_unlock_irqrestore(scan_q_lock, flags);
+ goto done;
+ }
+
cmd_node = list_first_entry(&adapter->scan_pending_q,
struct cmd_ctrl_node, list);
list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
- flags);
+ spin_unlock_irqrestore(scan_q_lock, flags);
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
true);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index 5f7afffdd34e..c16dd2cc8198 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -2238,7 +2238,6 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
struct pcie_service_card *card = adapter->card;
const struct mwifiex_pcie_card_reg *creg = card->pcie.reg;
unsigned int reg, reg_start, reg_end;
- struct timeval t;
u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0;
enum rdwr_status stat;
u32 memory_size;
@@ -2257,9 +2256,7 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
entry->mem_size = 0;
}
- do_gettimeofday(&t);
- dev_info(adapter->dev, "== mwifiex firmware dump start: %u.%06u ==\n",
- (u32)t.tv_sec, (u32)t.tv_usec);
+ dev_info(adapter->dev, "== mwifiex firmware dump start ==\n");
/* Read the number of the memories which will dump */
stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
@@ -2303,9 +2300,8 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
end_ptr = dbg_ptr + memory_size;
doneflag = entry->done_flag;
- do_gettimeofday(&t);
- dev_info(adapter->dev, "Start %s output %u.%06u, please wait...\n",
- entry->mem_name, (u32)t.tv_sec, (u32)t.tv_usec);
+ dev_info(adapter->dev, "Start %s output, please wait...\n",
+ entry->mem_name);
do {
stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
@@ -2331,9 +2327,7 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
break;
} while (true);
}
- do_gettimeofday(&t);
- dev_info(adapter->dev, "== mwifiex firmware dump end: %u.%06u ==\n",
- (u32)t.tv_sec, (u32)t.tv_usec);
+ dev_info(adapter->dev, "== mwifiex firmware dump end ==\n");
kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env);
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index 1da04a086bd9..1770fa3fc1e6 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -1954,6 +1954,7 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter)
mmc_remove_host(target);
/* 20ms delay is based on experiment with sdhci controller */
mdelay(20);
+ target->rescan_entered = 0; /* rescan non-removable cards */
mmc_add_host(target);
}
@@ -2012,7 +2013,6 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work)
int ret = 0;
unsigned int reg, reg_start, reg_end;
u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0;
- struct timeval t;
enum rdwr_status stat;
u32 memory_size;
static char *env[] = { "DRIVER=mwifiex_sdio", "EVENT=fw_dump", NULL };
@@ -2033,9 +2033,7 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work)
mwifiex_pm_wakeup_card(adapter);
sdio_claim_host(card->func);
- do_gettimeofday(&t);
- dev_info(adapter->dev, "== mwifiex firmware dump start: %u.%06u ==\n",
- (u32)t.tv_sec, (u32)t.tv_usec);
+ dev_info(adapter->dev, "== mwifiex firmware dump start ==\n");
stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag);
if (stat == RDWR_STATUS_FAILURE)
@@ -2087,9 +2085,8 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work)
end_ptr = dbg_ptr + memory_size;
doneflag = entry->done_flag;
- do_gettimeofday(&t);
- dev_info(adapter->dev, "Start %s output %u.%06u, please wait...\n",
- entry->mem_name, (u32)t.tv_sec, (u32)t.tv_usec);
+ dev_info(adapter->dev, "Start %s output, please wait...\n",
+ entry->mem_name);
do {
stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag);
@@ -2120,9 +2117,7 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work)
break;
} while (1);
}
- do_gettimeofday(&t);
- dev_info(adapter->dev, "== mwifiex firmware dump end: %u.%06u ==\n",
- (u32)t.tv_sec, (u32)t.tv_usec);
+ dev_info(adapter->dev, "== mwifiex firmware dump end ==\n");
kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env);
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 0f077aaadab6..733de92a4c61 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -1647,7 +1647,7 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv,
timeout = (void *)(pos + config_len);
timeout->header.type = cpu_to_le16(TLV_TYPE_TDLS_IDLE_TIMEOUT);
timeout->header.len = cpu_to_le16(sizeof(timeout->value));
- timeout->value = cpu_to_le16(MWIFIEX_TDLS_IDLE_TIMEOUT);
+ timeout->value = cpu_to_le16(MWIFIEX_TDLS_IDLE_TIMEOUT_IN_SEC);
config_len += sizeof(struct mwifiex_ie_types_tdls_idle_timeout);
break;
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 822357b7b0bb..08b78baeb846 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -908,7 +908,7 @@ static int mwifiex_ret_tdls_oper(struct mwifiex_private *priv,
break;
default:
dev_err(priv->adapter->dev,
- "Unknown TDLS command action respnse %d", action);
+ "Unknown TDLS command action response %d", action);
return -1;
}
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 1a03d4d8b418..caae9738100a 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -283,10 +283,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
u8 config_bands;
- ret = mwifiex_deauthenticate(priv, NULL);
- if (ret)
- goto done;
-
if (!bss_desc)
return -1;
@@ -345,12 +341,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
goto done;
}
- /* Exit Adhoc mode first */
- dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n");
- ret = mwifiex_deauthenticate(priv, NULL);
- if (ret)
- goto done;
-
priv->adhoc_is_link_sensed = false;
ret = mwifiex_check_network_compatibility(priv, bss_desc);
diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c
index a414161c6064..4c5fd953893d 100644
--- a/drivers/net/wireless/mwifiex/tdls.c
+++ b/drivers/net/wireless/mwifiex/tdls.c
@@ -781,6 +781,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
struct mwifiex_sta_node *sta_ptr;
u8 *peer, *pos, *end;
u8 i, action, basic;
+ __le16 cap = 0;
int ie_len = 0;
if (len < (sizeof(struct ethhdr) + 3))
@@ -792,18 +793,9 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
peer = buf + ETH_ALEN;
action = *(buf + sizeof(struct ethhdr) + 2);
-
- /* just handle TDLS setup request/response/confirm */
- if (action > WLAN_TDLS_SETUP_CONFIRM)
- return;
-
dev_dbg(priv->adapter->dev,
"rx:tdls action: peer=%pM, action=%d\n", peer, action);
- sta_ptr = mwifiex_add_sta_entry(priv, peer);
- if (!sta_ptr)
- return;
-
switch (action) {
case WLAN_TDLS_SETUP_REQUEST:
if (len < (sizeof(struct ethhdr) + TDLS_REQ_FIX_LEN))
@@ -811,7 +803,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
pos = buf + sizeof(struct ethhdr) + 4;
/* payload 1+ category 1 + action 1 + dialog 1 */
- sta_ptr->tdls_cap.capab = cpu_to_le16(*(u16 *)pos);
+ cap = cpu_to_le16(*(u16 *)pos);
ie_len = len - sizeof(struct ethhdr) - TDLS_REQ_FIX_LEN;
pos += 2;
break;
@@ -821,7 +813,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
return;
/* payload 1+ category 1 + action 1 + dialog 1 + status code 2*/
pos = buf + sizeof(struct ethhdr) + 6;
- sta_ptr->tdls_cap.capab = cpu_to_le16(*(u16 *)pos);
+ cap = cpu_to_le16(*(u16 *)pos);
ie_len = len - sizeof(struct ethhdr) - TDLS_RESP_FIX_LEN;
pos += 2;
break;
@@ -833,10 +825,16 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
ie_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN;
break;
default:
- dev_warn(priv->adapter->dev, "Unknown TDLS frame type.\n");
+ dev_dbg(priv->adapter->dev, "Unknown TDLS frame type.\n");
return;
}
+ sta_ptr = mwifiex_add_sta_entry(priv, peer);
+ if (!sta_ptr)
+ return;
+
+ sta_ptr->tdls_cap.capab = cap;
+
for (end = pos + ie_len; pos + 1 < end; pos += 2 + pos[1]) {
if (pos + 2 + pos[1] > end)
break;
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 832006b5aab1..573897b8e878 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -1284,6 +1284,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
/* Arcadyan */
{ USB_DEVICE(0x043e, 0x7a12) },
{ USB_DEVICE(0x043e, 0x7a32) },
+ /* ASUS */
+ { USB_DEVICE(0x0b05, 0x17e8) },
/* Azurewave */
{ USB_DEVICE(0x13d3, 0x3329) },
{ USB_DEVICE(0x13d3, 0x3365) },
@@ -1320,6 +1322,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x057c, 0x8501) },
/* Buffalo */
{ USB_DEVICE(0x0411, 0x0241) },
+ { USB_DEVICE(0x0411, 0x0253) },
/* D-Link */
{ USB_DEVICE(0x2001, 0x3c1a) },
{ USB_DEVICE(0x2001, 0x3c21) },
@@ -1410,6 +1413,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x0df6, 0x0053) },
{ USB_DEVICE(0x0df6, 0x0069) },
{ USB_DEVICE(0x0df6, 0x006f) },
+ { USB_DEVICE(0x0df6, 0x0078) },
/* SMC */
{ USB_DEVICE(0x083a, 0xa512) },
{ USB_DEVICE(0x083a, 0xc522) },
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index d50dfac91631..0bccf123831e 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -1668,7 +1668,7 @@ static bool wl12xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
{
u8 thold;
- if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map))
+ if (test_bit(hlid, &wl->fw_fast_lnk_map))
thold = wl->conf.tx.fast_link_thold;
else
thold = wl->conf.tx.slow_link_thold;
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c
index 7649c75cd68d..44f0b205b065 100644
--- a/drivers/net/wireless/ti/wl18xx/cmd.c
+++ b/drivers/net/wireless/ti/wl18xx/cmd.c
@@ -78,3 +78,92 @@ out_free:
out:
return ret;
}
+
+int wl18xx_cmd_smart_config_start(struct wl1271 *wl, u32 group_bitmap)
+{
+ struct wl18xx_cmd_smart_config_start *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd smart config start group_bitmap=0x%x",
+ group_bitmap);
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->group_id_bitmask = cpu_to_le32(group_bitmap);
+
+ ret = wl1271_cmd_send(wl, CMD_SMART_CONFIG_START, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send smart config start command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+out:
+ return ret;
+}
+
+int wl18xx_cmd_smart_config_stop(struct wl1271 *wl)
+{
+ struct wl1271_cmd_header *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd smart config stop");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1271_cmd_send(wl, CMD_SMART_CONFIG_STOP, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send smart config stop command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+out:
+ return ret;
+}
+
+int wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id,
+ u8 key_len, u8 *key)
+{
+ struct wl18xx_cmd_smart_config_set_group_key *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd smart config set group key id=0x%x",
+ group_id);
+
+ if (key_len != sizeof(cmd->key)) {
+ wl1271_error("invalid group key size: %d", key_len);
+ return -E2BIG;
+ }
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->group_id = cpu_to_le32(group_id);
+ memcpy(cmd->key, key, key_len);
+
+ ret = wl1271_cmd_send(wl, CMD_SMART_CONFIG_SET_GROUP_KEY, cmd,
+ sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send smart config set group key cmd");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+out:
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h
index 6687d10899ac..92499e2dfa83 100644
--- a/drivers/net/wireless/ti/wl18xx/cmd.h
+++ b/drivers/net/wireless/ti/wl18xx/cmd.h
@@ -45,8 +45,25 @@ struct wl18xx_cmd_channel_switch {
u8 padding[2];
} __packed;
+struct wl18xx_cmd_smart_config_start {
+ struct wl1271_cmd_header header;
+
+ __le32 group_id_bitmask;
+} __packed;
+
+struct wl18xx_cmd_smart_config_set_group_key {
+ struct wl1271_cmd_header header;
+
+ __le32 group_id;
+
+ u8 key[16];
+} __packed;
+
int wl18xx_cmd_channel_switch(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch);
-
+int wl18xx_cmd_smart_config_start(struct wl1271 *wl, u32 group_bitmap);
+int wl18xx_cmd_smart_config_stop(struct wl1271 *wl);
+int wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id,
+ u8 key_len, u8 *key);
#endif
diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c
index c9199d7804c6..eb1848e08424 100644
--- a/drivers/net/wireless/ti/wl18xx/event.c
+++ b/drivers/net/wireless/ti/wl18xx/event.c
@@ -19,10 +19,12 @@
*
*/
+#include <net/genetlink.h>
#include "event.h"
#include "scan.h"
#include "../wlcore/cmd.h"
#include "../wlcore/debug.h"
+#include "../wlcore/vendor_cmd.h"
int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
bool *timeout)
@@ -45,6 +47,58 @@ int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout);
}
+static int wlcore_smart_config_sync_event(struct wl1271 *wl, u8 sync_channel,
+ u8 sync_band)
+{
+ struct sk_buff *skb;
+ enum ieee80211_band band;
+ int freq;
+
+ if (sync_band == WLCORE_BAND_5GHZ)
+ band = IEEE80211_BAND_5GHZ;
+ else
+ band = IEEE80211_BAND_2GHZ;
+
+ freq = ieee80211_channel_to_frequency(sync_channel, band);
+
+ wl1271_debug(DEBUG_EVENT,
+ "SMART_CONFIG_SYNC_EVENT_ID, freq: %d (chan: %d band %d)",
+ freq, sync_channel, sync_band);
+ skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, 20,
+ WLCORE_VENDOR_EVENT_SC_SYNC,
+ GFP_KERNEL);
+
+ if (nla_put_u32(skb, WLCORE_VENDOR_ATTR_FREQ, freq)) {
+ kfree_skb(skb);
+ return -EMSGSIZE;
+ }
+ cfg80211_vendor_event(skb, GFP_KERNEL);
+ return 0;
+}
+
+static int wlcore_smart_config_decode_event(struct wl1271 *wl,
+ u8 ssid_len, u8 *ssid,
+ u8 pwd_len, u8 *pwd)
+{
+ struct sk_buff *skb;
+
+ wl1271_debug(DEBUG_EVENT, "SMART_CONFIG_DECODE_EVENT_ID");
+ wl1271_dump_ascii(DEBUG_EVENT, "SSID:", ssid, ssid_len);
+
+ skb = cfg80211_vendor_event_alloc(wl->hw->wiphy,
+ ssid_len + pwd_len + 20,
+ WLCORE_VENDOR_EVENT_SC_DECODE,
+ GFP_KERNEL);
+
+ if (nla_put(skb, WLCORE_VENDOR_ATTR_SSID, ssid_len, ssid) ||
+ nla_put(skb, WLCORE_VENDOR_ATTR_PSK, pwd_len, pwd)) {
+ kfree_skb(skb);
+ return -EMSGSIZE;
+ }
+ cfg80211_vendor_event(skb, GFP_KERNEL);
+ return 0;
+}
+
int wl18xx_process_mailbox_events(struct wl1271 *wl)
{
struct wl18xx_event_mailbox *mbox = wl->mbox;
@@ -107,5 +161,16 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl)
if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID)
wlcore_event_roc_complete(wl);
+ if (vector & SMART_CONFIG_SYNC_EVENT_ID)
+ wlcore_smart_config_sync_event(wl, mbox->sc_sync_channel,
+ mbox->sc_sync_band);
+
+ if (vector & SMART_CONFIG_DECODE_EVENT_ID)
+ wlcore_smart_config_decode_event(wl,
+ mbox->sc_ssid_len,
+ mbox->sc_ssid,
+ mbox->sc_pwd_len,
+ mbox->sc_pwd);
+
return 0;
}
diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h
index a76e98eb8372..0680312d4943 100644
--- a/drivers/net/wireless/ti/wl18xx/event.h
+++ b/drivers/net/wireless/ti/wl18xx/event.h
@@ -38,6 +38,8 @@ enum {
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(18),
DFS_CHANNELS_CONFIG_COMPLETE_EVENT = BIT(19),
PERIODIC_SCAN_REPORT_EVENT_ID = BIT(20),
+ SMART_CONFIG_SYNC_EVENT_ID = BIT(22),
+ SMART_CONFIG_DECODE_EVENT_ID = BIT(23),
};
struct wl18xx_event_mailbox {
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index de5b4fa5d166..7af1936719eb 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -992,7 +992,10 @@ static int wl18xx_boot(struct wl1271 *wl)
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
INACTIVE_STA_EVENT_ID |
CHANNEL_SWITCH_COMPLETE_EVENT_ID |
- DFS_CHANNELS_CONFIG_COMPLETE_EVENT;
+ DFS_CHANNELS_CONFIG_COMPLETE_EVENT |
+ SMART_CONFIG_SYNC_EVENT_ID |
+ SMART_CONFIG_DECODE_EVENT_ID;
+;
wl->ap_event_mask = MAX_TX_FAILURE_EVENT_ID;
@@ -1606,15 +1609,20 @@ static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
u8 thold;
struct wl18xx_fw_status_priv *status_priv =
(struct wl18xx_fw_status_priv *)wl->fw_status->priv;
- u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
+ unsigned long suspend_bitmap;
+
+ /* if we don't have the link map yet, assume they all low prio */
+ if (!status_priv)
+ return false;
/* suspended links are never high priority */
- if (test_bit(hlid, (unsigned long *)&suspend_bitmap))
+ suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
+ if (test_bit(hlid, &suspend_bitmap))
return false;
/* the priority thresholds are taken from FW */
- if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) &&
- !test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map))
+ if (test_bit(hlid, &wl->fw_fast_lnk_map) &&
+ !test_bit(hlid, &wl->ap_fw_ps_map))
thold = status_priv->tx_fast_link_prio_threshold;
else
thold = status_priv->tx_slow_link_prio_threshold;
@@ -1628,12 +1636,17 @@ static bool wl18xx_lnk_low_prio(struct wl1271 *wl, u8 hlid,
u8 thold;
struct wl18xx_fw_status_priv *status_priv =
(struct wl18xx_fw_status_priv *)wl->fw_status->priv;
- u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
+ unsigned long suspend_bitmap;
+
+ /* if we don't have the link map yet, assume they all low prio */
+ if (!status_priv)
+ return true;
- if (test_bit(hlid, (unsigned long *)&suspend_bitmap))
+ suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
+ if (test_bit(hlid, &suspend_bitmap))
thold = status_priv->tx_suspend_threshold;
- else if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) &&
- !test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map))
+ else if (test_bit(hlid, &wl->fw_fast_lnk_map) &&
+ !test_bit(hlid, &wl->ap_fw_ps_map))
thold = status_priv->tx_fast_stop_threshold;
else
thold = status_priv->tx_slow_stop_threshold;
@@ -1687,6 +1700,9 @@ static struct wlcore_ops wl18xx_ops = {
.convert_hwaddr = wl18xx_convert_hwaddr,
.lnk_high_prio = wl18xx_lnk_high_prio,
.lnk_low_prio = wl18xx_lnk_low_prio,
+ .smart_config_start = wl18xx_cmd_smart_config_start,
+ .smart_config_stop = wl18xx_cmd_smart_config_stop,
+ .smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key,
};
/* HT cap appropriate for wide channels in 2Ghz */
diff --git a/drivers/net/wireless/ti/wl18xx/tx.c b/drivers/net/wireless/ti/wl18xx/tx.c
index be1ebd55ac88..3406ffb53325 100644
--- a/drivers/net/wireless/ti/wl18xx/tx.c
+++ b/drivers/net/wireless/ti/wl18xx/tx.c
@@ -30,7 +30,7 @@
static
void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif,
- struct ieee80211_tx_rate *rate)
+ u8 band, struct ieee80211_tx_rate *rate)
{
u8 fw_rate = wl->fw_status->counters.tx_last_rate;
@@ -43,6 +43,8 @@ void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif,
if (fw_rate <= CONF_HW_RATE_INDEX_54MBPS) {
rate->idx = fw_rate;
+ if (band == IEEE80211_BAND_5GHZ)
+ rate->idx -= CONF_HW_RATE_INDEX_6MBPS;
rate->flags = 0;
} else {
rate->flags = IEEE80211_TX_RC_MCS;
@@ -102,7 +104,8 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
* first pass info->control.vif while it's valid, and then fill out
* the info->status structures
*/
- wl18xx_get_last_tx_rate(wl, info->control.vif, &info->status.rates[0]);
+ wl18xx_get_last_tx_rate(wl, info->control.vif,
+ info->band, &info->status.rates[0]);
info->status.rates[0].count = 1; /* no data about retries */
info->status.ack_signal = -1;
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h
index eb7cfe817010..6a2b88030c1d 100644
--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
+++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
@@ -38,7 +38,7 @@
#define WL18XX_NUM_TX_DESCRIPTORS 32
#define WL18XX_NUM_RX_DESCRIPTORS 32
-#define WL18XX_NUM_MAC_ADDRESSES 3
+#define WL18XX_NUM_MAC_ADDRESSES 2
#define WL18XX_RX_BA_MAX_SESSIONS 13
diff --git a/drivers/net/wireless/ti/wlcore/Makefile b/drivers/net/wireless/ti/wlcore/Makefile
index 4f23931d7bd5..0a69c1373643 100644
--- a/drivers/net/wireless/ti/wlcore/Makefile
+++ b/drivers/net/wireless/ti/wlcore/Makefile
@@ -1,5 +1,5 @@
wlcore-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \
- boot.o init.o debugfs.o scan.o sysfs.o
+ boot.o init.o debugfs.o scan.o sysfs.o vendor_cmd.o
wlcore_spi-objs = spi.o
wlcore_sdio-objs = sdio.o
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index e269c0a57017..05604ee31224 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -372,9 +372,9 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
wl1271_tx_reset_link_queues(wl, *hlid);
wl->links[*hlid].wlvif = NULL;
- if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
- (wlvif->bss_type == BSS_TYPE_AP_BSS &&
- *hlid == wlvif->ap.bcast_hlid)) {
+ if (wlvif->bss_type == BSS_TYPE_AP_BSS &&
+ *hlid == wlvif->ap.bcast_hlid) {
+ u32 sqn_padding = WL1271_TX_SQN_POST_RECOVERY_PADDING;
/*
* save the total freed packets in the wlvif, in case this is
* recovery or suspend
@@ -385,9 +385,11 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
* increment the initial seq number on recovery to account for
* transmitted packets that we haven't yet got in the FW status
*/
+ if (wlvif->encryption_type == KEY_GEM)
+ sqn_padding = WL1271_TX_SQN_POST_RECOVERY_PADDING_GEM;
+
if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
- wlvif->total_freed_pkts +=
- WL1271_TX_SQN_POST_RECOVERY_PADDING;
+ wlvif->total_freed_pkts += sqn_padding;
}
wl->links[*hlid].total_freed_pkts = 0;
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h
index 6788d7356ca5..ca6a28b03f8f 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.h
+++ b/drivers/net/wireless/ti/wlcore/cmd.h
@@ -170,6 +170,9 @@ enum wl1271_commands {
/* start of 18xx specific commands */
CMD_DFS_CHANNEL_CONFIG = 60,
+ CMD_SMART_CONFIG_START = 61,
+ CMD_SMART_CONFIG_STOP = 62,
+ CMD_SMART_CONFIG_SET_GROUP_KEY = 63,
MAX_COMMAND_ID = 0xFFFF,
};
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c
index 89893c717025..0be21f62fcb0 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.c
+++ b/drivers/net/wireless/ti/wlcore/debugfs.c
@@ -496,7 +496,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
DRIVER_STATE_PRINT_INT(sg_enabled);
DRIVER_STATE_PRINT_INT(enable_11a);
DRIVER_STATE_PRINT_INT(noise);
- DRIVER_STATE_PRINT_HEX(ap_fw_ps_map);
+ DRIVER_STATE_PRINT_LHEX(ap_fw_ps_map);
DRIVER_STATE_PRINT_LHEX(ap_ps_map);
DRIVER_STATE_PRINT_HEX(quirks);
DRIVER_STATE_PRINT_HEX(irq);
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index 1555ff970050..aa9f82c72296 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -260,4 +260,31 @@ wlcore_hw_lnk_low_prio(struct wl1271 *wl, u8 hlid,
return wl->ops->lnk_low_prio(wl, hlid, lnk);
}
+static inline int
+wlcore_smart_config_start(struct wl1271 *wl, u32 group_bitmap)
+{
+ if (!wl->ops->smart_config_start)
+ return -EINVAL;
+
+ return wl->ops->smart_config_start(wl, group_bitmap);
+}
+
+static inline int
+wlcore_smart_config_stop(struct wl1271 *wl)
+{
+ if (!wl->ops->smart_config_stop)
+ return -EINVAL;
+
+ return wl->ops->smart_config_stop(wl);
+}
+
+static inline int
+wlcore_smart_config_set_group_key(struct wl1271 *wl, u16 group_id,
+ u8 key_len, u8 *key)
+{
+ if (!wl->ops->smart_config_set_group_key)
+ return -EINVAL;
+
+ return wl->ops->smart_config_set_group_key(wl, group_id, key_len, key);
+}
#endif
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 48f83868f9cb..575c8f6d4009 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -37,6 +37,7 @@
#include "init.h"
#include "debugfs.h"
#include "testmode.h"
+#include "vendor_cmd.h"
#include "scan.h"
#include "hw_ops.h"
#include "sysfs.h"
@@ -332,7 +333,7 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
{
bool fw_ps;
- fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
+ fw_ps = test_bit(hlid, &wl->ap_fw_ps_map);
/*
* Wake up from high level PS if the STA is asleep with too little
@@ -359,13 +360,13 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct wl_fw_status *status)
{
- u32 cur_fw_ps_map;
+ unsigned long cur_fw_ps_map;
u8 hlid;
cur_fw_ps_map = status->link_ps_bitmap;
if (wl->ap_fw_ps_map != cur_fw_ps_map) {
wl1271_debug(DEBUG_PSM,
- "link ps prev 0x%x cur 0x%x changed 0x%x",
+ "link ps prev 0x%lx cur 0x%lx changed 0x%lx",
wl->ap_fw_ps_map, cur_fw_ps_map,
wl->ap_fw_ps_map ^ cur_fw_ps_map);
@@ -898,6 +899,44 @@ out:
wlcore_set_partition(wl, &old_part);
}
+static void wlcore_save_freed_pkts(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 hlid, struct ieee80211_sta *sta)
+{
+ struct wl1271_station *wl_sta;
+ u32 sqn_recovery_padding = WL1271_TX_SQN_POST_RECOVERY_PADDING;
+
+ wl_sta = (void *)sta->drv_priv;
+ wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts;
+
+ /*
+ * increment the initial seq number on recovery to account for
+ * transmitted packets that we haven't yet got in the FW status
+ */
+ if (wlvif->encryption_type == KEY_GEM)
+ sqn_recovery_padding = WL1271_TX_SQN_POST_RECOVERY_PADDING_GEM;
+
+ if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
+ wl_sta->total_freed_pkts += sqn_recovery_padding;
+}
+
+static void wlcore_save_freed_pkts_addr(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ u8 hlid, const u8 *addr)
+{
+ struct ieee80211_sta *sta;
+ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+
+ if (WARN_ON(hlid == WL12XX_INVALID_LINK_ID ||
+ is_zero_ether_addr(addr)))
+ return;
+
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, addr);
+ if (sta)
+ wlcore_save_freed_pkts(wl, wlvif, hlid, sta);
+ rcu_read_unlock();
+}
+
static void wlcore_print_recovery(struct wl1271 *wl)
{
u32 pc = 0;
@@ -961,6 +1000,13 @@ static void wl1271_recovery_work(struct work_struct *work)
wlvif = list_first_entry(&wl->wlvif_list,
struct wl12xx_vif, list);
vif = wl12xx_wlvif_to_vif(wlvif);
+
+ if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
+ test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
+ wlcore_save_freed_pkts_addr(wl, wlvif, wlvif->sta.hlid,
+ vif->bss_conf.bssid);
+ }
+
__wl1271_op_remove_interface(wl, vif, false);
}
@@ -4703,36 +4749,18 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
{
- struct wl1271_station *wl_sta;
- struct ieee80211_sta *sta;
- struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
-
if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
return;
clear_bit(hlid, wlvif->ap.sta_hlid_map);
__clear_bit(hlid, &wl->ap_ps_map);
- __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
+ __clear_bit(hlid, &wl->ap_fw_ps_map);
/*
* save the last used PN in the private part of iee80211_sta,
* in case of recovery/suspend
*/
- rcu_read_lock();
- sta = ieee80211_find_sta(vif, wl->links[hlid].addr);
- if (sta) {
- wl_sta = (void *)sta->drv_priv;
- wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts;
-
- /*
- * increment the initial seq number on recovery to account for
- * transmitted packets that we haven't yet got in the FW status
- */
- if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
- wl_sta->total_freed_pkts +=
- WL1271_TX_SQN_POST_RECOVERY_PADDING;
- }
- rcu_read_unlock();
+ wlcore_save_freed_pkts_addr(wl, wlvif, hlid, wl->links[hlid].addr);
wl12xx_free_link(wl, wlvif, &hlid);
wl->active_sta_count--;
@@ -4915,6 +4943,21 @@ static int wl12xx_update_sta_state(struct wl1271 *wl,
clear_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags);
}
+ /* save seq number on disassoc (suspend) */
+ if (is_sta &&
+ old_state == IEEE80211_STA_ASSOC &&
+ new_state == IEEE80211_STA_AUTH) {
+ wlcore_save_freed_pkts(wl, wlvif, wlvif->sta.hlid, sta);
+ wlvif->total_freed_pkts = 0;
+ }
+
+ /* restore seq number on assoc (resume) */
+ if (is_sta &&
+ old_state == IEEE80211_STA_AUTH &&
+ new_state == IEEE80211_STA_ASSOC) {
+ wlvif->total_freed_pkts = wl_sta->total_freed_pkts;
+ }
+
/* clear ROCs on failure or authorization */
if (is_sta &&
(new_state == IEEE80211_STA_AUTHORIZED ||
@@ -5149,6 +5192,10 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
if (unlikely(wl->state == WLCORE_STATE_OFF)) {
wl12xx_for_each_wlvif_sta(wl, wlvif) {
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+
+ if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+ continue;
+
ieee80211_chswitch_done(vif, false);
}
goto out;
@@ -5164,6 +5211,9 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
wl12xx_for_each_wlvif_sta(wl, wlvif) {
unsigned long delay_usec;
+ if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+ continue;
+
ret = wl->ops->channel_switch(wl, wlvif, ch_switch);
if (ret)
goto out_sleep;
@@ -5619,7 +5669,7 @@ static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic)
memcpy(&wl->addresses[idx], &wl->addresses[0],
sizeof(wl->addresses[0]));
/* LAA bit */
- wl->addresses[idx].addr[2] |= BIT(1);
+ wl->addresses[idx].addr[0] |= BIT(1);
}
wl->hw->wiphy->n_addresses = WLCORE_NUM_MAC_ADDRESSES;
@@ -5764,7 +5814,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
sizeof(struct ieee80211_header);
- wl->hw->wiphy->max_remain_on_channel_duration = 5000;
+ wl->hw->wiphy->max_remain_on_channel_duration = 30000;
wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
@@ -5833,6 +5883,9 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->wiphy->iface_combinations = wl->iface_combinations;
wl->hw->wiphy->n_iface_combinations = wl->n_iface_combinations;
+ /* register vendor commands */
+ wlcore_set_vendor_commands(wl->hw->wiphy);
+
SET_IEEE80211_DEV(wl->hw, wl->dev);
wl->hw->sta_data_size = sizeof(struct wl1271_station);
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index 40b43115f835..f0ac36139bcc 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -126,7 +126,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
if (WARN_ON(!test_bit(hlid, wlvif->links_map)))
return;
- fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
+ fw_ps = test_bit(hlid, &wl->ap_fw_ps_map);
tx_pkts = wl->links[hlid].allocated_pkts;
/*
diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c
new file mode 100644
index 000000000000..ad86a48dcfcb
--- /dev/null
+++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c
@@ -0,0 +1,197 @@
+/*
+ * This file is part of wlcore
+ *
+ * Copyright (C) 2014 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <net/mac80211.h>
+#include <net/netlink.h>
+
+#include "wlcore.h"
+#include "debug.h"
+#include "ps.h"
+#include "hw_ops.h"
+#include "vendor_cmd.h"
+
+static const
+struct nla_policy wlcore_vendor_attr_policy[NUM_WLCORE_VENDOR_ATTR] = {
+ [WLCORE_VENDOR_ATTR_FREQ] = { .type = NLA_U32 },
+ [WLCORE_VENDOR_ATTR_GROUP_ID] = { .type = NLA_U32 },
+ [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_U32,
+ .len = WLAN_MAX_KEY_LEN },
+};
+
+static int
+wlcore_vendor_cmd_smart_config_start(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct wl1271 *wl = hw->priv;
+ struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR];
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "vendor cmd smart config start");
+
+ if (!data)
+ return -EINVAL;
+
+ ret = nla_parse(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len,
+ wlcore_vendor_attr_policy);
+ if (ret)
+ return ret;
+
+ if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID])
+ return -EINVAL;
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wlcore_smart_config_start(wl,
+ nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]));
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+
+ return 0;
+}
+
+static int
+wlcore_vendor_cmd_smart_config_stop(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct wl1271 *wl = hw->priv;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "testmode cmd smart config stop");
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wlcore_smart_config_stop(wl);
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+static int
+wlcore_vendor_cmd_smart_config_set_group_key(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct wl1271 *wl = hw->priv;
+ struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR];
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "testmode cmd smart config set group key");
+
+ if (!data)
+ return -EINVAL;
+
+ ret = nla_parse(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len,
+ wlcore_vendor_attr_policy);
+ if (ret)
+ return ret;
+
+ if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID] ||
+ !tb[WLCORE_VENDOR_ATTR_GROUP_KEY])
+ return -EINVAL;
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wlcore_smart_config_set_group_key(wl,
+ nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]),
+ nla_len(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]),
+ nla_data(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]));
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+static const struct wiphy_vendor_command wlcore_vendor_commands[] = {
+ {
+ .info = {
+ .vendor_id = TI_OUI,
+ .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_START,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wlcore_vendor_cmd_smart_config_start,
+ },
+ {
+ .info = {
+ .vendor_id = TI_OUI,
+ .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_STOP,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wlcore_vendor_cmd_smart_config_stop,
+ },
+ {
+ .info = {
+ .vendor_id = TI_OUI,
+ .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_SET_GROUP_KEY,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wlcore_vendor_cmd_smart_config_set_group_key,
+ },
+};
+
+static const struct nl80211_vendor_cmd_info wlcore_vendor_events[] = {
+ {
+ .vendor_id = TI_OUI,
+ .subcmd = WLCORE_VENDOR_EVENT_SC_SYNC,
+ },
+ {
+ .vendor_id = TI_OUI,
+ .subcmd = WLCORE_VENDOR_EVENT_SC_DECODE,
+ },
+};
+
+void wlcore_set_vendor_commands(struct wiphy *wiphy)
+{
+ wiphy->vendor_commands = wlcore_vendor_commands;
+ wiphy->n_vendor_commands = ARRAY_SIZE(wlcore_vendor_commands);
+ wiphy->vendor_events = wlcore_vendor_events;
+ wiphy->n_vendor_events = ARRAY_SIZE(wlcore_vendor_events);
+}
diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.h b/drivers/net/wireless/ti/wlcore/vendor_cmd.h
new file mode 100644
index 000000000000..6e0c15e30f03
--- /dev/null
+++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of wlcore
+ *
+ * Copyright (C) 2014 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef __WLCORE_VENDOR_H__
+#define __WLCORE_VENDOR_H__
+
+#ifdef __KERNEL__
+void wlcore_set_vendor_commands(struct wiphy *wiphy);
+#endif
+
+#define TI_OUI 0x080028
+
+enum wlcore_vendor_commands {
+ WLCORE_VENDOR_CMD_SMART_CONFIG_START,
+ WLCORE_VENDOR_CMD_SMART_CONFIG_STOP,
+ WLCORE_VENDOR_CMD_SMART_CONFIG_SET_GROUP_KEY,
+
+ NUM_WLCORE_VENDOR_CMD,
+ MAX_WLCORE_VENDOR_CMD = NUM_WLCORE_VENDOR_CMD - 1
+};
+
+enum wlcore_vendor_attributes {
+ WLCORE_VENDOR_ATTR_FREQ,
+ WLCORE_VENDOR_ATTR_PSK,
+ WLCORE_VENDOR_ATTR_SSID,
+ WLCORE_VENDOR_ATTR_GROUP_ID,
+ WLCORE_VENDOR_ATTR_GROUP_KEY,
+
+ NUM_WLCORE_VENDOR_ATTR,
+ MAX_WLCORE_VENDOR_ATTR = NUM_WLCORE_VENDOR_ATTR - 1
+};
+
+enum wlcore_vendor_events {
+ WLCORE_VENDOR_EVENT_SC_SYNC,
+ WLCORE_VENDOR_EVENT_SC_DECODE,
+};
+
+#endif /* __WLCORE_VENDOR_H__ */
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index 71320509b56d..df78cf12ef15 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -117,6 +117,10 @@ struct wlcore_ops {
struct wl1271_link *lnk);
bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid,
struct wl1271_link *lnk);
+ int (*smart_config_start)(struct wl1271 *wl, u32 group_bitmap);
+ int (*smart_config_stop)(struct wl1271 *wl);
+ int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id,
+ u8 key_len, u8 *key);
};
enum wlcore_partitions {
@@ -384,10 +388,10 @@ struct wl1271 {
int active_link_count;
/* Fast/slow links bitmap according to FW */
- u32 fw_fast_lnk_map;
+ unsigned long fw_fast_lnk_map;
/* AP-mode - a bitmap of links currently in PS mode according to FW */
- u32 ap_fw_ps_map;
+ unsigned long ap_fw_ps_map;
/* AP-mode - a bitmap of links currently in PS mode in mac80211 */
unsigned long ap_ps_map;
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index c2c34a84ff3d..0e52556044d9 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -45,6 +45,9 @@
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
#define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff
+/* Use smaller padding for GEM, as some APs have issues when it's too big */
+#define WL1271_TX_SQN_POST_RECOVERY_PADDING_GEM 0x20
+
#define WL1271_CIPHER_SUITE_GEM 0x00147201
@@ -324,6 +327,7 @@ struct wl1271_station {
* total freed FW packets on the link to the STA - used for tracking the
* AES/TKIP PN across recoveries. Re-initialized each time from the
* wl1271_station structure.
+ * Used in both AP and STA mode.
*/
u64 total_freed_pkts;
};
@@ -460,21 +464,19 @@ struct wl12xx_vif {
struct delayed_work pending_auth_complete_work;
/*
+ * total freed FW packets on the link.
+ * For STA this holds the PN of the link to the AP.
+ * For AP this holds the PN of the broadcast link.
+ */
+ u64 total_freed_pkts;
+
+ /*
* This struct must be last!
* data that has to be saved acrossed reconfigs (e.g. recovery)
* should be declared in this struct.
*/
struct {
u8 persistent[0];
-
- /*
- * total freed FW packets on the link - used for
- * storing the AES/TKIP PN during recovery, as this
- * structure is not zeroed out.
- * For STA this holds the PN of the link to the AP.
- * For AP this holds the PN of the broadcast link.
- */
- u64 total_freed_pkts;
};
};
diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig
index 96c8e1de0879..95920581860a 100644
--- a/drivers/net/wireless/zd1211rw/Kconfig
+++ b/drivers/net/wireless/zd1211rw/Kconfig
@@ -3,11 +3,11 @@ config ZD1211RW
depends on USB && MAC80211
select FW_LOADER
---help---
- This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless
+ This is a driver for the ZyDAS ZD1211/ZD1211B wireless
chip, present in many USB-wireless adapters.
Device firmware is required alongside this driver. You can download
- the firmware distribution from http://zd1211.ath.cx/get-firmware
+ the firmware distribution from http://sf.net/projects/zd1211/files/
config ZD1211RW_DEBUG
bool "ZyDAS ZD1211 debugging"