diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-27 12:03:20 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-27 12:03:20 -0700 |
commit | 468fc7ed5537615efe671d94248446ac24679773 (patch) | |
tree | 27bc9de792e863d6ec1630927b77ac9e7dabb38a /drivers/net/wireless | |
parent | 08fd8c17686c6b09fa410a26d516548dd80ff147 (diff) | |
parent | 36232012344b8db67052432742deaf17f82e70e6 (diff) | |
download | linux-468fc7ed5537615efe671d94248446ac24679773.tar.bz2 |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller:
1) Unified UDP encapsulation offload methods for drivers, from
Alexander Duyck.
2) Make DSA binding more sane, from Andrew Lunn.
3) Support QCA9888 chips in ath10k, from Anilkumar Kolli.
4) Several workqueue usage cleanups, from Bhaktipriya Shridhar.
5) Add XDP (eXpress Data Path), essentially running BPF programs on RX
packets as soon as the device sees them, with the option to mirror
the packet on TX via the same interface. From Brenden Blanco and
others.
6) Allow qdisc/class stats dumps to run lockless, from Eric Dumazet.
7) Add VLAN support to b53 and bcm_sf2, from Florian Fainelli.
8) Simplify netlink conntrack entry layout, from Florian Westphal.
9) Add ipv4 forwarding support to mlxsw spectrum driver, from Ido
Schimmel, Yotam Gigi, and Jiri Pirko.
10) Add SKB array infrastructure and convert tun and macvtap over to it.
From Michael S Tsirkin and Jason Wang.
11) Support qdisc packet injection in pktgen, from John Fastabend.
12) Add neighbour monitoring framework to TIPC, from Jon Paul Maloy.
13) Add NV congestion control support to TCP, from Lawrence Brakmo.
14) Add GSO support to SCTP, from Marcelo Ricardo Leitner.
15) Allow GRO and RPS to function on macsec devices, from Paolo Abeni.
16) Support MPLS over IPV4, from Simon Horman.
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1622 commits)
xgene: Fix build warning with ACPI disabled.
be2net: perform temperature query in adapter regardless of its interface state
l2tp: Correctly return -EBADF from pppol2tp_getname.
net/mlx5_core/health: Remove deprecated create_singlethread_workqueue
net: ipmr/ip6mr: update lastuse on entry change
macsec: ensure rx_sa is set when validation is disabled
tipc: dump monitor attributes
tipc: add a function to get the bearer name
tipc: get monitor threshold for the cluster
tipc: make cluster size threshold for monitoring configurable
tipc: introduce constants for tipc address validation
net: neigh: disallow transition to NUD_STALE if lladdr is unchanged in neigh_update()
MAINTAINERS: xgene: Add driver and documentation path
Documentation: dtb: xgene: Add MDIO node
dtb: xgene: Add MDIO node
drivers: net: xgene: ethtool: Use phy_ethtool_gset and sset
drivers: net: xgene: Use exported functions
drivers: net: xgene: Enable MDIO driver
drivers: net: xgene: Add backward compatibility
drivers: net: phy: xgene: Add MDIO driver
...
Diffstat (limited to 'drivers/net/wireless')
279 files changed, 6320 insertions, 3938 deletions
diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index bd62bc19e758..acec16b9cf49 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -25,10 +25,9 @@ #include "ahb.h" static const struct of_device_id ath10k_ahb_of_match[] = { - /* TODO: enable this entry once everything in place. - * { .compatible = "qcom,ipq4019-wifi", - * .data = (void *)ATH10K_HW_QCA4019 }, - */ + { .compatible = "qcom,ipq4019-wifi", + .data = (void *)ATH10K_HW_QCA4019 + }, { } }; @@ -476,6 +475,7 @@ static irqreturn_t ath10k_ahb_interrupt_handler(int irq, void *arg) static int ath10k_ahb_request_irq_legacy(struct ath10k *ar) { + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); int ret; @@ -487,6 +487,7 @@ static int ath10k_ahb_request_irq_legacy(struct ath10k *ar) ar_ahb->irq, ret); return ret; } + ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_LEGACY; return 0; } @@ -918,8 +919,6 @@ int ath10k_ahb_init(void) { int ret; - printk(KERN_ERR "AHB support is still work in progress\n"); - ret = platform_driver_register(&ath10k_ahb_driver); if (ret) printk(KERN_ERR "failed to register ath10k ahb driver: %d\n", diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index a92a0ba829f5..e88982921aa3 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -18,6 +18,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/of.h> +#include <asm/byteorder.h> #include "core.h" #include "mac.h" @@ -55,7 +56,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca988x hw2.0", .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, - .has_shifted_cc_wraparound = true, + .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL, .otp_exe_param = 0, .channel_counters_freq_hz = 88000, .max_probe_resp_desc_thres = 0, @@ -69,6 +70,25 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, }, { + .id = QCA9887_HW_1_0_VERSION, + .dev_id = QCA9887_1_0_DEVICE_ID, + .name = "qca9887 hw1.0", + .patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR, + .uart_pin = 7, + .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL, + .otp_exe_param = 0, + .channel_counters_freq_hz = 88000, + .max_probe_resp_desc_thres = 0, + .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER, + .cal_data_len = 2116, + .fw = { + .dir = QCA9887_HW_1_0_FW_DIR, + .board = QCA9887_HW_1_0_BOARD_DATA_FILE, + .board_size = QCA9887_BOARD_DATA_SZ, + .board_ext_size = QCA9887_BOARD_EXT_DATA_SZ, + }, + }, + { .id = QCA6174_HW_2_1_VERSION, .dev_id = QCA6164_2_1_DEVICE_ID, .name = "qca6164 hw2.1", @@ -148,6 +168,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .uart_pin = 7, .otp_exe_param = 0x00000700, .continuous_frag_desc = true, + .cck_rate_map_rev2 = true, .channel_counters_freq_hz = 150000, .max_probe_resp_desc_thres = 24, .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE, @@ -163,6 +184,51 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, }, { + .id = QCA9984_HW_1_0_DEV_VERSION, + .dev_id = QCA9984_1_0_DEVICE_ID, + .name = "qca9984/qca9994 hw1.0", + .patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR, + .uart_pin = 7, + .otp_exe_param = 0x00000700, + .continuous_frag_desc = true, + .cck_rate_map_rev2 = true, + .channel_counters_freq_hz = 150000, + .max_probe_resp_desc_thres = 24, + .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE, + .tx_chain_mask = 0xf, + .rx_chain_mask = 0xf, + .max_spatial_stream = 4, + .cal_data_len = 12064, + .fw = { + .dir = QCA9984_HW_1_0_FW_DIR, + .board = QCA9984_HW_1_0_BOARD_DATA_FILE, + .board_size = QCA99X0_BOARD_DATA_SZ, + .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, + }, + }, + { + .id = QCA9888_HW_2_0_DEV_VERSION, + .dev_id = QCA9888_2_0_DEVICE_ID, + .name = "qca9888 hw2.0", + .patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR, + .uart_pin = 7, + .otp_exe_param = 0x00000700, + .continuous_frag_desc = true, + .channel_counters_freq_hz = 150000, + .max_probe_resp_desc_thres = 24, + .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE, + .tx_chain_mask = 3, + .rx_chain_mask = 3, + .max_spatial_stream = 2, + .cal_data_len = 12064, + .fw = { + .dir = QCA9888_HW_2_0_FW_DIR, + .board = QCA9888_HW_2_0_BOARD_DATA_FILE, + .board_size = QCA99X0_BOARD_DATA_SZ, + .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, + }, + }, + { .id = QCA9377_HW_1_0_DEV_VERSION, .dev_id = QCA9377_1_0_DEVICE_ID, .name = "qca9377 hw1.0", @@ -202,9 +268,10 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca4019 hw1.0", .patch_load_addr = QCA4019_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, - .has_shifted_cc_wraparound = true, + .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH, .otp_exe_param = 0x0010000, .continuous_frag_desc = true, + .cck_rate_map_rev2 = true, .channel_counters_freq_hz = 125000, .max_probe_resp_desc_thres = 24, .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE, @@ -236,6 +303,7 @@ static const char *const ath10k_core_fw_feature_str[] = { [ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca", [ATH10K_FW_FEATURE_MFP_SUPPORT] = "mfp", [ATH10K_FW_FEATURE_PEER_FLOW_CONTROL] = "peer-flow-ctrl", + [ATH10K_FW_FEATURE_BTCOEX_PARAM] = "btcoex-param", }; static unsigned int ath10k_core_get_fw_feature_str(char *buf, @@ -531,6 +599,35 @@ out: return ret; } +static int ath10k_download_cal_eeprom(struct ath10k *ar) +{ + size_t data_len; + void *data = NULL; + int ret; + + ret = ath10k_hif_fetch_cal_eeprom(ar, &data, &data_len); + if (ret) { + if (ret != -EOPNOTSUPP) + ath10k_warn(ar, "failed to read calibration data from EEPROM: %d\n", + ret); + goto out_free; + } + + ret = ath10k_download_board_data(ar, data, data_len); + if (ret) { + ath10k_warn(ar, "failed to download calibration data from EEPROM: %d\n", + ret); + goto out_free; + } + + ret = 0; + +out_free: + kfree(data); + + return ret; +} + static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) { u32 result, address; @@ -1293,7 +1390,17 @@ static int ath10k_download_cal_data(struct ath10k *ar) } ath10k_dbg(ar, ATH10K_DBG_BOOT, - "boot did not find DT entry, try OTP next: %d\n", + "boot did not find DT entry, try target EEPROM next: %d\n", + ret); + + ret = ath10k_download_cal_eeprom(ar); + if (ret == 0) { + ar->cal_mode = ATH10K_CAL_MODE_EEPROM; + goto done; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot did not find target EEPROM entry, try OTP next: %d\n", ret); ret = ath10k_download_and_run_otp(ar); @@ -1590,7 +1697,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_10_4: case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: - WARN_ON(1); + ath10k_err(ar, "htt op version not found from fw meta data"); return -EINVAL; } } @@ -1733,6 +1840,16 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, if (test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map)) val |= WMI_10_4_BSS_CHANNEL_INFO_64; + /* 10.4 firmware supports BT-Coex without reloading firmware + * via pdev param. To support Bluetooth coexistence pdev param, + * WMI_COEX_GPIO_SUPPORT of extended resource config should be + * enabled always. + */ + if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map) && + test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM, + ar->running_fw->fw_file.fw_features)) + val |= WMI_10_4_COEX_GPIO_SUPPORT; + status = ath10k_mac_ext_resource_config(ar, val); if (status) { ath10k_err(ar, @@ -2062,6 +2179,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, switch (hw_rev) { case ATH10K_HW_QCA988X: + case ATH10K_HW_QCA9887: ar->regs = &qca988x_regs; ar->hw_values = &qca988x_values; break; @@ -2071,9 +2189,14 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ar->hw_values = &qca6174_values; break; case ATH10K_HW_QCA99X0: + case ATH10K_HW_QCA9984: ar->regs = &qca99x0_regs; ar->hw_values = &qca99x0_values; break; + case ATH10K_HW_QCA9888: + ar->regs = &qca99x0_regs; + ar->hw_values = &qca9888_values; + break; case ATH10K_HW_QCA4019: ar->regs = &qca4019_regs; ar->hw_values = &qca4019_values; @@ -2159,5 +2282,5 @@ void ath10k_core_destroy(struct ath10k *ar) EXPORT_SYMBOL(ath10k_core_destroy); MODULE_AUTHOR("Qualcomm Atheros"); -MODULE_DESCRIPTION("Core module for QCA988X PCIe devices."); +MODULE_DESCRIPTION("Core module for Qualcomm Atheros 802.11ac wireless LAN cards."); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 1852e0ee3fa1..30ae5bf81611 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -165,6 +165,13 @@ struct ath10k_fw_stats_peer { u32 rx_duration; }; +struct ath10k_fw_extd_stats_peer { + struct list_head list; + + u8 peer_macaddr[ETH_ALEN]; + u32 rx_duration; +}; + struct ath10k_fw_stats_vdev { struct list_head list; @@ -256,9 +263,11 @@ struct ath10k_fw_stats_pdev { }; struct ath10k_fw_stats { + bool extended; struct list_head pdevs; struct list_head vdevs; struct list_head peers; + struct list_head peers_extd; }; #define ATH10K_TPC_TABLE_TYPE_FLAG 1 @@ -535,6 +544,13 @@ enum ath10k_fw_features { */ ATH10K_FW_FEATURE_PEER_FLOW_CONTROL = 13, + /* Firmware supports BT-Coex without reloading firmware via pdev param. + * To support Bluetooth coexistence pdev param, WMI_COEX_GPIO_SUPPORT of + * extended resource config should be enabled always. This firmware IE + * is used to configure WMI_COEX_GPIO_SUPPORT. + */ + ATH10K_FW_FEATURE_BTCOEX_PARAM = 14, + /* keep last */ ATH10K_FW_FEATURE_COUNT, }; @@ -571,6 +587,7 @@ enum ath10k_cal_mode { ATH10K_CAL_MODE_DT, ATH10K_PRE_CAL_MODE_FILE, ATH10K_PRE_CAL_MODE_DT, + ATH10K_CAL_MODE_EEPROM, }; enum ath10k_crypt_mode { @@ -593,6 +610,8 @@ static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode) return "pre-cal-file"; case ATH10K_PRE_CAL_MODE_DT: return "pre-cal-dt"; + case ATH10K_CAL_MODE_EEPROM: + return "eeprom"; } return "unknown"; @@ -657,6 +676,7 @@ struct ath10k_fw_components { struct ath10k { struct ath_common ath_common; struct ieee80211_hw *hw; + struct ieee80211_ops *ops; struct device *dev; u8 mac_addr[ETH_ALEN]; @@ -703,12 +723,10 @@ struct ath10k { int uart_pin; u32 otp_exe_param; - /* This is true if given HW chip has a quirky Cycle Counter - * wraparound which resets to 0x7fffffff instead of 0. All - * other CC related counters (e.g. Rx Clear Count) are divided - * by 2 so they never wraparound themselves. + /* Type of hw cycle counter wraparound logic, for more info + * refer enum ath10k_hw_cc_wraparound_type. */ - bool has_shifted_cc_wraparound; + enum ath10k_hw_cc_wraparound_type cc_wraparound_type; /* Some of chip expects fragment descriptor to be continuous * memory for any TX operation. Set continuous_frag_desc flag @@ -716,6 +734,12 @@ struct ath10k { */ bool continuous_frag_desc; + /* CCK hardware rate table mapping for the newer chipsets + * like QCA99X0, QCA4019 got revised. The CCK h/w rate values + * are in a proper order with respect to the rate/preamble + */ + bool cck_rate_map_rev2; + u32 channel_counters_freq_hz; /* Mgmt tx descriptors threshold for limiting probe response diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index e2511550fbb8..355e1ae665f9 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -313,13 +313,25 @@ static void ath10k_fw_stats_peers_free(struct list_head *head) } } +static void ath10k_fw_extd_stats_peers_free(struct list_head *head) +{ + struct ath10k_fw_extd_stats_peer *i, *tmp; + + list_for_each_entry_safe(i, tmp, head, list) { + list_del(&i->list); + kfree(i); + } +} + static void ath10k_debug_fw_stats_reset(struct ath10k *ar) { spin_lock_bh(&ar->data_lock); ar->debug.fw_stats_done = false; + ar->debug.fw_stats.extended = false; ath10k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs); ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs); ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers); + ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd); spin_unlock_bh(&ar->data_lock); } @@ -334,6 +346,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) INIT_LIST_HEAD(&stats.pdevs); INIT_LIST_HEAD(&stats.vdevs); INIT_LIST_HEAD(&stats.peers); + INIT_LIST_HEAD(&stats.peers_extd); spin_lock_bh(&ar->data_lock); ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats); @@ -354,7 +367,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) * delivered which is treated as end-of-data and is itself discarded */ if (ath10k_peer_stats_enabled(ar)) - ath10k_sta_update_rx_duration(ar, &stats.peers); + ath10k_sta_update_rx_duration(ar, &stats); if (ar->debug.fw_stats_done) { if (!ath10k_peer_stats_enabled(ar)) @@ -396,6 +409,8 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers); list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs); + list_splice_tail_init(&stats.peers_extd, + &ar->debug.fw_stats.peers_extd); } complete(&ar->debug.fw_stats_complete); @@ -407,6 +422,7 @@ free: ath10k_fw_stats_pdevs_free(&stats.pdevs); ath10k_fw_stats_vdevs_free(&stats.vdevs); ath10k_fw_stats_peers_free(&stats.peers); + ath10k_fw_extd_stats_peers_free(&stats.peers_extd); spin_unlock_bh(&ar->data_lock); } @@ -609,25 +625,23 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, char buf[32]; int ret; - mutex_lock(&ar->conf_mutex); - simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); /* make sure that buf is null terminated */ buf[sizeof(buf) - 1] = 0; + /* drop the possible '\n' from the end */ + if (buf[count - 1] == '\n') + buf[count - 1] = 0; + + mutex_lock(&ar->conf_mutex); + if (ar->state != ATH10K_STATE_ON && ar->state != ATH10K_STATE_RESTARTED) { ret = -ENETDOWN; goto exit; } - /* drop the possible '\n' from the end */ - if (buf[count - 1] == '\n') { - buf[count - 1] = 0; - count--; - } - if (!strcmp(buf, "soft")) { ath10k_info(ar, "simulating soft firmware crash\n"); ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); @@ -2127,6 +2141,7 @@ static ssize_t ath10k_write_btcoex(struct file *file, size_t buf_size; int ret; bool val; + u32 pdev_param; buf_size = min(count, (sizeof(buf) - 1)); if (copy_from_user(buf, ubuf, buf_size)) @@ -2150,14 +2165,25 @@ static ssize_t ath10k_write_btcoex(struct file *file, goto exit; } + pdev_param = ar->wmi.pdev_param->enable_btcoex; + if (test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM, + ar->running_fw->fw_file.fw_features)) { + ret = ath10k_wmi_pdev_set_param(ar, pdev_param, val); + if (ret) { + ath10k_warn(ar, "failed to enable btcoex: %d\n", ret); + ret = count; + goto exit; + } + } else { + ath10k_info(ar, "restarting firmware due to btcoex change"); + queue_work(ar->workqueue, &ar->restart_work); + } + if (val) set_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags); else clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags); - ath10k_info(ar, "restarting firmware due to btcoex change"); - - queue_work(ar->workqueue, &ar->restart_work); ret = count; exit: @@ -2320,6 +2346,7 @@ int ath10k_debug_create(struct ath10k *ar) INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs); INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs); INIT_LIST_HEAD(&ar->debug.fw_stats.peers); + INIT_LIST_HEAD(&ar->debug.fw_stats.peers_extd); return 0; } diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 75c89e3625ef..c458fa96a6d4 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -154,10 +154,15 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) #ifdef CONFIG_MAC80211_DEBUGFS void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); -void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *peer); +void ath10k_sta_update_rx_duration(struct ath10k *ar, + struct ath10k_fw_stats *stats); +void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo); #else -static inline void ath10k_sta_update_rx_duration(struct ath10k *ar, - struct list_head *peer) +static inline +void ath10k_sta_update_rx_duration(struct ath10k *ar, + struct ath10k_fw_stats *stats) { } #endif /* CONFIG_MAC80211_DEBUGFS */ diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 67ef75b60567..9955fea0802a 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -18,13 +18,34 @@ #include "wmi-ops.h" #include "debug.h" -void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *head) -{ struct ieee80211_sta *sta; +static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar, + struct ath10k_fw_stats *stats) +{ + struct ath10k_fw_extd_stats_peer *peer; + struct ieee80211_sta *sta; + struct ath10k_sta *arsta; + + rcu_read_lock(); + list_for_each_entry(peer, &stats->peers_extd, list) { + sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr, + NULL); + if (!sta) + continue; + arsta = (struct ath10k_sta *)sta->drv_priv; + arsta->rx_duration += (u64)peer->rx_duration; + } + rcu_read_unlock(); +} + +static void ath10k_sta_update_stats_rx_duration(struct ath10k *ar, + struct ath10k_fw_stats *stats) +{ struct ath10k_fw_stats_peer *peer; + struct ieee80211_sta *sta; struct ath10k_sta *arsta; rcu_read_lock(); - list_for_each_entry(peer, head, list) { + list_for_each_entry(peer, &stats->peers, list) { sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr, NULL); if (!sta) @@ -35,6 +56,29 @@ void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *head) rcu_read_unlock(); } +void ath10k_sta_update_rx_duration(struct ath10k *ar, + struct ath10k_fw_stats *stats) +{ + if (stats->extended) + ath10k_sta_update_extd_stats_rx_duration(ar, stats); + else + ath10k_sta_update_stats_rx_duration(ar, stats); +} + +void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) +{ + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + + if (!ath10k_peer_stats_enabled(ar)) + return; + + sinfo->rx_duration = arsta->rx_duration; + sinfo->filled |= 1ULL << NL80211_STA_INFO_RX_DURATION; +} + static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -249,28 +293,6 @@ static const struct file_operations fops_delba = { .llseek = default_llseek, }; -static ssize_t ath10k_dbg_sta_read_rx_duration(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_sta *sta = file->private_data; - struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; - char buf[100]; - int len = 0; - - len = scnprintf(buf, sizeof(buf), - "%llu usecs\n", arsta->rx_duration); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static const struct file_operations fops_rx_duration = { - .read = ath10k_dbg_sta_read_rx_duration, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir) { @@ -279,6 +301,4 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba); debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp); debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba); - debugfs_create_file("rx_duration", S_IRUGO, dir, sta, - &fops_rx_duration); } diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 89e7076c919f..b2566b06e1e1 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -87,6 +87,10 @@ struct ath10k_hif_ops { int (*suspend)(struct ath10k *ar); int (*resume)(struct ath10k *ar); + + /* fetch calibration data from target eeprom */ + int (*fetch_cal_eeprom)(struct ath10k *ar, void **data, + size_t *data_len); }; static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id, @@ -202,4 +206,14 @@ static inline void ath10k_hif_write32(struct ath10k *ar, ar->hif.ops->write32(ar, address, data); } +static inline int ath10k_hif_fetch_cal_eeprom(struct ath10k *ar, + void **data, + size_t *data_len) +{ + if (!ar->hif.ops->fetch_cal_eeprom) + return -EOPNOTSUPP; + + return ar->hif.ops->fetch_cal_eeprom(ar, data, data_len); +} + #endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index cc827185d3e9..0c55cd92a951 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -22,7 +22,6 @@ #include <linux/list.h> #include <linux/bug.h> #include <linux/skbuff.h> -#include <linux/semaphore.h> #include <linux/timer.h> struct ath10k; diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 911c535d0863..430a83e142aa 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -485,10 +485,10 @@ struct htt_mgmt_tx_completion { __le32 status; } __packed; -#define HTT_RX_INDICATION_INFO0_EXT_TID_MASK (0x3F) +#define HTT_RX_INDICATION_INFO0_EXT_TID_MASK (0x1F) #define HTT_RX_INDICATION_INFO0_EXT_TID_LSB (0) -#define HTT_RX_INDICATION_INFO0_FLUSH_VALID (1 << 6) -#define HTT_RX_INDICATION_INFO0_RELEASE_VALID (1 << 7) +#define HTT_RX_INDICATION_INFO0_FLUSH_VALID (1 << 5) +#define HTT_RX_INDICATION_INFO0_RELEASE_VALID (1 << 6) #define HTT_RX_INDICATION_INFO1_FLUSH_START_SEQNO_MASK 0x0000003F #define HTT_RX_INDICATION_INFO1_FLUSH_START_SEQNO_LSB 0 diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 813cdd2621a1..78db5d679f19 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -748,7 +748,7 @@ ath10k_htt_rx_h_peer_channel(struct ath10k *ar, struct htt_rx_desc *rxd) if (WARN_ON_ONCE(!arvif)) return NULL; - if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def))) + if (ath10k_mac_vif_chan(arvif->vif, &def)) return NULL; return def.chan; @@ -939,7 +939,8 @@ static void ath10k_process_rx(struct ath10k *ar, is_multicast_ether_addr(ieee80211_get_DA(hdr)) ? "mcast" : "ucast", (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4, - status->flag == 0 ? "legacy" : "", + (status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) == 0 ? + "legacy" : "", status->flag & RX_FLAG_HT ? "ht" : "", status->flag & RX_FLAG_VHT ? "vht" : "", status->flag & RX_FLAG_40MHZ ? "40" : "", @@ -2181,34 +2182,6 @@ static void ath10k_htt_rx_tx_mode_switch_ind(struct ath10k *ar, ath10k_mac_tx_push_pending(ar); } -static inline enum nl80211_band phy_mode_to_band(u32 phy_mode) -{ - enum nl80211_band band; - - switch (phy_mode) { - case MODE_11A: - case MODE_11NA_HT20: - case MODE_11NA_HT40: - case MODE_11AC_VHT20: - case MODE_11AC_VHT40: - case MODE_11AC_VHT80: - band = NL80211_BAND_5GHZ; - break; - case MODE_11G: - case MODE_11B: - case MODE_11GONLY: - case MODE_11NG_HT20: - case MODE_11NG_HT40: - case MODE_11AC_VHT20_2G: - case MODE_11AC_VHT40_2G: - case MODE_11AC_VHT80_2G: - default: - band = NL80211_BAND_2GHZ; - } - - return band; -} - void ath10k_htt_htc_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) { bool release; @@ -2290,7 +2263,6 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) ath10k_htt_tx_mgmt_dec_pending(htt); spin_unlock_bh(&htt->tx_lock); } - ath10k_mac_tx_push_pending(ar); break; } case HTT_T2H_MSG_TYPE_TX_COMPL_IND: @@ -2335,12 +2307,10 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) ath10k_htt_rx_delba(ar, resp); break; case HTT_T2H_MSG_TYPE_PKTLOG: { - struct ath10k_pktlog_hdr *hdr = - (struct ath10k_pktlog_hdr *)resp->pktlog_msg.payload; - trace_ath10k_htt_pktlog(ar, resp->pktlog_msg.payload, - sizeof(*hdr) + - __le16_to_cpu(hdr->size)); + skb->len - + offsetof(struct htt_resp, + pktlog_msg.payload)); break; } case HTT_T2H_MSG_TYPE_RX_FLUSH: { @@ -2441,8 +2411,6 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr) dev_kfree_skb_any(skb); } - ath10k_mac_tx_push_pending(ar); - num_mpdus = atomic_read(&htt->num_mpdus_ready); while (num_mpdus) { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 6269c610b0a3..7c072b605bc7 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -49,7 +49,7 @@ static void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw, struct ieee80211_txq *txq) { struct ath10k *ar = hw->priv; - struct ath10k_sta *arsta = (void *)txq->sta->drv_priv; + struct ath10k_sta *arsta; struct ath10k_vif *arvif = (void *)txq->vif->drv_priv; unsigned long frame_cnt; unsigned long byte_cnt; @@ -67,10 +67,12 @@ static void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw, if (ar->htt.tx_q_state.mode != HTT_TX_MODE_SWITCH_PUSH_PULL) return; - if (txq->sta) + if (txq->sta) { + arsta = (void *)txq->sta->drv_priv; peer_id = arsta->peer_id; - else + } else { peer_id = arvif->peer_id; + } tid = txq->tid; bit = BIT(peer_id % 32); @@ -388,6 +390,8 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt) { int size; + tasklet_kill(&htt->txrx_compl_task); + idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); idr_destroy(&htt->pending_tx); @@ -733,16 +737,18 @@ static u8 ath10k_htt_tx_get_vdev_id(struct ath10k *ar, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb); - struct ath10k_vif *arvif = (void *)cb->vif->drv_priv; + struct ath10k_vif *arvif; - if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) + if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { return ar->scan.vdev_id; - else if (cb->vif) + } else if (cb->vif) { + arvif = (void *)cb->vif->drv_priv; return arvif->vdev_id; - else if (ar->monitor_started) + } else if (ar->monitor_started) { return ar->monitor_vdev_id; - else + } else { return 0; + } } static u8 ath10k_htt_tx_get_tid(struct sk_buff *skb, bool is_eth) diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index f544d48518c3..f903d468dbe6 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -19,7 +19,6 @@ #include "hw.h" const struct ath10k_hw_regs qca988x_regs = { - .rtc_state_cold_reset_mask = 0x00000400, .rtc_soc_base_address = 0x00004000, .rtc_wmac_base_address = 0x00005000, .soc_core_base_address = 0x00009000, @@ -46,7 +45,6 @@ const struct ath10k_hw_regs qca988x_regs = { }; const struct ath10k_hw_regs qca6174_regs = { - .rtc_state_cold_reset_mask = 0x00002000, .rtc_soc_base_address = 0x00000800, .rtc_wmac_base_address = 0x00001000, .soc_core_base_address = 0x0003a000, @@ -73,7 +71,6 @@ const struct ath10k_hw_regs qca6174_regs = { }; const struct ath10k_hw_regs qca99x0_regs = { - .rtc_state_cold_reset_mask = 0x00000400, .rtc_soc_base_address = 0x00080000, .rtc_wmac_base_address = 0x00000000, .soc_core_base_address = 0x00082000, @@ -168,6 +165,15 @@ const struct ath10k_hw_values qca99x0_values = { .ce_desc_meta_data_lsb = 4, }; +const struct ath10k_hw_values qca9888_values = { + .rtc_state_val_on = 3, + .ce_count = 12, + .msi_assign_ce_max = 12, + .num_target_ce_config_wlan = 10, + .ce_desc_meta_data_mask = 0xFFF0, + .ce_desc_meta_data_lsb = 4, +}; + const struct ath10k_hw_values qca4019_values = { .ce_count = 12, .num_target_ce_config_wlan = 10, @@ -179,17 +185,36 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev) { u32 cc_fix = 0; + u32 rcc_fix = 0; + enum ath10k_hw_cc_wraparound_type wraparound_type; survey->filled |= SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; - if (ar->hw_params.has_shifted_cc_wraparound && cc < cc_prev) { - cc_fix = 0x7fffffff; - survey->filled &= ~SURVEY_INFO_TIME_BUSY; + wraparound_type = ar->hw_params.cc_wraparound_type; + + if (cc < cc_prev || rcc < rcc_prev) { + switch (wraparound_type) { + case ATH10K_HW_CC_WRAP_SHIFTED_ALL: + if (cc < cc_prev) { + cc_fix = 0x7fffffff; + survey->filled &= ~SURVEY_INFO_TIME_BUSY; + } + break; + case ATH10K_HW_CC_WRAP_SHIFTED_EACH: + if (cc < cc_prev) + cc_fix = 0x7fffffff; + + if (rcc < rcc_prev) + rcc_fix = 0x7fffffff; + break; + case ATH10K_HW_CC_WRAP_DISABLED: + break; + } } cc -= cc_prev - cc_fix; - rcc -= rcc_prev; + rcc -= rcc_prev - rcc_fix; survey->time = CCNT_TO_MSEC(ar, cc); survey->time_busy = CCNT_TO_MSEC(ar, rcc); diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index aedd8987040b..e014cd732a0d 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -26,7 +26,10 @@ #define QCA6164_2_1_DEVICE_ID (0x0041) #define QCA6174_2_1_DEVICE_ID (0x003e) #define QCA99X0_2_0_DEVICE_ID (0x0040) +#define QCA9888_2_0_DEVICE_ID (0x0056) +#define QCA9984_1_0_DEVICE_ID (0x0046) #define QCA9377_1_0_DEVICE_ID (0x0042) +#define QCA9887_1_0_DEVICE_ID (0x0050) /* QCA988X 1.0 definitions (unsupported) */ #define QCA988X_HW_1_0_CHIP_ID_REV 0x0 @@ -38,6 +41,13 @@ #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin" #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234 +/* QCA9887 1.0 definitions */ +#define QCA9887_HW_1_0_VERSION 0x4100016d +#define QCA9887_HW_1_0_CHIP_ID_REV 0 +#define QCA9887_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9887/hw1.0" +#define QCA9887_HW_1_0_BOARD_DATA_FILE "board.bin" +#define QCA9887_HW_1_0_PATCH_LOAD_ADDR 0x1234 + /* QCA6174 target BMI version signatures */ #define QCA6174_HW_1_0_VERSION 0x05000000 #define QCA6174_HW_1_1_VERSION 0x05000001 @@ -91,6 +101,22 @@ enum qca9377_chip_id_rev { #define QCA99X0_HW_2_0_BOARD_DATA_FILE "board.bin" #define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234 +/* QCA9984 1.0 defines */ +#define QCA9984_HW_1_0_DEV_VERSION 0x1000000 +#define QCA9984_HW_DEV_TYPE 0xa +#define QCA9984_HW_1_0_CHIP_ID_REV 0x0 +#define QCA9984_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9984/hw1.0" +#define QCA9984_HW_1_0_BOARD_DATA_FILE "board.bin" +#define QCA9984_HW_1_0_PATCH_LOAD_ADDR 0x1234 + +/* QCA9888 2.0 defines */ +#define QCA9888_HW_2_0_DEV_VERSION 0x1000000 +#define QCA9888_HW_DEV_TYPE 0xc +#define QCA9888_HW_2_0_CHIP_ID_REV 0x0 +#define QCA9888_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA9888/hw2.0" +#define QCA9888_HW_2_0_BOARD_DATA_FILE "board.bin" +#define QCA9888_HW_2_0_PATCH_LOAD_ADDR 0x1234 + /* QCA9377 1.0 definitions */ #define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0" #define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin" @@ -193,12 +219,14 @@ enum ath10k_hw_rev { ATH10K_HW_QCA988X, ATH10K_HW_QCA6174, ATH10K_HW_QCA99X0, + ATH10K_HW_QCA9888, + ATH10K_HW_QCA9984, ATH10K_HW_QCA9377, ATH10K_HW_QCA4019, + ATH10K_HW_QCA9887, }; struct ath10k_hw_regs { - u32 rtc_state_cold_reset_mask; u32 rtc_soc_base_address; u32 rtc_wmac_base_address; u32 soc_core_base_address; @@ -241,14 +269,18 @@ struct ath10k_hw_values { extern const struct ath10k_hw_values qca988x_values; extern const struct ath10k_hw_values qca6174_values; extern const struct ath10k_hw_values qca99x0_values; +extern const struct ath10k_hw_values qca9888_values; extern const struct ath10k_hw_values qca4019_values; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); #define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X) +#define QCA_REV_9887(ar) ((ar)->hw_rev == ATH10K_HW_QCA9887) #define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) #define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0) +#define QCA_REV_9888(ar) ((ar)->hw_rev == ATH10K_HW_QCA9888) +#define QCA_REV_9984(ar) ((ar)->hw_rev == ATH10K_HW_QCA9984) #define QCA_REV_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377) #define QCA_REV_40XX(ar) ((ar)->hw_rev == ATH10K_HW_QCA4019) @@ -275,25 +307,6 @@ enum ath10k_mcast2ucast_mode { ATH10K_MCAST2UCAST_ENABLED = 1, }; -struct ath10k_pktlog_hdr { - __le16 flags; - __le16 missed_cnt; - __le16 log_type; - __le16 size; - __le32 timestamp; - u8 payload[0]; -} __packed; - -struct ath10k_pktlog_10_4_hdr { - __le16 flags; - __le16 missed_cnt; - __le16 log_type; - __le16 size; - __le32 timestamp; - __le32 type_specific_data; - u8 payload[0]; -} __packed; - enum ath10k_hw_rate_ofdm { ATH10K_HW_RATE_OFDM_48M = 0, ATH10K_HW_RATE_OFDM_24M, @@ -315,11 +328,41 @@ enum ath10k_hw_rate_cck { ATH10K_HW_RATE_CCK_SP_2M, }; +enum ath10k_hw_rate_rev2_cck { + ATH10K_HW_RATE_REV2_CCK_LP_1M = 1, + ATH10K_HW_RATE_REV2_CCK_LP_2M, + ATH10K_HW_RATE_REV2_CCK_LP_5_5M, + ATH10K_HW_RATE_REV2_CCK_LP_11M, + ATH10K_HW_RATE_REV2_CCK_SP_2M, + ATH10K_HW_RATE_REV2_CCK_SP_5_5M, + ATH10K_HW_RATE_REV2_CCK_SP_11M, +}; + enum ath10k_hw_4addr_pad { ATH10K_HW_4ADDR_PAD_AFTER, ATH10K_HW_4ADDR_PAD_BEFORE, }; +enum ath10k_hw_cc_wraparound_type { + ATH10K_HW_CC_WRAP_DISABLED = 0, + + /* This type is when the HW chip has a quirky Cycle Counter + * wraparound which resets to 0x7fffffff instead of 0. All + * other CC related counters (e.g. Rx Clear Count) are divided + * by 2 so they never wraparound themselves. + */ + ATH10K_HW_CC_WRAP_SHIFTED_ALL = 1, + + /* Each hw counter wrapsaround independently. When the + * counter overflows the repestive counter is right shifted + * by 1, i.e reset to 0x7fffffff, and other counters will be + * running unaffected. In this type of wraparound, it should + * be possible to report accurate Rx busy time unlike the + * first type. + */ + ATH10K_HW_CC_WRAP_SHIFTED_EACH = 2, +}; + /* Target specific defines for MAIN firmware */ #define TARGET_NUM_VDEVS 8 #define TARGET_NUM_PEER_AST 2 @@ -484,7 +527,6 @@ enum ath10k_hw_4addr_pad { /* as of IP3.7.1 */ #define RTC_STATE_V_ON ar->hw_values->rtc_state_val_on -#define RTC_STATE_COLD_RESET_MASK ar->regs->rtc_state_cold_reset_mask #define RTC_STATE_V_LSB 0 #define RTC_STATE_V_MASK 0x00000007 #define RTC_STATE_ADDRESS 0x0000 @@ -547,7 +589,10 @@ enum ath10k_hw_4addr_pad { #define WLAN_SYSTEM_SLEEP_DISABLE_MASK 0x00000001 #define WLAN_GPIO_PIN0_ADDRESS 0x00000028 +#define WLAN_GPIO_PIN0_CONFIG_LSB 11 #define WLAN_GPIO_PIN0_CONFIG_MASK 0x00007800 +#define WLAN_GPIO_PIN0_PAD_PULL_LSB 5 +#define WLAN_GPIO_PIN0_PAD_PULL_MASK 0x00000060 #define WLAN_GPIO_PIN1_ADDRESS 0x0000002c #define WLAN_GPIO_PIN1_CONFIG_MASK 0x00007800 #define WLAN_GPIO_PIN10_ADDRESS 0x00000050 @@ -560,6 +605,8 @@ enum ath10k_hw_4addr_pad { #define CLOCK_GPIO_BT_CLK_OUT_EN_MASK 0 #define SI_CONFIG_OFFSET 0x00000000 +#define SI_CONFIG_ERR_INT_LSB 19 +#define SI_CONFIG_ERR_INT_MASK 0x00080000 #define SI_CONFIG_BIDIR_OD_DATA_LSB 18 #define SI_CONFIG_BIDIR_OD_DATA_MASK 0x00040000 #define SI_CONFIG_I2C_LSB 16 @@ -573,7 +620,9 @@ enum ath10k_hw_4addr_pad { #define SI_CONFIG_DIVIDER_LSB 0 #define SI_CONFIG_DIVIDER_MASK 0x0000000f #define SI_CS_OFFSET 0x00000004 +#define SI_CS_DONE_ERR_LSB 10 #define SI_CS_DONE_ERR_MASK 0x00000400 +#define SI_CS_DONE_INT_LSB 9 #define SI_CS_DONE_INT_MASK 0x00000200 #define SI_CS_START_LSB 8 #define SI_CS_START_MASK 0x00000100 @@ -624,7 +673,10 @@ enum ath10k_hw_4addr_pad { #define GPIO_BASE_ADDRESS WLAN_GPIO_BASE_ADDRESS #define GPIO_PIN0_OFFSET WLAN_GPIO_PIN0_ADDRESS #define GPIO_PIN1_OFFSET WLAN_GPIO_PIN1_ADDRESS +#define GPIO_PIN0_CONFIG_LSB WLAN_GPIO_PIN0_CONFIG_LSB #define GPIO_PIN0_CONFIG_MASK WLAN_GPIO_PIN0_CONFIG_MASK +#define GPIO_PIN0_PAD_PULL_LSB WLAN_GPIO_PIN0_PAD_PULL_LSB +#define GPIO_PIN0_PAD_PULL_MASK WLAN_GPIO_PIN0_PAD_PULL_MASK #define GPIO_PIN1_CONFIG_MASK WLAN_GPIO_PIN1_CONFIG_MASK #define SI_BASE_ADDRESS WLAN_SI_BASE_ADDRESS #define SCRATCH_BASE_ADDRESS SOC_CORE_BASE_ADDRESS @@ -679,6 +731,18 @@ enum ath10k_hw_4addr_pad { #define WINDOW_READ_ADDR_ADDRESS MISSING #define WINDOW_WRITE_ADDR_ADDRESS MISSING +#define QCA9887_1_0_I2C_SDA_GPIO_PIN 5 +#define QCA9887_1_0_I2C_SDA_PIN_CONFIG 3 +#define QCA9887_1_0_SI_CLK_GPIO_PIN 17 +#define QCA9887_1_0_SI_CLK_PIN_CONFIG 3 +#define QCA9887_1_0_GPIO_ENABLE_W1TS_LOW_ADDRESS 0x00000010 + +#define QCA9887_EEPROM_SELECT_READ 0xa10000a0 +#define QCA9887_EEPROM_ADDR_HI_MASK 0x0000ff00 +#define QCA9887_EEPROM_ADDR_HI_LSB 8 +#define QCA9887_EEPROM_ADDR_LO_MASK 0x00ff0000 +#define QCA9887_EEPROM_ADDR_LO_LSB 16 + #define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB) #endif /* _HW_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4040f9413e86..fb8e38df9446 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -62,6 +62,32 @@ static struct ieee80211_rate ath10k_rates[] = { { .bitrate = 540, .hw_value = ATH10K_HW_RATE_OFDM_54M }, }; +static struct ieee80211_rate ath10k_rates_rev2[] = { + { .bitrate = 10, + .hw_value = ATH10K_HW_RATE_REV2_CCK_LP_1M }, + { .bitrate = 20, + .hw_value = ATH10K_HW_RATE_REV2_CCK_LP_2M, + .hw_value_short = ATH10K_HW_RATE_REV2_CCK_SP_2M, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = ATH10K_HW_RATE_REV2_CCK_LP_5_5M, + .hw_value_short = ATH10K_HW_RATE_REV2_CCK_SP_5_5M, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = ATH10K_HW_RATE_REV2_CCK_LP_11M, + .hw_value_short = ATH10K_HW_RATE_REV2_CCK_SP_11M, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + + { .bitrate = 60, .hw_value = ATH10K_HW_RATE_OFDM_6M }, + { .bitrate = 90, .hw_value = ATH10K_HW_RATE_OFDM_9M }, + { .bitrate = 120, .hw_value = ATH10K_HW_RATE_OFDM_12M }, + { .bitrate = 180, .hw_value = ATH10K_HW_RATE_OFDM_18M }, + { .bitrate = 240, .hw_value = ATH10K_HW_RATE_OFDM_24M }, + { .bitrate = 360, .hw_value = ATH10K_HW_RATE_OFDM_36M }, + { .bitrate = 480, .hw_value = ATH10K_HW_RATE_OFDM_48M }, + { .bitrate = 540, .hw_value = ATH10K_HW_RATE_OFDM_54M }, +}; + #define ATH10K_MAC_FIRST_OFDM_RATE_IDX 4 #define ath10k_a_rates (ath10k_rates + ATH10K_MAC_FIRST_OFDM_RATE_IDX) @@ -70,6 +96,9 @@ static struct ieee80211_rate ath10k_rates[] = { #define ath10k_g_rates (ath10k_rates + 0) #define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates)) +#define ath10k_g_rates_rev2 (ath10k_rates_rev2 + 0) +#define ath10k_g_rates_rev2_size (ARRAY_SIZE(ath10k_rates_rev2)) + static bool ath10k_mac_bitrate_is_cck(int bitrate) { switch (bitrate) { @@ -773,6 +802,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id) { struct ath10k_peer *peer, *tmp; int peer_id; + int i; lockdep_assert_held(&ar->conf_mutex); @@ -789,6 +819,17 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id) ar->peer_map[peer_id] = NULL; } + /* Double check that peer is properly un-referenced from + * the peer_map + */ + for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++) { + if (ar->peer_map[i] == peer) { + ath10k_warn(ar, "removing stale peer_map entry for %pM (ptr %p idx %d)\n", + peer->addr, peer, i); + ar->peer_map[i] = NULL; + } + } + list_del(&peer->list); kfree(peer); ar->num_peers--; @@ -799,6 +840,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id) static void ath10k_peer_cleanup_all(struct ath10k *ar) { struct ath10k_peer *peer, *tmp; + int i; lockdep_assert_held(&ar->conf_mutex); @@ -807,6 +849,10 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar) list_del(&peer->list); kfree(peer); } + + for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++) + ar->peer_map[i] = NULL; + spin_unlock_bh(&ar->data_lock); ar->num_peers = 0; @@ -2910,7 +2956,7 @@ static int ath10k_update_channel_list(struct ath10k *ar) if (channel->flags & IEEE80211_CHAN_DISABLED) continue; - ch->allow_ht = true; + ch->allow_ht = true; /* FIXME: when should we really allow VHT? */ ch->allow_vht = true; @@ -3646,17 +3692,18 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) static void ath10k_mac_txq_init(struct ieee80211_txq *txq) { - struct ath10k_txq *artxq = (void *)txq->drv_priv; + struct ath10k_txq *artxq; if (!txq) return; + artxq = (void *)txq->drv_priv; INIT_LIST_HEAD(&artxq->list); } static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq) { - struct ath10k_txq *artxq = (void *)txq->drv_priv; + struct ath10k_txq *artxq; struct ath10k_skb_cb *cb; struct sk_buff *msdu; int msdu_id; @@ -3664,6 +3711,7 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq) if (!txq) return; + artxq = (void *)txq->drv_priv; spin_lock_bh(&ar->txqs_lock); if (!list_empty(&artxq->list)) list_del_init(&artxq->list); @@ -3781,6 +3829,9 @@ void ath10k_mac_tx_push_pending(struct ath10k *ar) int ret; int max; + if (ar->htt.num_pending_tx >= (ar->htt.max_num_pending_tx / 2)) + return; + spin_lock_bh(&ar->txqs_lock); rcu_read_lock(); @@ -3826,12 +3877,16 @@ void __ath10k_scan_finish(struct ath10k *ar) break; case ATH10K_SCAN_RUNNING: case ATH10K_SCAN_ABORTING: - if (!ar->scan.is_roc) - ieee80211_scan_completed(ar->hw, - (ar->scan.state == - ATH10K_SCAN_ABORTING)); - else if (ar->scan.roc_notify) + if (!ar->scan.is_roc) { + struct cfg80211_scan_info info = { + .aborted = (ar->scan.state == + ATH10K_SCAN_ABORTING), + }; + + ieee80211_scan_completed(ar->hw, &info); + } else if (ar->scan.roc_notify) { ieee80211_remain_on_channel_expired(ar->hw); + } /* fall through */ case ATH10K_SCAN_STARTING: ar->scan.state = ATH10K_SCAN_IDLE; @@ -4051,9 +4106,7 @@ static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw, list_add_tail(&artxq->list, &ar->txqs); spin_unlock_bh(&ar->txqs_lock); - if (ath10k_mac_tx_can_push(hw, txq)) - tasklet_schedule(&ar->htt.txrx_compl_task); - + ath10k_mac_tx_push_pending(ar); ath10k_htt_tx_txq_update(hw, txq); } @@ -4194,6 +4247,9 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2); } + if (ar->cfg_tx_chainmask <= 1) + vht_cap.cap &= ~IEEE80211_VHT_CAP_TXSTBC; + vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); @@ -4231,7 +4287,7 @@ static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar) ht_cap.cap |= smps; } - if (ar->ht_cap_info & WMI_HT_CAP_TX_STBC) + if (ar->ht_cap_info & WMI_HT_CAP_TX_STBC && (ar->cfg_tx_chainmask > 1)) ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; if (ar->ht_cap_info & WMI_HT_CAP_RX_STBC) { @@ -4467,6 +4523,19 @@ static int ath10k_start(struct ieee80211_hw *hw) } } + param = ar->wmi.pdev_param->enable_btcoex; + if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map) && + test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM, + ar->running_fw->fw_file.fw_features)) { + ret = ath10k_wmi_pdev_set_param(ar, param, 0); + if (ret) { + ath10k_warn(ar, + "failed to set btcoex param: %d\n", ret); + goto err_core_stop; + } + clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags); + } + ar->num_started_vdevs = 0; ath10k_regd_update(ar); @@ -5932,9 +6001,17 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, continue; if (peer->sta == sta) { - ath10k_warn(ar, "found sta peer %pM entry on vdev %i after it was supposedly removed\n", - sta->addr, arvif->vdev_id); + ath10k_warn(ar, "found sta peer %pM (ptr %p id %d) entry on vdev %i after it was supposedly removed\n", + sta->addr, peer, i, arvif->vdev_id); peer->sta = NULL; + + /* Clean up the peer object as well since we + * must have failed to do this above. + */ + list_del(&peer->list); + ar->peer_map[i] = NULL; + kfree(peer); + ar->num_peers--; } } spin_unlock_bh(&ar->data_lock); @@ -7359,6 +7436,7 @@ static const struct ieee80211_ops ath10k_ops = { #endif #ifdef CONFIG_MAC80211_DEBUGFS .sta_add_debugfs = ath10k_sta_add_debugfs, + .sta_statistics = ath10k_sta_statistics, #endif }; @@ -7428,21 +7506,32 @@ static const struct ieee80211_channel ath10k_5ghz_channels[] = { struct ath10k *ath10k_mac_create(size_t priv_size) { struct ieee80211_hw *hw; + struct ieee80211_ops *ops; struct ath10k *ar; - hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, &ath10k_ops); - if (!hw) + ops = kmemdup(&ath10k_ops, sizeof(ath10k_ops), GFP_KERNEL); + if (!ops) return NULL; + hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, ops); + if (!hw) { + kfree(ops); + return NULL; + } + ar = hw->priv; ar->hw = hw; + ar->ops = ops; return ar; } void ath10k_mac_destroy(struct ath10k *ar) { + struct ieee80211_ops *ops = ar->ops; + ieee80211_free_hw(ar->hw); + kfree(ops); } static const struct ieee80211_iface_limit ath10k_if_limits[] = { @@ -7695,8 +7784,14 @@ int ath10k_mac_register(struct ath10k *ar) band = &ar->mac.sbands[NL80211_BAND_2GHZ]; band->n_channels = ARRAY_SIZE(ath10k_2ghz_channels); band->channels = channels; - band->n_bitrates = ath10k_g_rates_size; - band->bitrates = ath10k_g_rates; + + if (ar->hw_params.cck_rate_map_rev2) { + band->n_bitrates = ath10k_g_rates_rev2_size; + band->bitrates = ath10k_g_rates_rev2; + } else { + band->n_bitrates = ath10k_g_rates_size; + band->bitrates = ath10k_g_rates; + } ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = band; } @@ -7870,6 +7965,15 @@ int ath10k_mac_register(struct ath10k *ar) ath10k_warn(ar, "failed to initialise DFS pattern detector\n"); } + /* Current wake_tx_queue implementation imposes a significant + * performance penalty in some setups. The tx scheduling code needs + * more work anyway so disable the wake_tx_queue unless firmware + * supports the pull-push mechanism. + */ + if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, + ar->running_fw->fw_file.fw_features)) + ar->ops->wake_tx_queue = NULL; + ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, ath10k_reg_notifier); if (ret) { diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 8133d7b5b956..9a22c478dd1b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -56,7 +56,10 @@ static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */ { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */ { PCI_VDEVICE(ATHEROS, QCA99X0_2_0_DEVICE_ID) }, /* PCI-E QCA99X0 V2 */ + { PCI_VDEVICE(ATHEROS, QCA9888_2_0_DEVICE_ID) }, /* PCI-E QCA9888 V2 */ + { PCI_VDEVICE(ATHEROS, QCA9984_1_0_DEVICE_ID) }, /* PCI-E QCA9984 V1 */ { PCI_VDEVICE(ATHEROS, QCA9377_1_0_DEVICE_ID) }, /* PCI-E QCA9377 V1 */ + { PCI_VDEVICE(ATHEROS, QCA9887_1_0_DEVICE_ID) }, /* PCI-E QCA9887 */ {0} }; @@ -81,8 +84,14 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { { QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV }, + { QCA9984_1_0_DEVICE_ID, QCA9984_HW_1_0_CHIP_ID_REV }, + + { QCA9888_2_0_DEVICE_ID, QCA9888_HW_2_0_CHIP_ID_REV }, + { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_0_CHIP_ID_REV }, { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_1_CHIP_ID_REV }, + + { QCA9887_1_0_DEVICE_ID, QCA9887_HW_1_0_CHIP_ID_REV }, }; static void ath10k_pci_buffer_cleanup(struct ath10k *ar); @@ -837,13 +846,16 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) switch (ar->hw_rev) { case ATH10K_HW_QCA988X: + case ATH10K_HW_QCA9887: case ATH10K_HW_QCA6174: case ATH10K_HW_QCA9377: val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS) & 0x7ff) << 21; break; + case ATH10K_HW_QCA9888: case ATH10K_HW_QCA99X0: + case ATH10K_HW_QCA9984: case ATH10K_HW_QCA4019: val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS); break; @@ -864,7 +876,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret = 0; u32 *buf; - unsigned int completed_nbytes, orig_nbytes, remaining_bytes; + unsigned int completed_nbytes, alloc_nbytes, remaining_bytes; struct ath10k_ce_pipe *ce_diag; /* Host buffer address in CE space */ u32 ce_data; @@ -882,9 +894,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, * 1) 4-byte alignment * 2) Buffer in DMA-able space */ - orig_nbytes = nbytes; + alloc_nbytes = min_t(unsigned int, nbytes, DIAG_TRANSFER_LIMIT); + data_buf = (unsigned char *)dma_alloc_coherent(ar->dev, - orig_nbytes, + alloc_nbytes, &ce_data_base, GFP_ATOMIC); @@ -892,9 +905,9 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, ret = -ENOMEM; goto done; } - memset(data_buf, 0, orig_nbytes); + memset(data_buf, 0, alloc_nbytes); - remaining_bytes = orig_nbytes; + remaining_bytes = nbytes; ce_data = ce_data_base; while (remaining_bytes) { nbytes = min_t(unsigned int, remaining_bytes, @@ -954,19 +967,22 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, } remaining_bytes -= nbytes; + + if (ret) { + ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n", + address, ret); + break; + } + memcpy(data, data_buf, nbytes); + address += nbytes; - ce_data += nbytes; + data += nbytes; } done: - if (ret == 0) - memcpy(data, data_buf, orig_nbytes); - else - ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n", - address, ret); if (data_buf) - dma_free_coherent(ar->dev, orig_nbytes, data_buf, + dma_free_coherent(ar->dev, alloc_nbytes, data_buf, ce_data_base); spin_unlock_bh(&ar_pci->ce_lock); @@ -1560,6 +1576,7 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) switch (ar->hw_rev) { case ATH10K_HW_QCA988X: + case ATH10K_HW_QCA9887: case ATH10K_HW_QCA6174: case ATH10K_HW_QCA9377: val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + @@ -1569,6 +1586,8 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) CORE_CTRL_ADDRESS, val); break; case ATH10K_HW_QCA99X0: + case ATH10K_HW_QCA9984: + case ATH10K_HW_QCA9888: case ATH10K_HW_QCA4019: /* TODO: Find appropriate register configuration for QCA99X0 * to mask irq/MSI. @@ -1583,6 +1602,7 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar) switch (ar->hw_rev) { case ATH10K_HW_QCA988X: + case ATH10K_HW_QCA9887: case ATH10K_HW_QCA6174: case ATH10K_HW_QCA9377: val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + @@ -1592,6 +1612,8 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar) CORE_CTRL_ADDRESS, val); break; case ATH10K_HW_QCA99X0: + case ATH10K_HW_QCA9984: + case ATH10K_HW_QCA9888: case ATH10K_HW_QCA4019: /* TODO: Find appropriate register configuration for QCA99X0 * to unmask irq/MSI. @@ -1932,6 +1954,9 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar) switch (ar_pci->pdev->device) { case QCA988X_2_0_DEVICE_ID: case QCA99X0_2_0_DEVICE_ID: + case QCA9888_2_0_DEVICE_ID: + case QCA9984_1_0_DEVICE_ID: + case QCA9887_1_0_DEVICE_ID: return 1; case QCA6164_2_1_DEVICE_ID: case QCA6174_2_1_DEVICE_ID: @@ -2198,6 +2223,14 @@ static void ath10k_pci_fw_crashed_clear(struct ath10k *ar) ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val); } +static bool ath10k_pci_has_device_gone(struct ath10k *ar) +{ + u32 val; + + val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); + return (val == 0xffffffff); +} + /* this function effectively clears target memory controller assert line */ static void ath10k_pci_warm_reset_si0(struct ath10k *ar) { @@ -2293,16 +2326,20 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) return 0; } +static int ath10k_pci_qca99x0_soft_chip_reset(struct ath10k *ar) +{ + ath10k_pci_irq_disable(ar); + return ath10k_pci_qca99x0_chip_reset(ar); +} + static int ath10k_pci_safe_chip_reset(struct ath10k *ar) { - if (QCA_REV_988X(ar) || QCA_REV_6174(ar)) { - return ath10k_pci_warm_reset(ar); - } else if (QCA_REV_99X0(ar)) { - ath10k_pci_irq_disable(ar); - return ath10k_pci_qca99x0_chip_reset(ar); - } else { + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + if (!ar_pci->pci_soft_reset) return -ENOTSUPP; - } + + return ar_pci->pci_soft_reset(ar); } static int ath10k_pci_qca988x_chip_reset(struct ath10k *ar) @@ -2437,16 +2474,12 @@ static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar) static int ath10k_pci_chip_reset(struct ath10k *ar) { - if (QCA_REV_988X(ar)) - return ath10k_pci_qca988x_chip_reset(ar); - else if (QCA_REV_6174(ar)) - return ath10k_pci_qca6174_chip_reset(ar); - else if (QCA_REV_9377(ar)) - return ath10k_pci_qca6174_chip_reset(ar); - else if (QCA_REV_99X0(ar)) - return ath10k_pci_qca99x0_chip_reset(ar); - else + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + if (WARN_ON(!ar_pci->pci_hard_reset)) return -ENOTSUPP; + + return ar_pci->pci_hard_reset(ar); } static int ath10k_pci_hif_power_up(struct ath10k *ar) @@ -2559,6 +2592,144 @@ static int ath10k_pci_hif_resume(struct ath10k *ar) } #endif +static bool ath10k_pci_validate_cal(void *data, size_t size) +{ + __le16 *cal_words = data; + u16 checksum = 0; + size_t i; + + if (size % 2 != 0) + return false; + + for (i = 0; i < size / 2; i++) + checksum ^= le16_to_cpu(cal_words[i]); + + return checksum == 0xffff; +} + +static void ath10k_pci_enable_eeprom(struct ath10k *ar) +{ + /* Enable SI clock */ + ath10k_pci_soc_write32(ar, CLOCK_CONTROL_OFFSET, 0x0); + + /* Configure GPIOs for I2C operation */ + ath10k_pci_write32(ar, + GPIO_BASE_ADDRESS + GPIO_PIN0_OFFSET + + 4 * QCA9887_1_0_I2C_SDA_GPIO_PIN, + SM(QCA9887_1_0_I2C_SDA_PIN_CONFIG, + GPIO_PIN0_CONFIG) | + SM(1, GPIO_PIN0_PAD_PULL)); + + ath10k_pci_write32(ar, + GPIO_BASE_ADDRESS + GPIO_PIN0_OFFSET + + 4 * QCA9887_1_0_SI_CLK_GPIO_PIN, + SM(QCA9887_1_0_SI_CLK_PIN_CONFIG, GPIO_PIN0_CONFIG) | + SM(1, GPIO_PIN0_PAD_PULL)); + + ath10k_pci_write32(ar, + GPIO_BASE_ADDRESS + + QCA9887_1_0_GPIO_ENABLE_W1TS_LOW_ADDRESS, + 1u << QCA9887_1_0_SI_CLK_GPIO_PIN); + + /* In Swift ASIC - EEPROM clock will be (110MHz/512) = 214KHz */ + ath10k_pci_write32(ar, + SI_BASE_ADDRESS + SI_CONFIG_OFFSET, + SM(1, SI_CONFIG_ERR_INT) | + SM(1, SI_CONFIG_BIDIR_OD_DATA) | + SM(1, SI_CONFIG_I2C) | + SM(1, SI_CONFIG_POS_SAMPLE) | + SM(1, SI_CONFIG_INACTIVE_DATA) | + SM(1, SI_CONFIG_INACTIVE_CLK) | + SM(8, SI_CONFIG_DIVIDER)); +} + +static int ath10k_pci_read_eeprom(struct ath10k *ar, u16 addr, u8 *out) +{ + u32 reg; + int wait_limit; + + /* set device select byte and for the read operation */ + reg = QCA9887_EEPROM_SELECT_READ | + SM(addr, QCA9887_EEPROM_ADDR_LO) | + SM(addr >> 8, QCA9887_EEPROM_ADDR_HI); + ath10k_pci_write32(ar, SI_BASE_ADDRESS + SI_TX_DATA0_OFFSET, reg); + + /* write transmit data, transfer length, and START bit */ + ath10k_pci_write32(ar, SI_BASE_ADDRESS + SI_CS_OFFSET, + SM(1, SI_CS_START) | SM(1, SI_CS_RX_CNT) | + SM(4, SI_CS_TX_CNT)); + + /* wait max 1 sec */ + wait_limit = 100000; + + /* wait for SI_CS_DONE_INT */ + do { + reg = ath10k_pci_read32(ar, SI_BASE_ADDRESS + SI_CS_OFFSET); + if (MS(reg, SI_CS_DONE_INT)) + break; + + wait_limit--; + udelay(10); + } while (wait_limit > 0); + + if (!MS(reg, SI_CS_DONE_INT)) { + ath10k_err(ar, "timeout while reading device EEPROM at %04x\n", + addr); + return -ETIMEDOUT; + } + + /* clear SI_CS_DONE_INT */ + ath10k_pci_write32(ar, SI_BASE_ADDRESS + SI_CS_OFFSET, reg); + + if (MS(reg, SI_CS_DONE_ERR)) { + ath10k_err(ar, "failed to read device EEPROM at %04x\n", addr); + return -EIO; + } + + /* extract receive data */ + reg = ath10k_pci_read32(ar, SI_BASE_ADDRESS + SI_RX_DATA0_OFFSET); + *out = reg; + + return 0; +} + +static int ath10k_pci_hif_fetch_cal_eeprom(struct ath10k *ar, void **data, + size_t *data_len) +{ + u8 *caldata = NULL; + size_t calsize, i; + int ret; + + if (!QCA_REV_9887(ar)) + return -EOPNOTSUPP; + + calsize = ar->hw_params.cal_data_len; + caldata = kmalloc(calsize, GFP_KERNEL); + if (!caldata) + return -ENOMEM; + + ath10k_pci_enable_eeprom(ar); + + for (i = 0; i < calsize; i++) { + ret = ath10k_pci_read_eeprom(ar, i, &caldata[i]); + if (ret) + goto err_free; + } + + if (!ath10k_pci_validate_cal(caldata, calsize)) + goto err_free; + + *data = caldata; + *data_len = calsize; + + return 0; + +err_free: + kfree(data); + + return -EINVAL; +} + static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .tx_sg = ath10k_pci_hif_tx_sg, .diag_read = ath10k_pci_hif_diag_read, @@ -2578,6 +2749,7 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .suspend = ath10k_pci_hif_suspend, .resume = ath10k_pci_hif_resume, #endif + .fetch_cal_eeprom = ath10k_pci_hif_fetch_cal_eeprom, }; /* @@ -2591,6 +2763,9 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; + if (ath10k_pci_has_device_gone(ar)) + return IRQ_NONE; + ret = ath10k_pci_force_wake(ar); if (ret) { ath10k_warn(ar, "failed to wake device up on irq: %d\n", ret); @@ -2976,24 +3151,53 @@ static int ath10k_pci_probe(struct pci_dev *pdev, enum ath10k_hw_rev hw_rev; u32 chip_id; bool pci_ps; + int (*pci_soft_reset)(struct ath10k *ar); + int (*pci_hard_reset)(struct ath10k *ar); switch (pci_dev->device) { case QCA988X_2_0_DEVICE_ID: hw_rev = ATH10K_HW_QCA988X; pci_ps = false; + pci_soft_reset = ath10k_pci_warm_reset; + pci_hard_reset = ath10k_pci_qca988x_chip_reset; + break; + case QCA9887_1_0_DEVICE_ID: + dev_warn(&pdev->dev, "QCA9887 support is still experimental, there are likely bugs. You have been warned.\n"); + hw_rev = ATH10K_HW_QCA9887; + pci_ps = false; + pci_soft_reset = ath10k_pci_warm_reset; + pci_hard_reset = ath10k_pci_qca988x_chip_reset; break; case QCA6164_2_1_DEVICE_ID: case QCA6174_2_1_DEVICE_ID: hw_rev = ATH10K_HW_QCA6174; pci_ps = true; + pci_soft_reset = ath10k_pci_warm_reset; + pci_hard_reset = ath10k_pci_qca6174_chip_reset; break; case QCA99X0_2_0_DEVICE_ID: hw_rev = ATH10K_HW_QCA99X0; pci_ps = false; + pci_soft_reset = ath10k_pci_qca99x0_soft_chip_reset; + pci_hard_reset = ath10k_pci_qca99x0_chip_reset; + break; + case QCA9984_1_0_DEVICE_ID: + hw_rev = ATH10K_HW_QCA9984; + pci_ps = false; + pci_soft_reset = ath10k_pci_qca99x0_soft_chip_reset; + pci_hard_reset = ath10k_pci_qca99x0_chip_reset; + break; + case QCA9888_2_0_DEVICE_ID: + hw_rev = ATH10K_HW_QCA9888; + pci_ps = false; + pci_soft_reset = ath10k_pci_qca99x0_soft_chip_reset; + pci_hard_reset = ath10k_pci_qca99x0_chip_reset; break; case QCA9377_1_0_DEVICE_ID: hw_rev = ATH10K_HW_QCA9377; pci_ps = true; + pci_soft_reset = NULL; + pci_hard_reset = ath10k_pci_qca6174_chip_reset; break; default: WARN_ON(1); @@ -3018,6 +3222,8 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ar->dev_id = pci_dev->device; ar_pci->pci_ps = pci_ps; ar_pci->bus_ops = &ath10k_pci_bus_ops; + ar_pci->pci_soft_reset = pci_soft_reset; + ar_pci->pci_hard_reset = pci_hard_reset; ar->id.vendor = pdev->vendor; ar->id.device = pdev->device; @@ -3169,7 +3375,7 @@ static void __exit ath10k_pci_exit(void) module_exit(ath10k_pci_exit); MODULE_AUTHOR("Qualcomm Atheros"); -MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices"); +MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN PCIe/AHB devices"); MODULE_LICENSE("Dual BSD/GPL"); /* QCA988x 2.0 firmware files */ @@ -3180,6 +3386,11 @@ MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API5_FILE); MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE); MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_BOARD_API2_FILE); +/* QCA9887 1.0 firmware files */ +MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" ATH10K_FW_API5_FILE); +MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" QCA9887_HW_1_0_BOARD_DATA_FILE); +MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" ATH10K_BOARD_API2_FILE); + /* QCA6174 2.1 firmware files */ MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE); MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API5_FILE); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 959dc321b75e..6eca1df2ce60 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -234,6 +234,12 @@ struct ath10k_pci { const struct ath10k_bus_ops *bus_ops; + /* Chip specific pci reset routine used to do a safe reset */ + int (*pci_soft_reset)(struct ath10k *ar); + + /* Chip specific pci full reset function */ + int (*pci_hard_reset)(struct ath10k *ar); + /* Keep this entry in the last, memory for struct ath10k_ahb is * allocated (ahb support enabled case) in the continuation of * this struct. diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index ca8d16884af1..034e7a54c5b2 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -656,26 +656,6 @@ struct rx_msdu_end { * Reserved: HW should fill with zero. FW should ignore. */ -#define RX_PPDU_START_SIG_RATE_SELECT_OFDM 0 -#define RX_PPDU_START_SIG_RATE_SELECT_CCK 1 - -#define RX_PPDU_START_SIG_RATE_OFDM_48 0 -#define RX_PPDU_START_SIG_RATE_OFDM_24 1 -#define RX_PPDU_START_SIG_RATE_OFDM_12 2 -#define RX_PPDU_START_SIG_RATE_OFDM_6 3 -#define RX_PPDU_START_SIG_RATE_OFDM_54 4 -#define RX_PPDU_START_SIG_RATE_OFDM_36 5 -#define RX_PPDU_START_SIG_RATE_OFDM_18 6 -#define RX_PPDU_START_SIG_RATE_OFDM_9 7 - -#define RX_PPDU_START_SIG_RATE_CCK_LP_11 0 -#define RX_PPDU_START_SIG_RATE_CCK_LP_5_5 1 -#define RX_PPDU_START_SIG_RATE_CCK_LP_2 2 -#define RX_PPDU_START_SIG_RATE_CCK_LP_1 3 -#define RX_PPDU_START_SIG_RATE_CCK_SP_11 4 -#define RX_PPDU_START_SIG_RATE_CCK_SP_5_5 5 -#define RX_PPDU_START_SIG_RATE_CCK_SP_2 6 - #define HTT_RX_PPDU_START_PREAMBLE_LEGACY 0x04 #define HTT_RX_PPDU_START_PREAMBLE_HT 0x08 #define HTT_RX_PPDU_START_PREAMBLE_HT_WITH_TXBF 0x09 @@ -711,25 +691,6 @@ struct rx_msdu_end { /* No idea what this flag means. It seems to be always set in rate. */ #define RX_PPDU_START_RATE_FLAG BIT(3) -enum rx_ppdu_start_rate { - RX_PPDU_START_RATE_OFDM_48M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_48M, - RX_PPDU_START_RATE_OFDM_24M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_24M, - RX_PPDU_START_RATE_OFDM_12M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_12M, - RX_PPDU_START_RATE_OFDM_6M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_6M, - RX_PPDU_START_RATE_OFDM_54M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_54M, - RX_PPDU_START_RATE_OFDM_36M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_36M, - RX_PPDU_START_RATE_OFDM_18M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_18M, - RX_PPDU_START_RATE_OFDM_9M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_9M, - - RX_PPDU_START_RATE_CCK_LP_11M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_11M, - RX_PPDU_START_RATE_CCK_LP_5_5M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_5_5M, - RX_PPDU_START_RATE_CCK_LP_2M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_2M, - RX_PPDU_START_RATE_CCK_LP_1M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_1M, - RX_PPDU_START_RATE_CCK_SP_11M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_11M, - RX_PPDU_START_RATE_CCK_SP_5_5M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_5_5M, - RX_PPDU_START_RATE_CCK_SP_2M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_2M, -}; - struct rx_ppdu_start { struct { u8 pri20_mhz; @@ -994,7 +955,41 @@ struct rx_pkt_end { __le32 info0; /* %RX_PKT_END_INFO0_ */ __le32 phy_timestamp_1; __le32 phy_timestamp_2; - __le32 rx_location_info; /* %RX_LOCATION_INFO_ */ +} __packed; + +#define RX_LOCATION_INFO0_RTT_FAC_LEGACY_MASK 0x00003fff +#define RX_LOCATION_INFO0_RTT_FAC_LEGACY_LSB 0 +#define RX_LOCATION_INFO0_RTT_FAC_VHT_MASK 0x1fff8000 +#define RX_LOCATION_INFO0_RTT_FAC_VHT_LSB 15 +#define RX_LOCATION_INFO0_RTT_STRONGEST_CHAIN_MASK 0xc0000000 +#define RX_LOCATION_INFO0_RTT_STRONGEST_CHAIN_LSB 30 +#define RX_LOCATION_INFO0_RTT_FAC_LEGACY_STATUS BIT(14) +#define RX_LOCATION_INFO0_RTT_FAC_VHT_STATUS BIT(29) + +#define RX_LOCATION_INFO1_RTT_PREAMBLE_TYPE_MASK 0x0000000c +#define RX_LOCATION_INFO1_RTT_PREAMBLE_TYPE_LSB 2 +#define RX_LOCATION_INFO1_PKT_BW_MASK 0x00000030 +#define RX_LOCATION_INFO1_PKT_BW_LSB 4 +#define RX_LOCATION_INFO1_SKIP_P_SKIP_BTCF_MASK 0x0000ff00 +#define RX_LOCATION_INFO1_SKIP_P_SKIP_BTCF_LSB 8 +#define RX_LOCATION_INFO1_RTT_MSC_RATE_MASK 0x000f0000 +#define RX_LOCATION_INFO1_RTT_MSC_RATE_LSB 16 +#define RX_LOCATION_INFO1_RTT_PBD_LEG_BW_MASK 0x00300000 +#define RX_LOCATION_INFO1_RTT_PBD_LEG_BW_LSB 20 +#define RX_LOCATION_INFO1_TIMING_BACKOFF_MASK 0x07c00000 +#define RX_LOCATION_INFO1_TIMING_BACKOFF_LSB 22 +#define RX_LOCATION_INFO1_RTT_TX_FRAME_PHASE_MASK 0x18000000 +#define RX_LOCATION_INFO1_RTT_TX_FRAME_PHASE_LSB 27 +#define RX_LOCATION_INFO1_RTT_CFR_STATUS BIT(0) +#define RX_LOCATION_INFO1_RTT_CIR_STATUS BIT(1) +#define RX_LOCATION_INFO1_RTT_GI_TYPE BIT(7) +#define RX_LOCATION_INFO1_RTT_MAC_PHY_PHASE BIT(29) +#define RX_LOCATION_INFO1_RTT_TX_DATA_START_X_PHASE BIT(30) +#define RX_LOCATION_INFO1_RX_LOCATION_VALID BIT(31) + +struct rx_location_info { + __le32 rx_location_info0; /* %RX_LOCATION_INFO0_ */ + __le32 rx_location_info1; /* %RX_LOCATION_INFO1_ */ } __packed; enum rx_phy_ppdu_end_info0 { @@ -1067,6 +1062,17 @@ struct rx_phy_ppdu_end { struct rx_ppdu_end_qca99x0 { struct rx_pkt_end rx_pkt_end; + __le32 rx_location_info; /* %RX_LOCATION_INFO_ */ + struct rx_phy_ppdu_end rx_phy_ppdu_end; + __le32 rx_timing_offset; /* %RX_PPDU_END_RX_TIMING_OFFSET_ */ + __le32 rx_info; /* %RX_PPDU_END_RX_INFO_ */ + __le16 bb_length; + __le16 info1; /* %RX_PPDU_END_INFO1_ */ +} __packed; + +struct rx_ppdu_end_qca9984 { + struct rx_pkt_end rx_pkt_end; + struct rx_location_info rx_location_info; struct rx_phy_ppdu_end rx_phy_ppdu_end; __le32 rx_timing_offset; /* %RX_PPDU_END_RX_TIMING_OFFSET_ */ __le32 rx_info; /* %RX_PPDU_END_RX_INFO_ */ @@ -1080,6 +1086,7 @@ struct rx_ppdu_end { struct rx_ppdu_end_qca988x qca988x; struct rx_ppdu_end_qca6174 qca6174; struct rx_ppdu_end_qca99x0 qca99x0; + struct rx_ppdu_end_qca9984 qca9984; } __packed; } __packed; diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index 4671cfbcd8f7..7d9b0da1b010 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -101,9 +101,9 @@ int ath10k_spectral_process_fft(struct ath10k *ar, break; case 80: /* TODO: As experiments with an analogue sender and various - * configuaritions (fft-sizes of 64/128/256 and 20/40/80 Mhz) + * configurations (fft-sizes of 64/128/256 and 20/40/80 Mhz) * show, the particular configuration of 80 MHz/64 bins does - * not match with the other smaples at all. Until the reason + * not match with the other samples at all. Until the reason * for that is found, don't report these samples. */ if (bin_len == 64) diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index 8e24099fa936..aaf53a81e78b 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -447,6 +447,9 @@ Fw Mode/SubMode Mask #define QCA988X_BOARD_DATA_SZ 7168 #define QCA988X_BOARD_EXT_DATA_SZ 0 +#define QCA9887_BOARD_DATA_SZ 7168 +#define QCA9887_BOARD_EXT_DATA_SZ 0 + #define QCA6174_BOARD_DATA_SZ 8192 #define QCA6174_BOARD_EXT_DATA_SZ 0 diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 576e7c42ed65..b29a86a26c13 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -81,10 +81,11 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, skb_cb = ATH10K_SKB_CB(msdu); txq = skb_cb->txq; - artxq = (void *)txq->drv_priv; - if (txq) + if (txq) { + artxq = (void *)txq->drv_priv; artxq->num_fw_queued--; + } ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); ath10k_htt_tx_dec_pending(htt); @@ -117,6 +118,9 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, ieee80211_tx_status(htt->ar->hw, msdu); /* we do not own the msdu anymore */ + + ath10k_mac_tx_push_pending(ar); + return 0; } @@ -213,6 +217,7 @@ void ath10k_peer_map_event(struct ath10k_htt *htt, ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n", ev->vdev_id, ev->addr, ev->peer_id); + WARN_ON(ar->peer_map[ev->peer_id] && (ar->peer_map[ev->peer_id] != peer)); ar->peer_map[ev->peer_id] = peer; set_bit(ev->peer_id, peer->peer_ids); exit: diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 2c300329ebc3..169cd2e783eb 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1104,6 +1104,7 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = { .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_btcoex = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { @@ -1199,6 +1200,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_btcoex = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = { @@ -1294,6 +1296,7 @@ static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = { .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_btcoex = WMI_PDEV_PARAM_UNSUPPORTED, }; /* firmware 10.2 specific mappings */ @@ -1550,6 +1553,7 @@ static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = { .wapi_mbssid_offset = WMI_10_4_PDEV_PARAM_WAPI_MBSSID_OFFSET, .arp_srcaddr = WMI_10_4_PDEV_PARAM_ARP_SRCADDR, .arp_dstaddr = WMI_10_4_PDEV_PARAM_ARP_DSTADDR, + .enable_btcoex = WMI_10_4_PDEV_PARAM_ENABLE_BTCOEX, }; static const struct wmi_peer_flags_map wmi_peer_flags_map = { @@ -1822,7 +1826,7 @@ static struct sk_buff * ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) { struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu); - struct ath10k_vif *arvif = (void *)cb->vif->drv_priv; + struct ath10k_vif *arvif; struct wmi_mgmt_tx_cmd *cmd; struct ieee80211_hdr *hdr; struct sk_buff *skb; @@ -1834,10 +1838,12 @@ ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) hdr = (struct ieee80211_hdr *)msdu->data; fc = le16_to_cpu(hdr->frame_control); - if (cb->vif) + if (cb->vif) { + arvif = (void *)cb->vif->drv_priv; vdev_id = arvif->vdev_id; - else + } else { vdev_id = 0; + } if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control))) return ERR_PTR(-EINVAL); @@ -2920,6 +2926,7 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar, u32 num_pdev_ext_stats; u32 num_vdev_stats; u32 num_peer_stats; + u32 num_bcnflt_stats; u32 stats_id; int i; @@ -2930,6 +2937,7 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar, num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats); num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); num_peer_stats = __le32_to_cpu(ev->num_peer_stats); + num_bcnflt_stats = __le32_to_cpu(ev->num_bcnflt_stats); stats_id = __le32_to_cpu(ev->stats_id); for (i = 0; i < num_pdev_stats; i++) { @@ -2970,32 +2978,57 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar, /* fw doesn't implement vdev stats */ for (i = 0; i < num_peer_stats; i++) { - const struct wmi_10_4_peer_extd_stats *src; + const struct wmi_10_4_peer_stats *src; struct ath10k_fw_stats_peer *dst; - int stats_len; - bool extd_peer_stats = !!(stats_id & WMI_10_4_STAT_PEER_EXTD); - - if (extd_peer_stats) - stats_len = sizeof(struct wmi_10_4_peer_extd_stats); - else - stats_len = sizeof(struct wmi_10_4_peer_stats); src = (void *)skb->data; - if (!skb_pull(skb, stats_len)) + if (!skb_pull(skb, sizeof(*src))) return -EPROTO; dst = kzalloc(sizeof(*dst), GFP_ATOMIC); if (!dst) continue; - ath10k_wmi_10_4_pull_peer_stats(&src->common, dst); - /* FIXME: expose 10.4 specific values */ - if (extd_peer_stats) - dst->rx_duration = __le32_to_cpu(src->rx_duration); - + ath10k_wmi_10_4_pull_peer_stats(src, dst); list_add_tail(&dst->list, &stats->peers); } + for (i = 0; i < num_bcnflt_stats; i++) { + const struct wmi_10_4_bss_bcn_filter_stats *src; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + /* FIXME: expose values to userspace + * + * Note: Even though this loop seems to do nothing it is + * required to parse following sub-structures properly. + */ + } + + if ((stats_id & WMI_10_4_STAT_PEER_EXTD) == 0) + return 0; + + stats->extended = true; + + for (i = 0; i < num_peer_stats; i++) { + const struct wmi_10_4_peer_extd_stats *src; + struct ath10k_fw_extd_stats_peer *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr); + dst->rx_duration = __le32_to_cpu(src->rx_duration); + list_add_tail(&dst->list, &stats->peers_extd); + } + return 0; } @@ -5253,6 +5286,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_4_PEER_STA_KICKOUT_EVENTID: ath10k_wmi_event_peer_sta_kickout(ar, skb); break; + case WMI_10_4_ROAM_EVENTID: + ath10k_wmi_event_roam(ar, skb); + break; case WMI_10_4_HOST_SWBA_EVENTID: ath10k_wmi_event_host_swba(ar, skb); break; @@ -7899,6 +7935,7 @@ static const struct wmi_ops wmi_10_4_ops = { .pull_phyerr = ath10k_wmi_10_4_op_pull_phyerr_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, + .pull_roam_ev = ath10k_wmi_op_pull_roam_ev, .get_txbf_conf_scheme = ath10k_wmi_10_4_txbf_conf_scheme, .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 9fdf47ea27d0..3ef468893b3f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3447,6 +3447,7 @@ struct wmi_pdev_param_map { u32 wapi_mbssid_offset; u32 arp_srcaddr; u32 arp_dstaddr; + u32 enable_btcoex; }; #define WMI_PDEV_PARAM_UNSUPPORTED 0 @@ -3760,6 +3761,9 @@ enum wmi_10_4_pdev_param { WMI_10_4_PDEV_PARAM_ATF_OBSS_NOISE_SCH, WMI_10_4_PDEV_PARAM_ATF_OBSS_NOISE_SCALING_FACTOR, WMI_10_4_PDEV_PARAM_CUST_TXPOWER_SCALE, + WMI_10_4_PDEV_PARAM_ATF_DYNAMIC_ENABLE, + WMI_10_4_PDEV_PARAM_ATF_SSID_GROUP_POLICY, + WMI_10_4_PDEV_PARAM_ENABLE_BTCOEX, }; struct wmi_pdev_set_param_cmd { @@ -4336,7 +4340,6 @@ struct wmi_10_4_peer_stats { } __packed; struct wmi_10_4_peer_extd_stats { - struct wmi_10_4_peer_stats common; struct wmi_mac_addr peer_macaddr; __le32 inactive_time; __le32 peer_chain_rssi; @@ -4344,6 +4347,19 @@ struct wmi_10_4_peer_extd_stats { __le32 reserved[10]; } __packed; +struct wmi_10_4_bss_bcn_stats { + __le32 vdev_id; + __le32 bss_bcns_dropped; + __le32 bss_bcn_delivered; +} __packed; + +struct wmi_10_4_bss_bcn_filter_stats { + __le32 bcns_dropped; + __le32 bcns_delivered; + __le32 active_filters; + struct wmi_10_4_bss_bcn_stats bss_stats; +} __packed; + struct wmi_10_2_pdev_ext_stats { __le32 rx_rssi_comb; __le32 rx_rssi[4]; diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index fc47b70988b1..f23c851765df 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -219,8 +219,8 @@ ath5k_hw_get_default_sifs(struct ath5k_hw *ah) sifs = AR5K_INIT_SIFS_QUARTER_RATE; break; case AR5K_BWMODE_DEFAULT: - sifs = AR5K_INIT_SIFS_DEFAULT_BG; default: + sifs = AR5K_INIT_SIFS_DEFAULT_BG; if (channel->band == NL80211_BAND_5GHZ) sifs = AR5K_INIT_SIFS_DEFAULT_A; break; diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 4e11ba06f089..4ad6284fc37d 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -847,8 +847,6 @@ static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy, up(&ar->sem); - vif->sme_state = SME_DISCONNECTED; - return 0; } @@ -859,7 +857,11 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, struct ath6kl *ar = vif->ar; if (vif->scan_req) { - cfg80211_scan_done(vif->scan_req, true); + struct cfg80211_scan_info info = { + .aborted = true, + }; + + cfg80211_scan_done(vif->scan_req, &info); vif->scan_req = NULL; } @@ -1069,6 +1071,9 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted) { struct ath6kl *ar = vif->ar; + struct cfg80211_scan_info info = { + .aborted = aborted, + }; int i; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__, @@ -1089,7 +1094,7 @@ void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted) } out: - cfg80211_scan_done(vif->scan_req, aborted); + cfg80211_scan_done(vif->scan_req, &info); vif->scan_req = NULL; } @@ -1104,7 +1109,8 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, cfg80211_chandef_create(&chandef, ieee80211_get_channel(vif->ar->wiphy, freq), - (mode == WMI_11G_HT20) ? + (mode == WMI_11G_HT20 && + ath6kl_band_2ghz.ht_cap.ht_supported) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT); mutex_lock(&vif->wdev.mtx); @@ -2971,6 +2977,7 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx); clear_bit(CONNECTED, &vif->flags); + netif_carrier_off(vif->ndev); /* Restore ht setting in firmware */ return ath6kl_restore_htcap(vif); @@ -3614,7 +3621,11 @@ void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready) } if (vif->scan_req) { - cfg80211_scan_done(vif->scan_req, true); + struct cfg80211_scan_info info = { + .aborted = true, + }; + + cfg80211_scan_done(vif->scan_req, &info); vif->scan_req = NULL; } diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 7a1970e484a6..ac25f1781b42 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -148,7 +148,7 @@ enum ath6kl_fw_capability { /* ratetable is the 2 stream version (max MCS15) */ ATH6KL_FW_CAPABILITY_RATETABLE_MCS15, - /* firmare doesn't support IP checksumming */ + /* firmware doesn't support IP checksumming */ ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM, /* this needs to be last */ diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 40432fe7a5d2..9df41d5e3249 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -1401,6 +1401,10 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) return; } + pad_before_data_start = + (le16_to_cpu(dhdr->info3) >> WMI_DATA_HDR_PAD_BEFORE_DATA_SHIFT) + & WMI_DATA_HDR_PAD_BEFORE_DATA_MASK; + /* Get the Power save state of the STA */ if (vif->nw_type == AP_NETWORK) { meta_type = wmi_data_hdr_get_meta(dhdr); @@ -1408,7 +1412,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) ps_state = !!((dhdr->info >> WMI_DATA_HDR_PS_SHIFT) & WMI_DATA_HDR_PS_MASK); - offset = sizeof(struct wmi_data_hdr); + offset = sizeof(struct wmi_data_hdr) + pad_before_data_start; trig_state = !!(le16_to_cpu(dhdr->info3) & WMI_DATA_HDR_TRIG); switch (meta_type) { @@ -1523,9 +1527,6 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) seq_no = wmi_data_hdr_get_seqno(dhdr); meta_type = wmi_data_hdr_get_meta(dhdr); dot11_hdr = wmi_data_hdr_get_dot11(dhdr); - pad_before_data_start = - (le16_to_cpu(dhdr->info3) >> WMI_DATA_HDR_PAD_BEFORE_DATA_SHIFT) - & WMI_DATA_HDR_PAD_BEFORE_DATA_MASK; skb_pull(skb, sizeof(struct wmi_data_hdr)); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 631c3a0c572b..b8cf04d11975 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2544,8 +2544,7 @@ int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi, u8 if_idx, s32 nominal_phy = 0; int ret; - if (!((params->user_pri < 8) && - (params->user_pri <= 0x7) && + if (!((params->user_pri <= 0x7) && (up_to_ac[params->user_pri & 0x7] == params->traffic_class) && (params->traffic_direc == UPLINK_TRAFFIC || params->traffic_direc == DNLINK_TRAFFIC || diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index bd4a1a655f42..bea6186f745a 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -18,7 +18,6 @@ #include <linux/nl80211.h> #include <linux/platform_device.h> -#include <linux/ath9k_platform.h> #include <linux/module.h> #include "ath9k.h" @@ -58,20 +57,9 @@ static void ath_ahb_read_cachesize(struct ath_common *common, int *csz) static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) { - struct ath_softc *sc = (struct ath_softc *)common->priv; - struct platform_device *pdev = to_platform_device(sc->dev); - struct ath9k_platform_data *pdata; - - pdata = dev_get_platdata(&pdev->dev); - if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { - ath_err(common, - "%s: flash read failed, offset %08x is out of range\n", - __func__, off); - return false; - } - - *data = pdata->eeprom_data[off]; - return true; + ath_err(common, "%s: eeprom data has to be provided externally\n", + __func__); + return false; } static struct ath_bus_ops ath_ahb_bus_ops = { diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 53d7445a5d12..61a9b85045d2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -476,6 +476,7 @@ static void ar9002_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, struct ath_spec_scan *param) { + u32 repeat_bit; u8 count; if (!param->enabled) { @@ -486,12 +487,15 @@ static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA); REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE); + if (AR_SREV_9280(ah)) + repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT; + else + repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI; + if (param->short_repeat) - REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, - AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit); else - REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, - AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); + REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit); /* on AR92xx, the highest bit of count will make the the chip send * spectral samples endlessly. Check if this really was intended, @@ -499,15 +503,25 @@ static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, */ count = param->count; if (param->endless) { - if (AR_SREV_9271(ah)) - count = 0; - else + if (AR_SREV_9280(ah)) count = 0x80; + else + count = 0; } else if (count & 0x80) count = 0x7f; + else if (!count) + count = 1; + + if (AR_SREV_9280(ah)) { + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_COUNT, count); + } else { + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_COUNT_KIWI, count); + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT); + } - REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, - AR_PHY_SPECTRAL_SCAN_COUNT, count); REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_PERIOD, param->period); REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h index 9d17a5375f64..2b58245f774a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h @@ -177,8 +177,11 @@ #define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8 #define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000 /* Number of reports, reg 68, bits 16-23*/ #define AR_PHY_SPECTRAL_SCAN_COUNT_S 16 +#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI 0x0FFF0000 /* Number of reports, reg 68, bits 16-27*/ +#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI_S 16 #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 /* Short repeat, reg 68, bit 24*/ -#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 /* Short repeat, reg 68, bit 24*/ +#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI 0x10000000 /* Short repeat, reg 68, bit 28*/ +#define AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT 0x40000000 #define AR_PHY_RX_DELAY 0x9914 #define AR_PHY_SEARCH_START_DELAY 0x9918 diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 518e649ecff3..b6f064a8d264 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -33,6 +33,7 @@ struct coeff { enum ar9003_cal_types { IQ_MISMATCH_CAL = BIT(0), + TEMP_COMP_CAL = BIT(1), }; static void ar9003_hw_setup_calibration(struct ath_hw *ah, @@ -58,6 +59,12 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah, /* Kick-off cal */ REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); break; + case TEMP_COMP_CAL: + ath_dbg(common, CALIBRATE, + "starting Temperature Compensation Calibration\n"); + REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_LOCAL); + REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_START); + break; default: ath_err(common, "Invalid calibration type\n"); break; @@ -75,50 +82,51 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal) { struct ath9k_hw_cal_data *caldata = ah->caldata; - /* Cal is assumed not done until explicitly set below */ - bool iscaldone = false; + const struct ath9k_percal_data *cur_caldata = currCal->calData; /* Calibration in progress. */ if (currCal->calState == CAL_RUNNING) { /* Check to see if it has finished. */ - if (!(REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) { + if (REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL) + return false; + + /* + * Accumulate cal measures for active chains + */ + if (cur_caldata->calCollect) + cur_caldata->calCollect(ah); + ah->cal_samples++; + + if (ah->cal_samples >= cur_caldata->calNumSamples) { + unsigned int i, numChains = 0; + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (rxchainmask & (1 << i)) + numChains++; + } + /* - * Accumulate cal measures for active chains + * Process accumulated data */ - currCal->calData->calCollect(ah); - ah->cal_samples++; - - if (ah->cal_samples >= - currCal->calData->calNumSamples) { - unsigned int i, numChains = 0; - for (i = 0; i < AR9300_MAX_CHAINS; i++) { - if (rxchainmask & (1 << i)) - numChains++; - } - - /* - * Process accumulated data - */ - currCal->calData->calPostProc(ah, numChains); + if (cur_caldata->calPostProc) + cur_caldata->calPostProc(ah, numChains); - /* Calibration has finished. */ - caldata->CalValid |= currCal->calData->calType; - currCal->calState = CAL_DONE; - iscaldone = true; - } else { + /* Calibration has finished. */ + caldata->CalValid |= cur_caldata->calType; + currCal->calState = CAL_DONE; + return true; + } else { /* * Set-up collection of another sub-sample until we * get desired number */ ar9003_hw_setup_calibration(ah, currCal); - } } - } else if (!(caldata->CalValid & currCal->calData->calType)) { + } else if (!(caldata->CalValid & cur_caldata->calType)) { /* If current cal is marked invalid in channel, kick it off */ ath9k_hw_reset_calibration(ah, currCal); } - return iscaldone; + return false; } static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, @@ -315,9 +323,16 @@ static const struct ath9k_percal_data iq_cal_single_sample = { ar9003_hw_iqcalibrate }; +static const struct ath9k_percal_data temp_cal_single_sample = { + TEMP_COMP_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, +}; + static void ar9003_hw_init_cal_settings(struct ath_hw *ah) { ah->iq_caldata.calData = &iq_cal_single_sample; + ah->temp_caldata.calData = &temp_cal_single_sample; if (AR_SREV_9300_20_OR_LATER(ah)) { ah->enabled_cals |= TX_IQ_CAL; @@ -325,7 +340,7 @@ static void ar9003_hw_init_cal_settings(struct ath_hw *ah) ah->enabled_cals |= TX_IQ_ON_AGC_CAL; } - ah->supp_cals = IQ_MISMATCH_CAL; + ah->supp_cals = IQ_MISMATCH_CAL | TEMP_COMP_CAL; } #define OFF_UPPER_LT 24 @@ -1374,6 +1389,29 @@ static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable) } } +static void ar9003_hw_init_cal_common(struct ath_hw *ah) +{ + struct ath9k_hw_cal_data *caldata = ah->caldata; + + /* Initialize list pointers */ + ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; + + INIT_CAL(&ah->iq_caldata); + INSERT_CAL(ah, &ah->iq_caldata); + + INIT_CAL(&ah->temp_caldata); + INSERT_CAL(ah, &ah->temp_caldata); + + /* Initialize current pointer to first element in list */ + ah->cal_list_curr = ah->cal_list; + + if (ah->cal_list_curr) + ath9k_hw_reset_calibration(ah, ah->cal_list_curr); + + if (caldata) + caldata->CalValid = 0; +} + static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -1533,21 +1571,7 @@ skip_tx_iqcal: /* Revert chainmask to runtime parameters */ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); - /* Initialize list pointers */ - ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; - - INIT_CAL(&ah->iq_caldata); - INSERT_CAL(ah, &ah->iq_caldata); - ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); - - /* Initialize current pointer to first element in list */ - ah->cal_list_curr = ah->cal_list; - - if (ah->cal_list_curr) - ath9k_hw_reset_calibration(ah, ah->cal_list_curr); - - if (caldata) - caldata->CalValid = 0; + ar9003_hw_init_cal_common(ah); return true; } @@ -1578,8 +1602,6 @@ static bool do_ar9003_agc_cal(struct ath_hw *ah) static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_cal_data *caldata = ah->caldata; bool txiqcal_done = false; bool status = true; bool run_agc_cal = false, sep_iq_cal = false; @@ -1677,21 +1699,7 @@ skip_tx_iqcal: /* Revert chainmask to runtime parameters */ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); - /* Initialize list pointers */ - ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; - - INIT_CAL(&ah->iq_caldata); - INSERT_CAL(ah, &ah->iq_caldata); - ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); - - /* Initialize current pointer to first element in list */ - ah->cal_list_curr = ah->cal_list; - - if (ah->cal_list_curr) - ath9k_hw_reset_calibration(ah, ah->cal_list_curr); - - if (caldata) - caldata->CalValid = 0; + ar9003_hw_init_cal_common(ah); return true; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index dec1a317a070..5bd2cbaf582d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3202,8 +3202,7 @@ static int ar9300_compress_decision(struct ath_hw *ah, it, length); break; case _CompressBlock: - if (reference == 0) { - } else { + if (reference != 0) { eep = ar9003_eeprom_struct_find_by_id(reference); if (eep == NULL) { ath_dbg(common, EEPROM, @@ -4176,7 +4175,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah)) ar9003_hw_internal_regulator_apply(ah); ar9003_hw_apply_tuning_caps(ah); - ar9003_hw_apply_minccapwr_thresh(ah, chan); + ar9003_hw_apply_minccapwr_thresh(ah, is2ghz); ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz); ar9003_hw_thermometer_apply(ah); ar9003_hw_thermo_cal_apply(ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 566da789f97e..a171dbb29fbb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -689,13 +689,6 @@ #define AR_CH0_TOP_XPABIASLVL (AR_SREV_9550(ah) ? 0x3c0 : 0x300) #define AR_CH0_TOP_XPABIASLVL_S (AR_SREV_9550(ah) ? 6 : 8) -#define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : \ - ((AR_SREV_9485(ah) ? 0x1628c : 0x16294))) -#define AR_CH0_THERM_XPABIASLVL_MSB 0x3 -#define AR_CH0_THERM_XPABIASLVL_MSB_S 0 -#define AR_CH0_THERM_XPASHORT2GND 0x4 -#define AR_CH0_THERM_XPASHORT2GND_S 2 - #define AR_SWITCH_TABLE_COM_ALL (0xffff) #define AR_SWITCH_TABLE_COM_ALL_S (0) #define AR_SWITCH_TABLE_COM_AR9462_ALL (0xffffff) @@ -712,15 +705,17 @@ #define AR_SWITCH_TABLE_ALL (0xfff) #define AR_SWITCH_TABLE_ALL_S (0) -#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\ - ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16294 : 0x1628c)) +#define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\ + ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16294 : 0x1628c)) +#define AR_CH0_THERM_XPABIASLVL_MSB 0x3 +#define AR_CH0_THERM_XPABIASLVL_MSB_S 0 +#define AR_CH0_THERM_XPASHORT2GND 0x4 +#define AR_CH0_THERM_XPASHORT2GND_S 2 -#define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000 -#define AR_PHY_65NM_CH0_THERM_LOCAL_S 31 -#define AR_PHY_65NM_CH0_THERM_START 0x20000000 -#define AR_PHY_65NM_CH0_THERM_START_S 29 -#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT 0x0000ff00 -#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8 +#define AR_CH0_THERM_LOCAL 0x80000000 +#define AR_CH0_THERM_START 0x20000000 +#define AR_CH0_THERM_SAR_ADC_OUT 0x0000ff00 +#define AR_CH0_THERM_SAR_ADC_OUT_S 8 #define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \ (AR_SREV_9462(ah) ? 0x16290 : 0x16284)) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 93b3793cce2f..26fc8ecfe8c4 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -637,6 +637,8 @@ struct ath9k_vif_iter_data { int nwds; /* number of WDS vifs */ int nadhocs; /* number of adhoc vifs */ int nocbs; /* number of OCB vifs */ + int nbcnvifs; /* number of beaconing vifs */ + struct ieee80211_vif *primary_beacon_vif; struct ieee80211_vif *primary_sta; }; @@ -685,10 +687,11 @@ struct ath_beacon { }; void ath9k_beacon_tasklet(unsigned long data); -void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, - u32 changed); +void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif, + bool beacons); void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif); void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif); +void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc); void ath9k_set_beacon(struct ath_softc *sc); bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif); void ath9k_csa_update(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 5cf0cd7cb2d1..e36f947e19fc 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -50,7 +50,7 @@ static void ath9k_beaconq_config(struct ath_softc *sc) txq = sc->tx.txq_map[IEEE80211_AC_BE]; ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be); qi.tqi_aifs = qi_be.tqi_aifs; - if (ah->slottime == ATH9K_SLOT_TIME_20) + if (ah->slottime == 20) qi.tqi_cwmin = 2*qi_be.tqi_cwmin; else qi.tqi_cwmin = 4*qi_be.tqi_cwmin; @@ -209,7 +209,6 @@ void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif) } sc->beacon.bslot[avp->av_bslot] = vif; - sc->nbcnvifs++; ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n", avp->av_bslot); @@ -220,15 +219,12 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif) struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp = (void *)vif->drv_priv; struct ath_buf *bf = avp->av_bcbuf; - struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n", avp->av_bslot); tasklet_disable(&sc->bcon_tasklet); - cur_conf->enable_beacon &= ~BIT(avp->av_bslot); - if (bf && bf->bf_mpdu) { struct sk_buff *skb = bf->bf_mpdu; dma_unmap_single(sc->dev, bf->bf_buf_addr, @@ -240,12 +236,73 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif) avp->av_bcbuf = NULL; sc->beacon.bslot[avp->av_bslot] = NULL; - sc->nbcnvifs--; list_add_tail(&bf->list, &sc->beacon.bbuf); tasklet_enable(&sc->bcon_tasklet); } +void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_vif *vif; + struct ath_vif *avp; + s64 tsfadjust; + u32 offset; + int first_slot = ATH_BCBUF; + int slot; + + tasklet_disable(&sc->bcon_tasklet); + + /* Find first taken slot. */ + for (slot = 0; slot < ATH_BCBUF; slot++) { + if (sc->beacon.bslot[slot]) { + first_slot = slot; + break; + } + } + if (first_slot == 0) + goto out; + + /* Re-enumarate all slots, moving them forward. */ + for (slot = 0; slot < ATH_BCBUF; slot++) { + if (slot + first_slot < ATH_BCBUF) { + vif = sc->beacon.bslot[slot + first_slot]; + sc->beacon.bslot[slot] = vif; + + if (vif) { + avp = (void *)vif->drv_priv; + avp->av_bslot = slot; + } + } else { + sc->beacon.bslot[slot] = NULL; + } + } + + vif = sc->beacon.bslot[0]; + if (WARN_ON(!vif)) + goto out; + + /* Get the tsf_adjust value for the new first slot. */ + avp = (void *)vif->drv_priv; + tsfadjust = le64_to_cpu(avp->tsf_adjust); + + ath_dbg(common, CONFIG, + "Adjusting global TSF after beacon slot reassignment: %lld\n", + (signed long long)tsfadjust); + + /* Modify TSF as required and update the HW. */ + avp->chanctx->tsf_val += tsfadjust; + if (sc->cur_chan == avp->chanctx) { + offset = ath9k_hw_get_tsf_offset(&avp->chanctx->tsf_ts, NULL); + ath9k_hw_settsf64(sc->sc_ah, avp->chanctx->tsf_val + offset); + } + + /* The slots tsf_adjust will be updated by ath9k_beacon_config later. */ + +out: + tasklet_enable(&sc->bcon_tasklet); +} + static int ath9k_beacon_choose_slot(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -274,22 +331,33 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc) return slot; } -static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif) +static void ath9k_set_tsfadjust(struct ath_softc *sc, + struct ath_beacon_config *cur_conf) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_vif *avp = (void *)vif->drv_priv; - struct ath_beacon_config *cur_conf = &avp->chanctx->beacon; - u32 tsfadjust; + s64 tsfadjust; + int slot; - if (avp->av_bslot == 0) - return; + for (slot = 0; slot < ATH_BCBUF; slot++) { + struct ath_vif *avp; - tsfadjust = cur_conf->beacon_interval * avp->av_bslot; - tsfadjust = TU_TO_USEC(tsfadjust) / ATH_BCBUF; - avp->tsf_adjust = cpu_to_le64(tsfadjust); + if (!sc->beacon.bslot[slot]) + continue; - ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n", - (unsigned long long)tsfadjust, avp->av_bslot); + avp = (void *)sc->beacon.bslot[slot]->drv_priv; + + /* tsf_adjust is added to the TSF value. We send out the + * beacon late, so need to adjust the TSF starting point to be + * later in time (i.e. the theoretical first beacon has a TSF + * of 0 after correction). + */ + tsfadjust = cur_conf->beacon_interval * avp->av_bslot; + tsfadjust = -TU_TO_USEC(tsfadjust) / ATH_BCBUF; + avp->tsf_adjust = cpu_to_le64(tsfadjust); + + ath_dbg(common, CONFIG, "tsfadjust is: %lld for bslot: %d\n", + (signed long long)tsfadjust, avp->av_bslot); + } } bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif) @@ -443,20 +511,28 @@ void ath9k_beacon_tasklet(unsigned long data) * Both nexttbtt and intval have to be in usecs. */ static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, - u32 intval, bool reset_tsf) + u32 intval) { struct ath_hw *ah = sc->sc_ah; ath9k_hw_disable_interrupts(ah); - if (reset_tsf) - ath9k_hw_reset_tsf(ah); ath9k_beaconq_config(sc); ath9k_hw_beaconinit(ah, nexttbtt, intval); + ah->imask |= ATH9K_INT_SWBA; sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); } +static void ath9k_beacon_stop(struct ath_softc *sc) +{ + ath9k_hw_disable_interrupts(sc->sc_ah); + sc->sc_ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + sc->beacon.bmisscnt = 0; + ath9k_hw_set_interrupts(sc->sc_ah); + ath9k_hw_enable_interrupts(sc->sc_ah); +} + /* * For multi-bss ap support beacons are either staggered evenly over N slots or * burst together. For the former arrange for the SWBA to be delivered for each @@ -468,7 +544,7 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc, struct ath_hw *ah = sc->sc_ah; ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF); - ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, false); + ath9k_beacon_init(sc, conf->nexttbtt, conf->intval); } static void ath9k_beacon_config_sta(struct ath_hw *ah, @@ -497,7 +573,7 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, ath9k_cmn_beacon_config_adhoc(ah, conf); - ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, conf->ibss_creator); + ath9k_beacon_init(sc, conf->nexttbtt, conf->intval); /* * Set the global 'beacon has been configured' flag for the @@ -507,44 +583,6 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, set_bit(ATH_OP_BEACONS, &common->op_flags); } -static bool ath9k_allow_beacon_config(struct ath_softc *sc, - struct ieee80211_vif *vif) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_vif *avp = (void *)vif->drv_priv; - - if (ath9k_is_chanctx_enabled()) { - /* - * If the VIF is not present in the current channel context, - * then we can't do the usual opmode checks. Allow the - * beacon config for the VIF to be updated in this case and - * return immediately. - */ - if (sc->cur_chan != avp->chanctx) - return true; - } - - if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { - if (vif->type != NL80211_IFTYPE_AP) { - ath_dbg(common, CONFIG, - "An AP interface is already present !\n"); - return false; - } - } - - if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { - if ((vif->type == NL80211_IFTYPE_STATION) && - test_bit(ATH_OP_BEACONS, &common->op_flags) && - vif != sc->cur_chan->primary_sta) { - ath_dbg(common, CONFIG, - "Beacon already configured for a station interface\n"); - return false; - } - } - - return true; -} - static void ath9k_cache_beacon_config(struct ath_softc *sc, struct ath_chanctx *ctx, struct ieee80211_bss_conf *bss_conf) @@ -580,87 +618,79 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, if (cur_conf->dtim_period == 0) cur_conf->dtim_period = 1; + ath9k_set_tsfadjust(sc, cur_conf); } -void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, - u32 changed) +void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif, + bool beacons) { - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - struct ath_vif *avp = (void *)vif->drv_priv; - struct ath_chanctx *ctx = avp->chanctx; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_vif *avp; + struct ath_chanctx *ctx; struct ath_beacon_config *cur_conf; unsigned long flags; + bool enabled; bool skip_beacon = false; - if (!ctx) + if (!beacons) { + clear_bit(ATH_OP_BEACONS, &common->op_flags); + ath9k_beacon_stop(sc); return; + } - cur_conf = &avp->chanctx->beacon; - if (vif->type == NL80211_IFTYPE_AP) - ath9k_set_tsfadjust(sc, vif); - - if (!ath9k_allow_beacon_config(sc, vif)) + if (WARN_ON(!main_vif)) return; - if (vif->type == NL80211_IFTYPE_STATION) { - ath9k_cache_beacon_config(sc, ctx, bss_conf); - if (ctx != sc->cur_chan) - return; + avp = (void *)main_vif->drv_priv; + ctx = avp->chanctx; + cur_conf = &ctx->beacon; + enabled = cur_conf->enable_beacon; + cur_conf->enable_beacon = beacons; + + if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { + ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf); ath9k_set_beacon(sc); set_bit(ATH_OP_BEACONS, &common->op_flags); return; } - /* - * Take care of multiple interfaces when - * enabling/disabling SWBA. - */ - if (changed & BSS_CHANGED_BEACON_ENABLED) { - bool enabled = cur_conf->enable_beacon; - - if (!bss_conf->enable_beacon) { - cur_conf->enable_beacon &= ~BIT(avp->av_bslot); - } else { - cur_conf->enable_beacon |= BIT(avp->av_bslot); - if (!enabled) - ath9k_cache_beacon_config(sc, ctx, bss_conf); - } - } - - if (ctx != sc->cur_chan) - return; + /* Update the beacon configuration. */ + ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf); /* * Configure the HW beacon registers only when we have a valid * beacon interval. */ if (cur_conf->beacon_interval) { - /* - * If we are joining an existing IBSS network, start beaconing - * only after a TSF-sync has taken place. Ensure that this - * happens by setting the appropriate flags. + /* Special case to sync the TSF when joining an existing IBSS. + * This is only done if no AP interface is active. + * Note that mac80211 always resets the TSF when creating a new + * IBSS interface. */ - if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator && - bss_conf->enable_beacon) { + if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC && + !enabled && beacons && !main_vif->bss_conf.ibss_creator) { spin_lock_irqsave(&sc->sc_pm_lock, flags); sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; spin_unlock_irqrestore(&sc->sc_pm_lock, flags); skip_beacon = true; - } else { - ath9k_set_beacon(sc); } /* * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode * here, it is done in ath9k_beacon_config_adhoc(). */ - if (cur_conf->enable_beacon && !skip_beacon) + if (beacons && !skip_beacon) { set_bit(ATH_OP_BEACONS, &common->op_flags); - else + ath9k_set_beacon(sc); + } else { clear_bit(ATH_OP_BEACONS, &common->op_flags); + ath9k_beacon_stop(sc); + } + } else { + clear_bit(ATH_OP_BEACONS, &common->op_flags); + ath9k_beacon_stop(sc); } } diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index e56bafcf5864..57e26a640477 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -960,6 +960,9 @@ void ath_roc_complete(struct ath_softc *sc, enum ath_roc_complete_reason reason) void ath_scan_complete(struct ath_softc *sc, bool abort) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct cfg80211_scan_info info = { + .aborted = abort, + }; if (abort) ath_dbg(common, CHAN_CTX, "HW scan aborted\n"); @@ -969,7 +972,7 @@ void ath_scan_complete(struct ath_softc *sc, bool abort) sc->offchannel.scan_req = NULL; sc->offchannel.scan_vif = NULL; sc->offchannel.state = ATH_OFFCHANNEL_IDLE; - ieee80211_scan_completed(sc->hw, abort); + ieee80211_scan_completed(sc->hw, &info); clear_bit(ATH_OP_SCANNING, &common->op_flags); spin_lock_bh(&sc->chan_lock); if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index d23737342f4f..f0ab6f9955e4 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -50,6 +50,7 @@ #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) struct ath_beacon_config { + struct ieee80211_vif *main_vif; int beacon_interval; u16 dtim_period; u16 bmiss_timeout; diff --git a/drivers/net/wireless/ath/ath9k/dynack.c b/drivers/net/wireless/ath/ath9k/dynack.c index d2ff0fc0484c..7334c9b09e82 100644 --- a/drivers/net/wireless/ath/ath9k/dynack.c +++ b/drivers/net/wireless/ath/ath9k/dynack.c @@ -280,7 +280,7 @@ EXPORT_SYMBOL(ath_dynack_sample_ack_ts); void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an) { /* ackto = slottime + sifs + air delay */ - u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64; + u32 ackto = 9 + 16 + 64; struct ath_dynack *da = &ah->dynack; an->ackto = ackto; @@ -315,7 +315,7 @@ EXPORT_SYMBOL(ath_dynack_node_deinit); void ath_dynack_reset(struct ath_hw *ah) { /* ackto = slottime + sifs + air delay */ - u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64; + u32 ackto = 9 + 16 + 64; struct ath_dynack *da = &ah->dynack; da->lto = jiffies; diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index a794157a147d..a449588a8009 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -15,6 +15,7 @@ */ #include "hw.h" +#include <linux/ath9k_platform.h> void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val) { @@ -108,26 +109,42 @@ void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, } } -static bool ath9k_hw_nvram_read_blob(struct ath_hw *ah, u32 off, - u16 *data) +static bool ath9k_hw_nvram_read_array(u16 *blob, size_t blob_size, + off_t offset, u16 *data) { - u16 *blob_data; - - if (off * sizeof(u16) > ah->eeprom_blob->size) + if (offset > blob_size) return false; - blob_data = (u16 *)ah->eeprom_blob->data; - *data = blob_data[off]; + *data = blob[offset]; return true; } +static bool ath9k_hw_nvram_read_pdata(struct ath9k_platform_data *pdata, + off_t offset, u16 *data) +{ + return ath9k_hw_nvram_read_array(pdata->eeprom_data, + ARRAY_SIZE(pdata->eeprom_data), + offset, data); +} + +static bool ath9k_hw_nvram_read_firmware(const struct firmware *eeprom_blob, + off_t offset, u16 *data) +{ + return ath9k_hw_nvram_read_array((u16 *) eeprom_blob->data, + eeprom_blob->size / sizeof(u16), + offset, data); +} + bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) { struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_platform_data *pdata = ah->dev->platform_data; bool ret; if (ah->eeprom_blob) - ret = ath9k_hw_nvram_read_blob(ah, off, data); + ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data); + else if (pdata && !pdata->use_eeprom && pdata->eeprom_data) + ret = ath9k_hw_nvram_read_pdata(pdata, off, data); else ret = common->bus_ops->eeprom_read(common, off, data); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index e6bcb4c90fa0..2c0e4d26e8f9 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -45,7 +45,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) * Long slot time : 2x cwmin * Short slot time : 4x cwmin */ - if (ah->slottime == ATH9K_SLOT_TIME_20) + if (ah->slottime == 20) qi.tqi_cwmin = 2*qi_be.tqi_cwmin; else qi.tqi_cwmin = 4*qi_be.tqi_cwmin; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index c148c6c504f7..b65c1b661ade 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -678,7 +678,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) priv->beacon.bslot[i] = NULL; - priv->beacon.slottime = ATH9K_SLOT_TIME_9; + priv->beacon.slottime = 9; ath9k_cmn_init_channels_rates(common); ath9k_cmn_init_crypto(ah); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8b2895f9ac7a..d1d0c06d627c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -454,7 +454,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) if (AR_SREV_9100(ah)) ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX; - ah->slottime = ATH9K_SLOT_TIME_9; + ah->slottime = 9; ah->globaltxtimeout = (u32) -1; ah->power_mode = ATH9K_PM_UNDEFINED; ah->htc_reset_init = true; @@ -471,33 +471,34 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S); } -static int ath9k_hw_init_macaddr(struct ath_hw *ah) +static void ath9k_hw_init_macaddr(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - u32 sum; int i; u16 eeval; static const u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW }; - sum = 0; + /* MAC address may already be loaded via ath9k_platform_data */ + if (is_valid_ether_addr(common->macaddr)) + return; + for (i = 0; i < 3; i++) { eeval = ah->eep_ops->get_eeprom(ah, EEP_MAC[i]); - sum += eeval; common->macaddr[2 * i] = eeval >> 8; common->macaddr[2 * i + 1] = eeval & 0xff; } - if (!is_valid_ether_addr(common->macaddr)) { - ath_err(common, - "eeprom contains invalid mac address: %pM\n", - common->macaddr); - random_ether_addr(common->macaddr); - ath_err(common, - "random mac address will be used: %pM\n", - common->macaddr); - } + if (is_valid_ether_addr(common->macaddr)) + return; - return 0; + ath_err(common, "eeprom contains invalid mac address: %pM\n", + common->macaddr); + + random_ether_addr(common->macaddr); + ath_err(common, "random mac address will be used: %pM\n", + common->macaddr); + + return; } static int ath9k_hw_post_init(struct ath_hw *ah) @@ -636,12 +637,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (r) return r; - r = ath9k_hw_init_macaddr(ah); - if (r) { - ath_err(common, "Failed to initialize MAC address\n"); - return r; - } - + ath9k_hw_init_macaddr(ah); ath9k_hw_init_hang_checks(ah); common->state = ATH_HW_INITIALIZED; @@ -1832,8 +1828,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, u32 saveLedState; u32 saveDefAntenna; u32 macStaId1; + struct timespec tsf_ts; + u32 tsf_offset; u64 tsf = 0; - s64 usec = 0; int r; bool start_mci_reset = false; bool save_fullsleep = ah->chip_fullsleep; @@ -1877,8 +1874,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; /* Save TSF before chip reset, a cold reset clears it */ + getrawmonotonic(&tsf_ts); tsf = ath9k_hw_gettsf64(ah); - usec = ktime_to_us(ktime_get_raw()); saveLedState = REG_READ(ah, AR_CFG_LED) & (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | @@ -1911,8 +1908,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, } /* Restore TSF */ - usec = ktime_to_us(ktime_get_raw()) - usec; - ath9k_hw_settsf64(ah, tsf + usec); + tsf_offset = ath9k_hw_get_tsf_offset(&tsf_ts, NULL); + ath9k_hw_settsf64(ah, tsf + tsf_offset); if (AR_SREV_9280_20_OR_LATER(ah)) REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); @@ -1932,12 +1929,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, /* * Some AR91xx SoC devices frequently fail to accept TSF writes * right after the chip reset. When that happens, write a new - * value after the initvals have been applied, with an offset - * based on measured time difference + * value after the initvals have been applied. */ if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) { - tsf += 1500; - ath9k_hw_settsf64(ah, tsf); + tsf_offset = ath9k_hw_get_tsf_offset(&tsf_ts, NULL); + ath9k_hw_settsf64(ah, tsf + tsf_offset); } ath9k_hw_init_mfp(ah); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 9cbca1229bac..2a5d3ad1169c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -830,6 +830,7 @@ struct ath_hw { /* Calibration */ u32 supp_cals; struct ath9k_cal_list iq_caldata; + struct ath9k_cal_list temp_caldata; struct ath9k_cal_list adcgain_caldata; struct ath9k_cal_list adcdc_caldata; struct ath9k_cal_list *cal_list; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 2ee8624755f7..edc74fca60aa 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -372,7 +372,7 @@ static void ath9k_init_misc(struct ath_softc *sc) common->last_rssi = ATH_RSSI_DUMMY_MARKER; memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); - sc->beacon.slottime = ATH9K_SLOT_TIME_9; + sc->beacon.slottime = 9; for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) sc->beacon.bslot[i] = NULL; @@ -512,31 +512,52 @@ static void ath9k_eeprom_release(struct ath_softc *sc) release_firmware(sc->sc_ah->eeprom_blob); } -static int ath9k_init_soc_platform(struct ath_softc *sc) +static int ath9k_init_platform(struct ath_softc *sc) { struct ath9k_platform_data *pdata = sc->dev->platform_data; struct ath_hw *ah = sc->sc_ah; - int ret = 0; + struct ath_common *common = ath9k_hw_common(ah); + int ret; if (!pdata) return 0; + if (!pdata->use_eeprom) { + ah->ah_flags &= ~AH_USE_EEPROM; + ah->gpio_mask = pdata->gpio_mask; + ah->gpio_val = pdata->gpio_val; + ah->led_pin = pdata->led_pin; + ah->is_clk_25mhz = pdata->is_clk_25mhz; + ah->get_mac_revision = pdata->get_mac_revision; + ah->external_reset = pdata->external_reset; + ah->disable_2ghz = pdata->disable_2ghz; + ah->disable_5ghz = pdata->disable_5ghz; + + if (!pdata->endian_check) + ah->ah_flags |= AH_NO_EEP_SWAP; + } + if (pdata->eeprom_name) { ret = ath9k_eeprom_request(sc, pdata->eeprom_name); if (ret) return ret; } + if (pdata->led_active_high) + ah->config.led_active_high = true; + if (pdata->tx_gain_buffalo) ah->config.tx_gain_buffalo = true; - return ret; + if (pdata->macaddr) + ether_addr_copy(common->macaddr, pdata->macaddr); + + return 0; } static int ath9k_init_softc(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops) { - struct ath9k_platform_data *pdata = sc->dev->platform_data; struct ath_hw *ah = NULL; struct ath9k_hw_capabilities *pCap; struct ath_common *common; @@ -550,6 +571,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ah->dev = sc->dev; ah->hw = sc->hw; ah->hw_version.devid = devid; + ah->ah_flags |= AH_USE_EEPROM; + ah->led_pin = -1; ah->reg_ops.read = ath9k_ioread32; ah->reg_ops.multi_read = ath9k_multi_ioread32; ah->reg_ops.write = ath9k_iowrite32; @@ -569,22 +592,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, if (!ath9k_is_chanctx_enabled()) sc->cur_chan->hw_queue_base = 0; - if (!pdata || pdata->use_eeprom) { - ah->ah_flags |= AH_USE_EEPROM; - sc->sc_ah->led_pin = -1; - } else { - sc->sc_ah->gpio_mask = pdata->gpio_mask; - sc->sc_ah->gpio_val = pdata->gpio_val; - sc->sc_ah->led_pin = pdata->led_pin; - ah->is_clk_25mhz = pdata->is_clk_25mhz; - ah->get_mac_revision = pdata->get_mac_revision; - ah->external_reset = pdata->external_reset; - ah->disable_2ghz = pdata->disable_2ghz; - ah->disable_5ghz = pdata->disable_5ghz; - if (!pdata->endian_check) - ah->ah_flags |= AH_NO_EEP_SWAP; - } - common->ops = &ah->reg_ops; common->bus_ops = bus_ops; common->ps_ops = &ath9k_ps_ops; @@ -600,7 +607,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, */ ath9k_init_pcoem_platform(sc); - ret = ath9k_init_soc_platform(sc); + ret = ath9k_init_platform(sc); if (ret) return ret; @@ -646,9 +653,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, if (ret) goto err_hw; - if (pdata && pdata->macaddr) - memcpy(common->macaddr, pdata->macaddr, ETH_ALEN); - ret = ath9k_init_queues(sc); if (ret) goto err_queues; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 7fbf7f965f61..3bab01435a86 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -65,10 +65,6 @@ #define INIT_SSH_RETRY 32 #define INIT_SLG_RETRY 32 -#define ATH9K_SLOT_TIME_6 6 -#define ATH9K_SLOT_TIME_9 9 -#define ATH9K_SLOT_TIME_20 20 - #define ATH9K_TXERR_XRETRY 0x01 #define ATH9K_TXERR_FILT 0x02 #define ATH9K_TXERR_FIFO 0x04 diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 8b6398850657..7594650f214f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -910,6 +910,22 @@ static bool ath9k_uses_beacons(int type) } } +static void ath9k_vif_iter_set_beacon(struct ath9k_vif_iter_data *iter_data, + struct ieee80211_vif *vif) +{ + /* Use the first (configured) interface, but prefering AP interfaces. */ + if (!iter_data->primary_beacon_vif) { + iter_data->primary_beacon_vif = vif; + } else { + if (iter_data->primary_beacon_vif->type != NL80211_IFTYPE_AP && + vif->type == NL80211_IFTYPE_AP) + iter_data->primary_beacon_vif = vif; + } + + iter_data->beacons = true; + iter_data->nbcnvifs += 1; +} + static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data, u8 *mac, struct ieee80211_vif *vif) { @@ -926,11 +942,13 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data, } if (!vif->bss_conf.use_short_slot) - iter_data->slottime = ATH9K_SLOT_TIME_20; + iter_data->slottime = 20; switch (vif->type) { case NL80211_IFTYPE_AP: iter_data->naps++; + if (vif->bss_conf.enable_beacon) + ath9k_vif_iter_set_beacon(iter_data, vif); break; case NL80211_IFTYPE_STATION: iter_data->nstations++; @@ -943,12 +961,12 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data, case NL80211_IFTYPE_ADHOC: iter_data->nadhocs++; if (vif->bss_conf.enable_beacon) - iter_data->beacons = true; + ath9k_vif_iter_set_beacon(iter_data, vif); break; case NL80211_IFTYPE_MESH_POINT: iter_data->nmeshes++; if (vif->bss_conf.enable_beacon) - iter_data->beacons = true; + ath9k_vif_iter_set_beacon(iter_data, vif); break; case NL80211_IFTYPE_WDS: iter_data->nwds++; @@ -999,7 +1017,7 @@ void ath9k_calculate_iter_data(struct ath_softc *sc, */ memset(iter_data, 0, sizeof(*iter_data)); eth_broadcast_addr(iter_data->mask); - iter_data->slottime = ATH9K_SLOT_TIME_9; + iter_data->slottime = 9; list_for_each_entry(avp, &ctx->vifs, list) ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif); @@ -1061,7 +1079,7 @@ static void ath9k_set_offchannel_state(struct ath_softc *sc) ah->opmode = vif->type; ah->imask &= ~ATH9K_INT_SWBA; ah->imask &= ~ATH9K_INT_TSFOOR; - ah->slottime = ATH9K_SLOT_TIME_9; + ah->slottime = 9; ath_hw_setbssidmask(common); ath9k_hw_setopmode(ah); @@ -1081,7 +1099,6 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_vif_iter_data iter_data; - struct ath_beacon_config *cur_conf; ath_chanctx_check_active(sc, ctx); @@ -1103,13 +1120,12 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, ath_hw_setbssidmask(common); if (iter_data.naps > 0) { - cur_conf = &ctx->beacon; ath9k_hw_set_tsfadjust(ah, true); ah->opmode = NL80211_IFTYPE_AP; - if (cur_conf->enable_beacon) - iter_data.beacons = true; } else { ath9k_hw_set_tsfadjust(ah, false); + if (iter_data.beacons) + ath9k_beacon_ensure_primary_slot(sc); if (iter_data.nmeshes) ah->opmode = NL80211_IFTYPE_MESH_POINT; @@ -1134,7 +1150,6 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, ctx->switch_after_beacon = true; } - ah->imask &= ~ATH9K_INT_SWBA; if (ah->opmode == NL80211_IFTYPE_STATION) { bool changed = (iter_data.primary_sta != ctx->primary_sta); @@ -1151,16 +1166,12 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, if (ath9k_hw_mci_is_enabled(sc->sc_ah)) ath9k_mci_update_wlan_channels(sc, true); } - } else if (iter_data.beacons) { - ah->imask |= ATH9K_INT_SWBA; } + sc->nbcnvifs = iter_data.nbcnvifs; + ath9k_beacon_config(sc, iter_data.primary_beacon_vif, + iter_data.beacons); ath9k_hw_set_interrupts(ah); - if (iter_data.beacons) - set_bit(ATH_OP_BEACONS, &common->op_flags); - else - clear_bit(ATH_OP_BEACONS, &common->op_flags); - if (ah->slottime != iter_data.slottime) { ah->slottime = iter_data.slottime; ath9k_hw_init_global_settings(ah); @@ -1777,9 +1788,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if ((changed & BSS_CHANGED_BEACON_ENABLED) || (changed & BSS_CHANGED_BEACON_INT) || (changed & BSS_CHANGED_BEACON_INFO)) { - ath9k_beacon_config(sc, vif, changed); - if (changed & BSS_CHANGED_BEACON_ENABLED) - ath9k_calculate_summary_state(sc, avp->chanctx); + ath9k_calculate_summary_state(sc, avp->chanctx); } if ((avp->chanctx == sc->cur_chan) && @@ -1788,6 +1797,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, slottime = 9; else slottime = 20; + if (vif->type == NL80211_IFTYPE_AP) { /* * Defer update, so that connected stations can adjust @@ -1823,11 +1833,19 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; + struct ath_vif *avp = (void *)vif->drv_priv; u64 tsf; mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - tsf = ath9k_hw_gettsf64(sc->sc_ah); + /* Get current TSF either from HW or kernel time. */ + if (sc->cur_chan == avp->chanctx) { + tsf = ath9k_hw_gettsf64(sc->sc_ah); + } else { + tsf = sc->cur_chan->tsf_val + + ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL); + } + tsf += le64_to_cpu(avp->tsf_adjust); ath9k_ps_restore(sc); mutex_unlock(&sc->mutex); @@ -1839,10 +1857,15 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) { struct ath_softc *sc = hw->priv; + struct ath_vif *avp = (void *)vif->drv_priv; mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - ath9k_hw_settsf64(sc->sc_ah, tsf); + tsf -= le64_to_cpu(avp->tsf_adjust); + getrawmonotonic(&avp->chanctx->tsf_ts); + if (sc->cur_chan == avp->chanctx) + ath9k_hw_settsf64(sc->sc_ah, tsf); + avp->chanctx->tsf_val = tsf; ath9k_ps_restore(sc); mutex_unlock(&sc->mutex); } @@ -1850,11 +1873,15 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; + struct ath_vif *avp = (void *)vif->drv_priv; mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - ath9k_hw_reset_tsf(sc->sc_ah); + getrawmonotonic(&avp->chanctx->tsf_ts); + if (sc->cur_chan == avp->chanctx) + ath9k_hw_reset_tsf(sc->sc_ah); + avp->chanctx->tsf_val = 0; ath9k_ps_restore(sc); mutex_unlock(&sc->mutex); diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 7cdaf40c3057..0dd454acf22a 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -19,7 +19,6 @@ #include <linux/nl80211.h> #include <linux/pci.h> #include <linux/pci-aspm.h> -#include <linux/ath9k_platform.h> #include <linux/module.h> #include "ath9k.h" @@ -786,35 +785,21 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) { - struct ath_softc *sc = (struct ath_softc *) common->priv; - struct ath9k_platform_data *pdata = sc->dev->platform_data; - - if (pdata && !pdata->use_eeprom) { - if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { - ath_err(common, - "%s: eeprom read failed, offset %08x is out of range\n", - __func__, off); - } - - *data = pdata->eeprom_data[off]; - } else { - struct ath_hw *ah = (struct ath_hw *) common->ah; - - common->ops->read(ah, AR5416_EEPROM_OFFSET + - (off << AR5416_EEPROM_S)); - - if (!ath9k_hw_wait(ah, - AR_EEPROM_STATUS_DATA, - AR_EEPROM_STATUS_DATA_BUSY | - AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, - AH_WAIT_TIMEOUT)) { - return false; - } - - *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA), - AR_EEPROM_STATUS_DATA_VAL); + struct ath_hw *ah = (struct ath_hw *) common->ah; + + common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); + + if (!ath9k_hw_wait(ah, + AR_EEPROM_STATUS_DATA, + AR_EEPROM_STATUS_DATA_BUSY | + AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, + AH_WAIT_TIMEOUT)) { + return false; } + *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA), + AR_EEPROM_STATUS_DATA_VAL); + return true; } diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index ac4781f37e78..16aca9e28b77 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -132,7 +132,6 @@ static int ath9k_tx99_init(struct ath_softc *sc) ath9k_ps_wakeup(sc); ath9k_hw_disable_interrupts(ah); - atomic_set(&ah->intr_ref_cnt, -1); ath_drain_all_txq(sc); ath_stoprecv(sc); @@ -266,7 +265,7 @@ static const struct file_operations fops_tx99_power = { void ath9k_tx99_init_debug(struct ath_softc *sc) { - if (!AR_SREV_9300_20_OR_LATER(sc->sc_ah)) + if (!AR_SREV_9280_20_OR_LATER(sc->sc_ah)) return; debugfs_create_file("tx99", S_IRUSR | S_IWUSR, diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig index 1a796e5f69ec..2e34baeaf764 100644 --- a/drivers/net/wireless/ath/carl9170/Kconfig +++ b/drivers/net/wireless/ath/carl9170/Kconfig @@ -5,12 +5,10 @@ config CARL9170 select FW_LOADER select CRC32 help - This is another driver for the Atheros "otus" 802.11n USB devices. + This is the mainline driver for the Atheros "otus" 802.11n USB devices. - This driver provides more features than the original, - but it needs a special firmware (carl9170-1.fw) to do that. - - The firmware can be downloaded from our wiki here: + It needs a special firmware (carl9170-1.fw), which can be downloaded + from our wiki here: <http://wireless.kernel.org/en/users/Drivers/carl9170> If you choose to build a module, it'll be called carl9170. diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 8643801f31b6..231fd022f0f5 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -35,26 +35,27 @@ void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low) return ch->head_blk_ctl->bd_cpu_addr; } +static void wcn36xx_ccu_write_register(struct wcn36xx *wcn, int addr, int data) +{ + wcn36xx_dbg(WCN36XX_DBG_DXE, + "wcn36xx_ccu_write_register: addr=%x, data=%x\n", + addr, data); + + writel(data, wcn->ccu_base + addr); +} + static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data) { wcn36xx_dbg(WCN36XX_DBG_DXE, "wcn36xx_dxe_write_register: addr=%x, data=%x\n", addr, data); - writel(data, wcn->mmio + addr); + writel(data, wcn->dxe_base + addr); } -#define wcn36xx_dxe_write_register_x(wcn, reg, reg_data) \ -do { \ - if (wcn->chip_version == WCN36XX_CHIP_3680) \ - wcn36xx_dxe_write_register(wcn, reg ## _3680, reg_data); \ - else \ - wcn36xx_dxe_write_register(wcn, reg ## _3660, reg_data); \ -} while (0) \ - static void wcn36xx_dxe_read_register(struct wcn36xx *wcn, int addr, int *data) { - *data = readl(wcn->mmio + addr); + *data = readl(wcn->dxe_base + addr); wcn36xx_dbg(WCN36XX_DBG_DXE, "wcn36xx_dxe_read_register: addr=%x, data=%x\n", @@ -701,9 +702,13 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) reg_data = WCN36XX_DXE_REG_RESET; wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CSR_RESET, reg_data); - /* Setting interrupt path */ - reg_data = WCN36XX_DXE_CCU_INT; - wcn36xx_dxe_write_register_x(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data); + /* Select channels for rx avail and xfer done interrupts... */ + reg_data = (WCN36XX_DXE_INT_CH3_MASK | WCN36XX_DXE_INT_CH1_MASK) << 16 | + WCN36XX_DXE_INT_CH0_MASK | WCN36XX_DXE_INT_CH4_MASK; + if (wcn->is_pronto) + wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_PRONTO, reg_data); + else + wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_RIVA, reg_data); /***************************************/ /* Init descriptors for TX LOW channel */ diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h index 3eca4f9594f2..c012e807753b 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.h +++ b/drivers/net/wireless/ath/wcn36xx/dxe.h @@ -28,11 +28,10 @@ H2H_TEST_RX_TX = DMA2 */ /* DXE registers */ -#define WCN36XX_DXE_MEM_REG 0x202000 +#define WCN36XX_DXE_MEM_REG 0 -#define WCN36XX_DXE_CCU_INT 0xA0011 -#define WCN36XX_DXE_REG_CCU_INT_3660 0x200b10 -#define WCN36XX_DXE_REG_CCU_INT_3680 0x2050dc +#define WCN36XX_CCU_DXE_INT_SELECT_RIVA 0x310 +#define WCN36XX_CCU_DXE_INT_SELECT_PRONTO 0x10dc /* TODO This must calculated properly but not hardcoded */ #define WCN36XX_DXE_CTRL_TX_L 0x328a44 diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index 658bfb8baabe..4f87ef1e1eb8 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -4123,7 +4123,7 @@ struct wcn36xx_hal_update_scan_params_req { /* Update scan params - sent from host to PNO to be used during PNO * scanningx */ -struct update_scan_params_req_ex { +struct wcn36xx_hal_update_scan_params_req_ex { struct wcn36xx_hal_msg_header header; @@ -4151,7 +4151,7 @@ struct update_scan_params_req_ex { /* Cb State */ enum phy_chan_bond_state state; -}; +} __packed; /* Update scan params - sent from host to PNO to be used during PNO * scanningx */ diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index a920d7020148..e1d59da2ad20 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -19,6 +19,8 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/platform_device.h> +#include <linux/of_address.h> +#include <linux/of_device.h> #include "wcn36xx.h" unsigned int wcn36xx_dbg_mask; @@ -259,17 +261,6 @@ static void wcn36xx_feat_caps_info(struct wcn36xx *wcn) } } -static void wcn36xx_detect_chip_version(struct wcn36xx *wcn) -{ - if (get_feat_caps(wcn->fw_feat_caps, DOT11AC)) { - wcn36xx_info("Chip is 3680\n"); - wcn->chip_version = WCN36XX_CHIP_3680; - } else { - wcn36xx_info("Chip is 3660\n"); - wcn->chip_version = WCN36XX_CHIP_3660; - } -} - static int wcn36xx_start(struct ieee80211_hw *hw) { struct wcn36xx *wcn = hw->priv; @@ -324,9 +315,6 @@ static int wcn36xx_start(struct ieee80211_hw *hw) wcn36xx_feat_caps_info(wcn); } - wcn36xx_detect_chip_version(wcn); - wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_ENABLE_MC_ADDR_LIST, 1); - /* DMA channel initialization */ ret = wcn36xx_dxe_init(wcn); if (ret) { @@ -1064,7 +1052,11 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) static int wcn36xx_platform_get_resources(struct wcn36xx *wcn, struct platform_device *pdev) { + struct device_node *mmio_node; struct resource *res; + int index; + int ret; + /* Set TX IRQ */ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "wcnss_wlantx_irq"); @@ -1083,19 +1075,40 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn, } wcn->rx_irq = res->start; - /* Map the memory */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "wcnss_mmio"); - if (!res) { - wcn36xx_err("failed to get mmio\n"); - return -ENOENT; + mmio_node = of_parse_phandle(pdev->dev.parent->of_node, "qcom,mmio", 0); + if (!mmio_node) { + wcn36xx_err("failed to acquire qcom,mmio reference\n"); + return -EINVAL; } - wcn->mmio = ioremap(res->start, resource_size(res)); - if (!wcn->mmio) { - wcn36xx_err("failed to map io memory\n"); - return -ENOMEM; + + wcn->is_pronto = !!of_device_is_compatible(mmio_node, "qcom,pronto"); + + /* Map the CCU memory */ + index = of_property_match_string(mmio_node, "reg-names", "ccu"); + wcn->ccu_base = of_iomap(mmio_node, index); + if (!wcn->ccu_base) { + wcn36xx_err("failed to map ccu memory\n"); + ret = -ENOMEM; + goto put_mmio_node; } + + /* Map the DXE memory */ + index = of_property_match_string(mmio_node, "reg-names", "dxe"); + wcn->dxe_base = of_iomap(mmio_node, index); + if (!wcn->dxe_base) { + wcn36xx_err("failed to map dxe memory\n"); + ret = -ENOMEM; + goto unmap_ccu; + } + + of_node_put(mmio_node); return 0; + +unmap_ccu: + iounmap(wcn->ccu_base); +put_mmio_node: + of_node_put(mmio_node); + return ret; } static int wcn36xx_probe(struct platform_device *pdev) @@ -1138,7 +1151,8 @@ static int wcn36xx_probe(struct platform_device *pdev) return 0; out_unmap: - iounmap(wcn->mmio); + iounmap(wcn->ccu_base); + iounmap(wcn->dxe_base); out_wq: ieee80211_free_hw(hw); out_err: @@ -1154,7 +1168,8 @@ static int wcn36xx_remove(struct platform_device *pdev) mutex_destroy(&wcn->hal_mutex); ieee80211_unregister_hw(hw); - iounmap(wcn->mmio); + iounmap(wcn->dxe_base); + iounmap(wcn->ccu_base); ieee80211_free_hw(hw); return 0; diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index e8b630c4f11e..a443992320f2 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -674,22 +674,25 @@ static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len) return 0; } -int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn) +int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, + u8 *channels, size_t channel_count) { - struct wcn36xx_hal_update_scan_params_req msg_body; + struct wcn36xx_hal_update_scan_params_req_ex msg_body; int ret = 0; mutex_lock(&wcn->hal_mutex); INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ); - msg_body.dot11d_enabled = 0; - msg_body.dot11d_resolved = 0; - msg_body.channel_count = 26; + msg_body.dot11d_enabled = false; + msg_body.dot11d_resolved = true; + + msg_body.channel_count = channel_count; + memcpy(msg_body.channels, channels, channel_count); msg_body.active_min_ch_time = 60; msg_body.active_max_ch_time = 120; msg_body.passive_min_ch_time = 60; msg_body.passive_max_ch_time = 110; - msg_body.state = 0; + msg_body.state = PHY_SINGLE_CHANNEL_CENTERED; PREPARE_HAL_BUF(wcn->hal_buf, msg_body); @@ -2226,17 +2229,12 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len) case WCN36XX_HAL_COEX_IND: case WCN36XX_HAL_AVOID_FREQ_RANGE_IND: + case WCN36XX_HAL_DEL_BA_IND: case WCN36XX_HAL_OTA_TX_COMPL_IND: case WCN36XX_HAL_MISSED_BEACON_IND: case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: - msg_ind = kmalloc(sizeof(*msg_ind), GFP_KERNEL); - if (!msg_ind) - goto nomem; - msg_ind->msg_len = len; - msg_ind->msg = kmemdup(buf, len, GFP_KERNEL); - if (!msg_ind->msg) { - kfree(msg_ind); -nomem: + msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_KERNEL); + if (!msg_ind) { /* * FIXME: Do something smarter then just * printing an error. @@ -2245,10 +2243,14 @@ nomem: msg_header->msg_type); break; } - mutex_lock(&wcn->hal_ind_mutex); + + msg_ind->msg_len = len; + memcpy(msg_ind->msg, buf, len); + + spin_lock(&wcn->hal_ind_lock); list_add_tail(&msg_ind->list, &wcn->hal_ind_queue); queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work); - mutex_unlock(&wcn->hal_ind_mutex); + spin_unlock(&wcn->hal_ind_lock); wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n"); break; default: @@ -2262,8 +2264,9 @@ static void wcn36xx_ind_smd_work(struct work_struct *work) container_of(work, struct wcn36xx, hal_ind_work); struct wcn36xx_hal_msg_header *msg_header; struct wcn36xx_hal_ind_msg *hal_ind_msg; + unsigned long flags; - mutex_lock(&wcn->hal_ind_mutex); + spin_lock_irqsave(&wcn->hal_ind_lock, flags); hal_ind_msg = list_first_entry(&wcn->hal_ind_queue, struct wcn36xx_hal_ind_msg, @@ -2273,6 +2276,7 @@ static void wcn36xx_ind_smd_work(struct work_struct *work) switch (msg_header->msg_type) { case WCN36XX_HAL_COEX_IND: + case WCN36XX_HAL_DEL_BA_IND: case WCN36XX_HAL_AVOID_FREQ_RANGE_IND: break; case WCN36XX_HAL_OTA_TX_COMPL_IND: @@ -2295,9 +2299,8 @@ static void wcn36xx_ind_smd_work(struct work_struct *work) msg_header->msg_type); } list_del(wcn->hal_ind_queue.next); - kfree(hal_ind_msg->msg); + spin_unlock_irqrestore(&wcn->hal_ind_lock, flags); kfree(hal_ind_msg); - mutex_unlock(&wcn->hal_ind_mutex); } int wcn36xx_smd_open(struct wcn36xx *wcn) { @@ -2310,7 +2313,7 @@ int wcn36xx_smd_open(struct wcn36xx *wcn) } INIT_WORK(&wcn->hal_ind_work, wcn36xx_ind_smd_work); INIT_LIST_HEAD(&wcn->hal_ind_queue); - mutex_init(&wcn->hal_ind_mutex); + spin_lock_init(&wcn->hal_ind_lock); ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process); if (ret) { @@ -2330,5 +2333,4 @@ void wcn36xx_smd_close(struct wcn36xx *wcn) { wcn->ctrl_ops->close(); destroy_workqueue(wcn->hal_ind_wq); - mutex_destroy(&wcn->hal_ind_mutex); } diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h index d93e3fd73831..df80cbbd9d1b 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.h +++ b/drivers/net/wireless/ath/wcn36xx/smd.h @@ -46,8 +46,8 @@ struct wcn36xx_fw_msg_status_rsp { struct wcn36xx_hal_ind_msg { struct list_head list; - u8 *msg; size_t msg_len; + u8 msg[]; }; struct wcn36xx; @@ -63,7 +63,7 @@ int wcn36xx_smd_start_scan(struct wcn36xx *wcn); int wcn36xx_smd_end_scan(struct wcn36xx *wcn); int wcn36xx_smd_finish_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode); -int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn); +int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, u8 *channels, size_t channel_count); int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif); int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr); int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index); diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 7433d67a5929..22242d18e1fe 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -193,7 +193,7 @@ struct wcn36xx { u8 fw_minor; u8 fw_major; u32 fw_feat_caps[WCN36XX_HAL_CAPS_SIZE]; - u32 chip_version; + bool is_pronto; /* extra byte for the NULL termination */ u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1]; @@ -202,7 +202,8 @@ struct wcn36xx { /* IRQs */ int tx_irq; int rx_irq; - void __iomem *mmio; + void __iomem *ccu_base; + void __iomem *dxe_base; struct wcn36xx_platform_ctrl_ops *ctrl_ops; /* @@ -215,7 +216,7 @@ struct wcn36xx { struct completion hal_rsp_compl; struct workqueue_struct *hal_ind_wq; struct work_struct hal_ind_work; - struct mutex hal_ind_mutex; + spinlock_t hal_ind_lock; struct list_head hal_ind_queue; /* DXE channels */ @@ -241,9 +242,6 @@ struct wcn36xx { }; -#define WCN36XX_CHIP_3660 0 -#define WCN36XX_CHIP_3680 1 - static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn, u8 major, u8 minor, diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 5769811291bf..f0e1175fb76a 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -378,6 +378,10 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, /* social scan on P2P_DEVICE is handled as p2p search */ if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE && wil_p2p_is_social_scan(request)) { + if (!wil->p2p.p2p_dev_started) { + wil_err(wil, "P2P search requested on stopped P2P device\n"); + return -EIO; + } wil->scan_request = request; wil->radio_wdev = wdev; rc = wil_p2p_search(wil, request); @@ -1351,6 +1355,7 @@ static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy, struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "%s: entered\n", __func__); + wil->p2p.p2p_dev_started = 1; return 0; } @@ -1358,8 +1363,23 @@ static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + u8 started; wil_dbg_misc(wil, "%s: entered\n", __func__); + mutex_lock(&wil->mutex); + started = wil_p2p_stop_discovery(wil); + if (started && wil->scan_request) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + + cfg80211_scan_done(wil->scan_request, &info); + wil->scan_request = NULL; + wil->radio_wdev = wil->wdev; + } + mutex_unlock(&wil->mutex); + + wil->p2p.p2p_dev_started = 0; } static struct cfg80211_ops wil_cfg80211_ops = { diff --git a/drivers/net/wireless/ath/wil6210/debug.c b/drivers/net/wireless/ath/wil6210/debug.c index c312a667c12a..217a4591bde4 100644 --- a/drivers/net/wireless/ath/wil6210/debug.c +++ b/drivers/net/wireless/ath/wil6210/debug.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Qualcomm Atheros, Inc. + * Copyright (c) 2013,2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,34 +19,31 @@ void __wil_err(struct wil6210_priv *wil, const char *fmt, ...) { - struct net_device *ndev = wil_to_ndev(wil); - struct va_format vaf = { - .fmt = fmt, - }; + struct va_format vaf; va_list args; va_start(args, fmt); + vaf.fmt = fmt; vaf.va = &args; - netdev_err(ndev, "%pV", &vaf); + netdev_err(wil_to_ndev(wil), "%pV", &vaf); trace_wil6210_log_err(&vaf); va_end(args); } void __wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...) { - if (net_ratelimit()) { - struct net_device *ndev = wil_to_ndev(wil); - struct va_format vaf = { - .fmt = fmt, - }; - va_list args; + struct va_format vaf; + va_list args; - va_start(args, fmt); - vaf.va = &args; - netdev_err(ndev, "%pV", &vaf); - trace_wil6210_log_err(&vaf); - va_end(args); - } + if (!net_ratelimit()) + return; + + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + netdev_err(wil_to_ndev(wil), "%pV", &vaf); + trace_wil6210_log_err(&vaf); + va_end(args); } void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...) @@ -67,27 +64,24 @@ void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...) void __wil_info(struct wil6210_priv *wil, const char *fmt, ...) { - struct net_device *ndev = wil_to_ndev(wil); - struct va_format vaf = { - .fmt = fmt, - }; + struct va_format vaf; va_list args; va_start(args, fmt); + vaf.fmt = fmt; vaf.va = &args; - netdev_info(ndev, "%pV", &vaf); + netdev_info(wil_to_ndev(wil), "%pV", &vaf); trace_wil6210_log_info(&vaf); va_end(args); } void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...) { - struct va_format vaf = { - .fmt = fmt, - }; + struct va_format vaf; va_list args; va_start(args, fmt); + vaf.fmt = fmt; vaf.va = &args; trace_wil6210_log_dbg(&vaf); va_end(args); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 8e31d755bbee..4bc92e54984a 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -850,10 +850,14 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) mutex_unlock(&wil->wmi_mutex); if (wil->scan_request) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + wil_dbg_misc(wil, "Abort scan_request 0x%p\n", wil->scan_request); del_timer_sync(&wil->scan_timer); - cfg80211_scan_done(wil->scan_request, true); + cfg80211_scan_done(wil->scan_request, &info); wil->scan_request = NULL; } @@ -1049,10 +1053,14 @@ int __wil_down(struct wil6210_priv *wil) (void)wil_p2p_stop_discovery(wil); if (wil->scan_request) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + wil_dbg_misc(wil, "Abort scan_request 0x%p\n", wil->scan_request); del_timer_sync(&wil->scan_timer); - cfg80211_scan_done(wil->scan_request, true); + cfg80211_scan_done(wil->scan_request, &info); wil->scan_request = NULL; } diff --git a/drivers/net/wireless/ath/wil6210/p2p.c b/drivers/net/wireless/ath/wil6210/p2p.c index 1c9153894dca..e0f8aa0ebfac 100644 --- a/drivers/net/wireless/ath/wil6210/p2p.c +++ b/drivers/net/wireless/ath/wil6210/p2p.c @@ -114,8 +114,10 @@ int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration, u8 channel = P2P_DMG_SOCIAL_CHANNEL; int rc; - if (chan) - channel = chan->hw_value; + if (!chan) + return -EINVAL; + + channel = chan->hw_value; wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration); @@ -250,8 +252,12 @@ void wil_p2p_search_expired(struct work_struct *work) mutex_unlock(&wil->mutex); if (started) { + struct cfg80211_scan_info info = { + .aborted = false, + }; + mutex_lock(&wil->p2p_wdev_mutex); - cfg80211_scan_done(wil->scan_request, 0); + cfg80211_scan_done(wil->scan_request, &info); wil->scan_request = NULL; wil->radio_wdev = wil->wdev; mutex_unlock(&wil->p2p_wdev_mutex); diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index aeb72c438e44..7b5c4222bc33 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,13 +18,20 @@ #include <linux/pci.h> #include <linux/moduleparam.h> #include <linux/interrupt.h> - +#include <linux/suspend.h> #include "wil6210.h" static bool use_msi = true; module_param(use_msi, bool, S_IRUGO); MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true"); +#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP +static int wil6210_pm_notify(struct notifier_block *notify_block, + unsigned long mode, void *unused); +#endif /* CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM */ + static void wil_set_capabilities(struct wil6210_priv *wil) { @@ -238,6 +245,18 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto bus_disable; } +#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP + wil->pm_notify.notifier_call = wil6210_pm_notify; + rc = register_pm_notifier(&wil->pm_notify); + if (rc) + /* Do not fail the driver initialization, as suspend can + * be prevented in a later phase if needed + */ + wil_err(wil, "register_pm_notifier failed: %d\n", rc); +#endif /* CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM */ + wil6210_debugfs_init(wil); @@ -267,6 +286,12 @@ static void wil_pcie_remove(struct pci_dev *pdev) wil_dbg_misc(wil, "%s()\n", __func__); +#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP + unregister_pm_notifier(&wil->pm_notify); +#endif /* CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM */ + wil6210_debugfs_remove(wil); wil_if_remove(wil); wil_if_pcie_disable(wil); @@ -335,6 +360,45 @@ static int wil6210_resume(struct device *dev, bool is_runtime) return rc; } +static int wil6210_pm_notify(struct notifier_block *notify_block, + unsigned long mode, void *unused) +{ + struct wil6210_priv *wil = container_of( + notify_block, struct wil6210_priv, pm_notify); + int rc = 0; + enum wil_platform_event evt; + + wil_dbg_pm(wil, "%s: mode (%ld)\n", __func__, mode); + + switch (mode) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + case PM_RESTORE_PREPARE: + rc = wil_can_suspend(wil, false); + if (rc) + break; + evt = WIL_PLATFORM_EVT_PRE_SUSPEND; + if (wil->platform_ops.notify) + rc = wil->platform_ops.notify(wil->platform_handle, + evt); + break; + case PM_POST_SUSPEND: + case PM_POST_HIBERNATION: + case PM_POST_RESTORE: + evt = WIL_PLATFORM_EVT_POST_SUSPEND; + if (wil->platform_ops.notify) + rc = wil->platform_ops.notify(wil->platform_handle, + evt); + break; + default: + wil_dbg_pm(wil, "unhandled notify mode %ld\n", mode); + break; + } + + wil_dbg_pm(wil, "notification mode %ld: rc (%d)\n", mode, rc); + return rc; +} + static int wil6210_pm_suspend(struct device *dev) { return wil6210_suspend(dev, false); diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 0b7ecbcac19c..11ee24d509e5 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014,2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,10 +24,32 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) wil_dbg_pm(wil, "%s(%s)\n", __func__, is_runtime ? "runtime" : "system"); + if (!netif_running(wil_to_ndev(wil))) { + /* can always sleep when down */ + wil_dbg_pm(wil, "Interface is down\n"); + goto out; + } + if (test_bit(wil_status_resetting, wil->status)) { + wil_dbg_pm(wil, "Delay suspend when resetting\n"); + rc = -EBUSY; + goto out; + } + if (wil->recovery_state != fw_recovery_idle) { + wil_dbg_pm(wil, "Delay suspend during recovery\n"); + rc = -EBUSY; + goto out; + } + + /* interface is running */ switch (wdev->iftype) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: + if (test_bit(wil_status_fwconnecting, wil->status)) { + wil_dbg_pm(wil, "Delay suspend when connecting\n"); + rc = -EBUSY; + goto out; + } break; /* AP-like interface - can't suspend */ default: @@ -36,6 +58,7 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) break; } +out: wil_dbg_pm(wil, "%s(%s) => %s (%d)\n", __func__, is_runtime ? "runtime" : "system", rc ? "No" : "Yes", rc); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index a4e43796addb..f2f6a404d3d1 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -184,6 +184,13 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, &vring->va[vring->swtail].tx; ctx = &vring->ctx[vring->swtail]; + if (!ctx) { + wil_dbg_txrx(wil, + "ctx(%d) was already completed\n", + vring->swtail); + vring->swtail = wil_vring_next_tail(vring); + continue; + } *d = *_d; wil_txdesc_unmap(dev, d, ctx); if (ctx->skb) @@ -544,6 +551,12 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) break; } } + + /* make sure all writes to descriptors (shared memory) are done before + * committing them to HW + */ + wmb(); + wil_w(wil, v->hwtail, v->swtail); return rc; @@ -969,6 +982,13 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) txdata->dot1x_open = false; txdata->enabled = 0; /* no Tx can be in progress or start anew */ spin_unlock_bh(&txdata->lock); + /* napi_synchronize waits for completion of the current NAPI but will + * not prevent the next NAPI run. + * Add a memory barrier to guarantee that txdata->enabled is zeroed + * before napi_synchronize so that the next scheduled NAPI will not + * handle this vring + */ + wmb(); /* make sure NAPI won't touch this vring */ if (test_bit(wil_status_napi_en, wil->status)) napi_synchronize(&wil->napi_tx); @@ -1551,6 +1571,13 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring, vring_index, used, used + descs_used); } + /* Make sure to advance the head only after descriptor update is done. + * This will prevent a race condition where the completion thread + * will see the DU bit set from previous run and will handle the + * skb before it was completed. + */ + wmb(); + /* advance swhead */ wil_vring_advance_head(vring, descs_used); wil_dbg_txrx(wil, "TSO: Tx swhead %d -> %d\n", swhead, vring->swhead); @@ -1567,7 +1594,7 @@ mem_error: while (descs_used > 0) { struct wil_ctx *ctx; - i = (swhead + descs_used) % vring->size; + i = (swhead + descs_used - 1) % vring->size; d = (struct vring_tx_desc *)&vring->va[i].tx; _desc = &vring->va[i].tx; *d = *_desc; @@ -1691,6 +1718,13 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, vring_index, used, used + nr_frags + 1); } + /* Make sure to advance the head only after descriptor update is done. + * This will prevent a race condition where the completion thread + * will see the DU bit set from previous run and will handle the + * skb before it was completed. + */ + wmb(); + /* advance swhead */ wil_vring_advance_head(vring, nr_frags + 1); wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead, @@ -1914,6 +1948,12 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) wil_consume_skb(skb, d->dma.error == 0); } memset(ctx, 0, sizeof(*ctx)); + /* Make sure the ctx is zeroed before updating the tail + * to prevent a case where wil_tx_vring will see + * this descriptor as used and handle it before ctx zero + * is completed. + */ + wmb(); /* There is no need to touch HW descriptor: * - ststus bit TX_DMA_STATUS_DU is set by design, * so hardware will not try to process this desc., diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index aa09cbcce47c..ecab4af90602 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -458,6 +458,7 @@ struct wil_tid_crypto_rx { struct wil_p2p_info { struct ieee80211_channel listen_chan; u8 discovery_started; + u8 p2p_dev_started; u64 cookie; struct timer_list discovery_timer; /* listen/search duration */ struct work_struct discovery_expired_work; /* listen/search expire */ @@ -662,6 +663,11 @@ struct wil6210_priv { /* High Access Latency Policy voting */ struct wil_halp halp; +#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP + struct notifier_block pm_notify; +#endif /* CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM */ }; #define wil_to_wiphy(i) (i->wdev->wiphy) diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h index 33d4a34b3b1c..f8c41172a3f4 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.h +++ b/drivers/net/wireless/ath/wil6210/wil_platform.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -23,6 +23,8 @@ enum wil_platform_event { WIL_PLATFORM_EVT_FW_CRASH = 0, WIL_PLATFORM_EVT_PRE_RESET = 1, WIL_PLATFORM_EVT_FW_RDY = 2, + WIL_PLATFORM_EVT_PRE_SUSPEND = 3, + WIL_PLATFORM_EVT_POST_SUSPEND = 4, }; /** diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index b80c5d850e1e..4d92541913c0 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -426,15 +426,17 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, { if (wil->scan_request) { struct wmi_scan_complete_event *data = d; - bool aborted = (data->status != WMI_SCAN_SUCCESS); + struct cfg80211_scan_info info = { + .aborted = (data->status != WMI_SCAN_SUCCESS), + }; wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n", - wil->scan_request, aborted); + wil->scan_request, info.aborted); del_timer_sync(&wil->scan_timer); mutex_lock(&wil->p2p_wdev_mutex); - cfg80211_scan_done(wil->scan_request, aborted); + cfg80211_scan_done(wil->scan_request, &info); wil->radio_wdev = wil->wdev; mutex_unlock(&wil->p2p_wdev_mutex); wil->scan_request = NULL; diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c index 7c108047fb46..0e180677c7fc 100644 --- a/drivers/net/wireless/atmel/at76c50x-usb.c +++ b/drivers/net/wireless/atmel/at76c50x-usb.c @@ -1922,6 +1922,9 @@ static void at76_dwork_hw_scan(struct work_struct *work) { struct at76_priv *priv = container_of(work, struct at76_priv, dwork_hw_scan.work); + struct cfg80211_scan_info info = { + .aborted = false, + }; int ret; if (priv->device_unplugged) @@ -1948,7 +1951,7 @@ static void at76_dwork_hw_scan(struct work_struct *work) mutex_unlock(&priv->mtx); - ieee80211_scan_completed(priv->hw, false); + ieee80211_scan_completed(priv->hw, &info); ieee80211_wake_queues(priv->hw); } diff --git a/drivers/net/wireless/broadcom/b43/Makefile b/drivers/net/wireless/broadcom/b43/Makefile index ddc4df46656f..27fab958e3d5 100644 --- a/drivers/net/wireless/broadcom/b43/Makefile +++ b/drivers/net/wireless/broadcom/b43/Makefile @@ -1,6 +1,6 @@ b43-y += main.o b43-y += bus.o -b43-$(CONFIG_B43_PHY_G) += phy_a.o phy_g.o tables.o lo.o wa.o +b43-$(CONFIG_B43_PHY_G) += phy_g.o tables.o lo.o wa.o b43-$(CONFIG_B43_PHY_N) += tables_nphy.o b43-$(CONFIG_B43_PHY_N) += radio_2055.o b43-$(CONFIG_B43_PHY_N) += radio_2056.o diff --git a/drivers/net/wireless/broadcom/b43/leds.c b/drivers/net/wireless/broadcom/b43/leds.c index d79ab2a227e1..cb987c2ecc6b 100644 --- a/drivers/net/wireless/broadcom/b43/leds.c +++ b/drivers/net/wireless/broadcom/b43/leds.c @@ -222,7 +222,7 @@ static void b43_led_get_sprominfo(struct b43_wldev *dev, sprom[2] = dev->dev->bus_sprom->gpio2; sprom[3] = dev->dev->bus_sprom->gpio3; - if (sprom[led_index] == 0xFF) { + if ((sprom[0] & sprom[1] & sprom[2] & sprom[3]) == 0xff) { /* There is no LED information in the SPROM * for this LED. Hardcode it here. */ *activelow = false; @@ -250,7 +250,11 @@ static void b43_led_get_sprominfo(struct b43_wldev *dev, return; } } else { - *behaviour = sprom[led_index] & B43_LED_BEHAVIOUR; + /* keep LED disabled if no mapping is defined */ + if (sprom[led_index] == 0xff) + *behaviour = B43_LED_OFF; + else + *behaviour = sprom[led_index] & B43_LED_BEHAVIOUR; *activelow = !!(sprom[led_index] & B43_LED_ACTIVELOW); } } diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 4ee5c5853f9f..6e5d9095b195 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -3180,7 +3180,6 @@ static void b43_rate_memory_write(struct b43_wldev *dev, u16 rate, int is_ofdm) static void b43_rate_memory_init(struct b43_wldev *dev) { switch (dev->phy.type) { - case B43_PHYTYPE_A: case B43_PHYTYPE_G: case B43_PHYTYPE_N: case B43_PHYTYPE_LP: @@ -3194,8 +3193,6 @@ static void b43_rate_memory_init(struct b43_wldev *dev) b43_rate_memory_write(dev, B43_OFDM_RATE_36MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_48MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_54MB, 1); - if (dev->phy.type == B43_PHYTYPE_A) - break; /* fallthrough */ case B43_PHYTYPE_B: b43_rate_memory_write(dev, B43_CCK_RATE_1MB, 0); @@ -4604,14 +4601,6 @@ static int b43_phy_versioning(struct b43_wldev *dev) if (radio_manuf != 0x17F /* Broadcom */) unsupported = 1; switch (phy_type) { - case B43_PHYTYPE_A: - if (radio_id != 0x2060) - unsupported = 1; - if (radio_rev != 1) - unsupported = 1; - if (radio_manuf != 0x17F) - unsupported = 1; - break; case B43_PHYTYPE_B: if ((radio_id & 0xFFF0) != 0x2050) unsupported = 1; @@ -4766,10 +4755,7 @@ static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle) u16 pu_delay; /* The time value is in microseconds. */ - if (dev->phy.type == B43_PHYTYPE_A) - pu_delay = 3700; - else - pu_delay = 1050; + pu_delay = 1050; if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC) || idle) pu_delay = 500; if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8)) @@ -4784,14 +4770,10 @@ static void b43_set_pretbtt(struct b43_wldev *dev) u16 pretbtt; /* The time value is in microseconds. */ - if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) { + if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) pretbtt = 2; - } else { - if (dev->phy.type == B43_PHYTYPE_A) - pretbtt = 120; - else - pretbtt = 250; - } + else + pretbtt = 250; b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRETBTT, pretbtt); b43_write16(dev, B43_MMIO_TSF_CFP_PRETBTT, pretbtt); } @@ -5380,10 +5362,6 @@ static void b43_supported_bands(struct b43_wldev *dev, bool *have_2ghz_phy, /* As a fallback, try to guess using PHY type */ switch (dev->phy.type) { - case B43_PHYTYPE_A: - *have_2ghz_phy = false; - *have_5ghz_phy = true; - return; case B43_PHYTYPE_G: case B43_PHYTYPE_N: case B43_PHYTYPE_LP: @@ -5455,7 +5433,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) /* We don't support 5 GHz on some PHYs yet */ if (have_5ghz_phy) { switch (dev->phy.type) { - case B43_PHYTYPE_A: case B43_PHYTYPE_G: case B43_PHYTYPE_LP: case B43_PHYTYPE_HT: diff --git a/drivers/net/wireless/broadcom/b43/phy_a.c b/drivers/net/wireless/broadcom/b43/phy_a.c deleted file mode 100644 index 99c036f5ecb7..000000000000 --- a/drivers/net/wireless/broadcom/b43/phy_a.c +++ /dev/null @@ -1,595 +0,0 @@ -/* - - Broadcom B43 wireless driver - IEEE 802.11a PHY driver - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> - Copyright (c) 2005-2008 Michael Buesch <m@bues.ch> - Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org> - Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include <linux/slab.h> - -#include "b43.h" -#include "phy_a.h" -#include "phy_common.h" -#include "wa.h" -#include "tables.h" -#include "main.h" - - -/* Get the freq, as it has to be written to the device. */ -static inline u16 channel2freq_a(u8 channel) -{ - B43_WARN_ON(channel > 200); - - return (5000 + 5 * channel); -} - -static inline u16 freq_r3A_value(u16 frequency) -{ - u16 value; - - if (frequency < 5091) - value = 0x0040; - else if (frequency < 5321) - value = 0x0000; - else if (frequency < 5806) - value = 0x0080; - else - value = 0x0040; - - return value; -} - -#if 0 -/* This function converts a TSSI value to dBm in Q5.2 */ -static s8 b43_aphy_estimate_power_out(struct b43_wldev *dev, s8 tssi) -{ - struct b43_phy *phy = &dev->phy; - struct b43_phy_a *aphy = phy->a; - s8 dbm = 0; - s32 tmp; - - tmp = (aphy->tgt_idle_tssi - aphy->cur_idle_tssi + tssi); - tmp += 0x80; - tmp = clamp_val(tmp, 0x00, 0xFF); - dbm = aphy->tssi2dbm[tmp]; - //TODO: There's a FIXME on the specs - - return dbm; -} -#endif - -static void b43_radio_set_tx_iq(struct b43_wldev *dev) -{ - static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; - static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; - u16 tmp = b43_radio_read16(dev, 0x001E); - int i, j; - - for (i = 0; i < 5; i++) { - for (j = 0; j < 5; j++) { - if (tmp == (data_high[i] << 4 | data_low[j])) { - b43_phy_write(dev, 0x0069, - (i - j) << 8 | 0x00C0); - return; - } - } - } -} - -static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel) -{ - u16 freq, r8, tmp; - - freq = channel2freq_a(channel); - - r8 = b43_radio_read16(dev, 0x0008); - b43_write16(dev, 0x03F0, freq); - b43_radio_write16(dev, 0x0008, r8); - - //TODO: write max channel TX power? to Radio 0x2D - tmp = b43_radio_read16(dev, 0x002E); - tmp &= 0x0080; - //TODO: OR tmp with the Power out estimation for this channel? - b43_radio_write16(dev, 0x002E, tmp); - - if (freq >= 4920 && freq <= 5500) { - /* - * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; - * = (freq * 0.025862069 - */ - r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ - } - b43_radio_write16(dev, 0x0007, (r8 << 4) | r8); - b43_radio_write16(dev, 0x0020, (r8 << 4) | r8); - b43_radio_write16(dev, 0x0021, (r8 << 4) | r8); - b43_radio_maskset(dev, 0x0022, 0x000F, (r8 << 4)); - b43_radio_write16(dev, 0x002A, (r8 << 4)); - b43_radio_write16(dev, 0x002B, (r8 << 4)); - b43_radio_maskset(dev, 0x0008, 0x00F0, (r8 << 4)); - b43_radio_maskset(dev, 0x0029, 0xFF0F, 0x00B0); - b43_radio_write16(dev, 0x0035, 0x00AA); - b43_radio_write16(dev, 0x0036, 0x0085); - b43_radio_maskset(dev, 0x003A, 0xFF20, freq_r3A_value(freq)); - b43_radio_mask(dev, 0x003D, 0x00FF); - b43_radio_maskset(dev, 0x0081, 0xFF7F, 0x0080); - b43_radio_mask(dev, 0x0035, 0xFFEF); - b43_radio_maskset(dev, 0x0035, 0xFFEF, 0x0010); - b43_radio_set_tx_iq(dev); - //TODO: TSSI2dbm workaround -//FIXME b43_phy_xmitpower(dev); -} - -static void b43_radio_init2060(struct b43_wldev *dev) -{ - b43_radio_write16(dev, 0x0004, 0x00C0); - b43_radio_write16(dev, 0x0005, 0x0008); - b43_radio_write16(dev, 0x0009, 0x0040); - b43_radio_write16(dev, 0x0005, 0x00AA); - b43_radio_write16(dev, 0x0032, 0x008F); - b43_radio_write16(dev, 0x0006, 0x008F); - b43_radio_write16(dev, 0x0034, 0x008F); - b43_radio_write16(dev, 0x002C, 0x0007); - b43_radio_write16(dev, 0x0082, 0x0080); - b43_radio_write16(dev, 0x0080, 0x0000); - b43_radio_write16(dev, 0x003F, 0x00DA); - b43_radio_mask(dev, 0x0005, ~0x0008); - b43_radio_mask(dev, 0x0081, ~0x0010); - b43_radio_mask(dev, 0x0081, ~0x0020); - b43_radio_mask(dev, 0x0081, ~0x0020); - msleep(1); /* delay 400usec */ - - b43_radio_maskset(dev, 0x0081, ~0x0020, 0x0010); - msleep(1); /* delay 400usec */ - - b43_radio_maskset(dev, 0x0005, ~0x0008, 0x0008); - b43_radio_mask(dev, 0x0085, ~0x0010); - b43_radio_mask(dev, 0x0005, ~0x0008); - b43_radio_mask(dev, 0x0081, ~0x0040); - b43_radio_maskset(dev, 0x0081, ~0x0040, 0x0040); - b43_radio_write16(dev, 0x0005, - (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008); - b43_phy_write(dev, 0x0063, 0xDDC6); - b43_phy_write(dev, 0x0069, 0x07BE); - b43_phy_write(dev, 0x006A, 0x0000); - - aphy_channel_switch(dev, dev->phy.ops->get_default_chan(dev)); - - msleep(1); -} - -static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable) -{ - int i; - - if (dev->phy.rev < 3) { - if (enable) - for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { - b43_ofdmtab_write16(dev, - B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8); - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, 0xFFF8); - } - else - for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { - b43_ofdmtab_write16(dev, - B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]); - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]); - } - } else { - if (enable) - for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, 0x0820); - else - for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++) - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]); - } -} - -static void b43_phy_ww(struct b43_wldev *dev) -{ - u16 b, curr_s, best_s = 0xFFFF; - int i; - - b43_phy_mask(dev, B43_PHY_CRS0, ~B43_PHY_CRS0_EN); - b43_phy_set(dev, B43_PHY_OFDM(0x1B), 0x1000); - b43_phy_maskset(dev, B43_PHY_OFDM(0x82), 0xF0FF, 0x0300); - b43_radio_set(dev, 0x0009, 0x0080); - b43_radio_maskset(dev, 0x0012, 0xFFFC, 0x0002); - b43_wa_initgains(dev); - b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5); - b = b43_phy_read(dev, B43_PHY_PWRDOWN); - b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005); - b43_radio_set(dev, 0x0004, 0x0004); - for (i = 0x10; i <= 0x20; i++) { - b43_radio_write16(dev, 0x0013, i); - curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF; - if (!curr_s) { - best_s = 0x0000; - break; - } else if (curr_s >= 0x0080) - curr_s = 0x0100 - curr_s; - if (curr_s < best_s) - best_s = curr_s; - } - b43_phy_write(dev, B43_PHY_PWRDOWN, b); - b43_radio_mask(dev, 0x0004, 0xFFFB); - b43_radio_write16(dev, 0x0013, best_s); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC); - b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80); - b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00); - b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0); - b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0); - b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF); - b43_phy_maskset(dev, B43_PHY_OFDM(0xBB), 0xF000, 0x0053); - b43_phy_maskset(dev, B43_PHY_OFDM61, 0xFE1F, 0x0120); - b43_phy_maskset(dev, B43_PHY_OFDM(0x13), 0x0FFF, 0x3000); - b43_phy_maskset(dev, B43_PHY_OFDM(0x14), 0x0FFF, 0x3000); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017); - for (i = 0; i < 6; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013); - b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030); - b43_phy_set(dev, B43_PHY_CRS0, B43_PHY_CRS0_EN); -} - -static void hardware_pctl_init_aphy(struct b43_wldev *dev) -{ - //TODO -} - -void b43_phy_inita(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - /* This lowlevel A-PHY init is also called from G-PHY init. - * So we must not access phy->a, if called from G-PHY code. - */ - B43_WARN_ON((phy->type != B43_PHYTYPE_A) && - (phy->type != B43_PHYTYPE_G)); - - might_sleep(); - - if (phy->rev >= 6) { - if (phy->type == B43_PHYTYPE_A) - b43_phy_mask(dev, B43_PHY_OFDM(0x1B), ~0x1000); - if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) - b43_phy_set(dev, B43_PHY_ENCORE, 0x0010); - else - b43_phy_mask(dev, B43_PHY_ENCORE, ~0x1010); - } - - b43_wa_all(dev); - - if (phy->type == B43_PHYTYPE_A) { - if (phy->gmode && (phy->rev < 3)) - b43_phy_set(dev, 0x0034, 0x0001); - b43_phy_rssiagc(dev, 0); - - b43_phy_set(dev, B43_PHY_CRS0, B43_PHY_CRS0_EN); - - b43_radio_init2060(dev); - - if ((dev->dev->board_vendor == SSB_BOARDVENDOR_BCM) && - ((dev->dev->board_type == SSB_BOARD_BU4306) || - (dev->dev->board_type == SSB_BOARD_BU4309))) { - ; //TODO: A PHY LO - } - - if (phy->rev >= 3) - b43_phy_ww(dev); - - hardware_pctl_init_aphy(dev); - - //TODO: radar detection - } - - if ((phy->type == B43_PHYTYPE_G) && - (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL)) { - b43_phy_maskset(dev, B43_PHY_OFDM(0x6E), 0xE000, 0x3CF); - } -} - -/* Initialise the TSSI->dBm lookup table */ -static int b43_aphy_init_tssi2dbm_table(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - struct b43_phy_a *aphy = phy->a; - s16 pab0, pab1, pab2; - - pab0 = (s16) (dev->dev->bus_sprom->pa1b0); - pab1 = (s16) (dev->dev->bus_sprom->pa1b1); - pab2 = (s16) (dev->dev->bus_sprom->pa1b2); - - if (pab0 != 0 && pab1 != 0 && pab2 != 0 && - pab0 != -1 && pab1 != -1 && pab2 != -1) { - /* The pabX values are set in SPROM. Use them. */ - if ((s8) dev->dev->bus_sprom->itssi_a != 0 && - (s8) dev->dev->bus_sprom->itssi_a != -1) - aphy->tgt_idle_tssi = - (s8) (dev->dev->bus_sprom->itssi_a); - else - aphy->tgt_idle_tssi = 62; - aphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0, - pab1, pab2); - if (!aphy->tssi2dbm) - return -ENOMEM; - } else { - /* pabX values not set in SPROM, - * but APHY needs a generated table. */ - aphy->tssi2dbm = NULL; - b43err(dev->wl, "Could not generate tssi2dBm " - "table (wrong SPROM info)!\n"); - return -ENODEV; - } - - return 0; -} - -static int b43_aphy_op_allocate(struct b43_wldev *dev) -{ - struct b43_phy_a *aphy; - int err; - - aphy = kzalloc(sizeof(*aphy), GFP_KERNEL); - if (!aphy) - return -ENOMEM; - dev->phy.a = aphy; - - err = b43_aphy_init_tssi2dbm_table(dev); - if (err) - goto err_free_aphy; - - return 0; - -err_free_aphy: - kfree(aphy); - dev->phy.a = NULL; - - return err; -} - -static void b43_aphy_op_prepare_structs(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - struct b43_phy_a *aphy = phy->a; - const void *tssi2dbm; - int tgt_idle_tssi; - - /* tssi2dbm table is constant, so it is initialized at alloc time. - * Save a copy of the pointer. */ - tssi2dbm = aphy->tssi2dbm; - tgt_idle_tssi = aphy->tgt_idle_tssi; - - /* Zero out the whole PHY structure. */ - memset(aphy, 0, sizeof(*aphy)); - - aphy->tssi2dbm = tssi2dbm; - aphy->tgt_idle_tssi = tgt_idle_tssi; - - //TODO init struct b43_phy_a - -} - -static void b43_aphy_op_free(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - struct b43_phy_a *aphy = phy->a; - - kfree(aphy->tssi2dbm); - aphy->tssi2dbm = NULL; - - kfree(aphy); - dev->phy.a = NULL; -} - -static int b43_aphy_op_init(struct b43_wldev *dev) -{ - b43_phy_inita(dev); - - return 0; -} - -static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset) -{ - /* OFDM registers are base-registers for the A-PHY. */ - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { - offset &= ~B43_PHYROUTE; - offset |= B43_PHYROUTE_BASE; - } - -#if B43_DEBUG - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { - /* Ext-G registers are only available on G-PHYs */ - b43err(dev->wl, "Invalid EXT-G PHY access at " - "0x%04X on A-PHY\n", offset); - dump_stack(); - } - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) { - /* N-BMODE registers are only available on N-PHYs */ - b43err(dev->wl, "Invalid N-BMODE PHY access at " - "0x%04X on A-PHY\n", offset); - dump_stack(); - } -#endif /* B43_DEBUG */ - - return offset; -} - -static u16 b43_aphy_op_read(struct b43_wldev *dev, u16 reg) -{ - reg = adjust_phyreg(dev, reg); - b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); - return b43_read16(dev, B43_MMIO_PHY_DATA); -} - -static void b43_aphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) -{ - reg = adjust_phyreg(dev, reg); - b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); - b43_write16(dev, B43_MMIO_PHY_DATA, value); -} - -static u16 b43_aphy_op_radio_read(struct b43_wldev *dev, u16 reg) -{ - /* Register 1 is a 32-bit register. */ - B43_WARN_ON(reg == 1); - /* A-PHY needs 0x40 for read access */ - reg |= 0x40; - - b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); - return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); -} - -static void b43_aphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) -{ - /* Register 1 is a 32-bit register. */ - B43_WARN_ON(reg == 1); - - b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); - b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); -} - -static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev) -{ - return (dev->phy.rev >= 5); -} - -static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, - bool blocked) -{ - struct b43_phy *phy = &dev->phy; - - if (!blocked) { - if (phy->radio_on) - return; - b43_radio_write16(dev, 0x0004, 0x00C0); - b43_radio_write16(dev, 0x0005, 0x0008); - b43_phy_mask(dev, 0x0010, 0xFFF7); - b43_phy_mask(dev, 0x0011, 0xFFF7); - b43_radio_init2060(dev); - } else { - b43_radio_write16(dev, 0x0004, 0x00FF); - b43_radio_write16(dev, 0x0005, 0x00FB); - b43_phy_set(dev, 0x0010, 0x0008); - b43_phy_set(dev, 0x0011, 0x0008); - } -} - -static int b43_aphy_op_switch_channel(struct b43_wldev *dev, - unsigned int new_channel) -{ - if (new_channel > 200) - return -EINVAL; - aphy_channel_switch(dev, new_channel); - - return 0; -} - -static unsigned int b43_aphy_op_get_default_chan(struct b43_wldev *dev) -{ - return 36; /* Default to channel 36 */ -} - -static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) -{//TODO - struct b43_phy *phy = &dev->phy; - u16 tmp; - int autodiv = 0; - - if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) - autodiv = 1; - - b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP); - - b43_phy_maskset(dev, B43_PHY_BBANDCFG, ~B43_PHY_BBANDCFG_RXANT, - (autodiv ? B43_ANTENNA_AUTO1 : antenna) << - B43_PHY_BBANDCFG_RXANT_SHIFT); - - if (autodiv) { - tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); - if (antenna == B43_ANTENNA_AUTO1) - tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; - else - tmp |= B43_PHY_ANTDWELL_AUTODIV1; - b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); - } - if (phy->rev < 3) - b43_phy_maskset(dev, B43_PHY_ANTDWELL, 0xFF00, 0x24); - else { - b43_phy_set(dev, B43_PHY_OFDM61, 0x10); - if (phy->rev == 3) { - b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, 0x1D); - b43_phy_write(dev, B43_PHY_ADIVRELATED, 8); - } else { - b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, 0x3A); - b43_phy_maskset(dev, B43_PHY_ADIVRELATED, 0xFF00, 8); - } - } - - b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP); -} - -static void b43_aphy_op_adjust_txpower(struct b43_wldev *dev) -{//TODO -} - -static enum b43_txpwr_result b43_aphy_op_recalc_txpower(struct b43_wldev *dev, - bool ignore_tssi) -{//TODO - return B43_TXPWR_RES_DONE; -} - -static void b43_aphy_op_pwork_15sec(struct b43_wldev *dev) -{//TODO -} - -static void b43_aphy_op_pwork_60sec(struct b43_wldev *dev) -{//TODO -} - -static const struct b43_phy_operations b43_phyops_a = { - .allocate = b43_aphy_op_allocate, - .free = b43_aphy_op_free, - .prepare_structs = b43_aphy_op_prepare_structs, - .init = b43_aphy_op_init, - .phy_read = b43_aphy_op_read, - .phy_write = b43_aphy_op_write, - .radio_read = b43_aphy_op_radio_read, - .radio_write = b43_aphy_op_radio_write, - .supports_hwpctl = b43_aphy_op_supports_hwpctl, - .software_rfkill = b43_aphy_op_software_rfkill, - .switch_analog = b43_phyop_switch_analog_generic, - .switch_channel = b43_aphy_op_switch_channel, - .get_default_chan = b43_aphy_op_get_default_chan, - .set_rx_antenna = b43_aphy_op_set_rx_antenna, - .recalc_txpower = b43_aphy_op_recalc_txpower, - .adjust_txpower = b43_aphy_op_adjust_txpower, - .pwork_15sec = b43_aphy_op_pwork_15sec, - .pwork_60sec = b43_aphy_op_pwork_60sec, -}; diff --git a/drivers/net/wireless/broadcom/b43/phy_a.h b/drivers/net/wireless/broadcom/b43/phy_a.h index f7d0d929a374..0a92d01c21f9 100644 --- a/drivers/net/wireless/broadcom/b43/phy_a.h +++ b/drivers/net/wireless/broadcom/b43/phy_a.h @@ -101,26 +101,4 @@ u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset); void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, u16 offset, u32 value); - -struct b43_phy_a { - /* Pointer to the table used to convert a - * TSSI value to dBm-Q5.2 */ - const s8 *tssi2dbm; - /* Target idle TSSI */ - int tgt_idle_tssi; - /* Current idle TSSI */ - int cur_idle_tssi;//FIXME value currently not set - - /* A-PHY TX Power control value. */ - u16 txpwr_offset; - - //TODO lots of missing stuff -}; - -/** - * b43_phy_inita - Lowlevel A-PHY init routine. - * This is _only_ used by the G-PHY code. - */ -void b43_phy_inita(struct b43_wldev *dev); - #endif /* LINUX_B43_PHY_A_H_ */ diff --git a/drivers/net/wireless/broadcom/b43/phy_common.h b/drivers/net/wireless/broadcom/b43/phy_common.h index 78d86526799e..ced054a9850c 100644 --- a/drivers/net/wireless/broadcom/b43/phy_common.h +++ b/drivers/net/wireless/broadcom/b43/phy_common.h @@ -190,7 +190,6 @@ struct b43_phy_operations { void (*pwork_60sec)(struct b43_wldev *dev); }; -struct b43_phy_a; struct b43_phy_g; struct b43_phy_n; struct b43_phy_lp; @@ -210,8 +209,6 @@ struct b43_phy { #else union { #endif - /* A-PHY specific information */ - struct b43_phy_a *a; /* G-PHY specific information */ struct b43_phy_g *g; /* N-PHY specific information */ diff --git a/drivers/net/wireless/broadcom/b43/phy_g.c b/drivers/net/wireless/broadcom/b43/phy_g.c index 462310e6e88f..822dcaa8ace6 100644 --- a/drivers/net/wireless/broadcom/b43/phy_g.c +++ b/drivers/net/wireless/broadcom/b43/phy_g.c @@ -31,6 +31,7 @@ #include "phy_common.h" #include "lo.h" #include "main.h" +#include "wa.h" #include <linux/bitrev.h> #include <linux/slab.h> @@ -1987,6 +1988,25 @@ static void b43_phy_init_pctl(struct b43_wldev *dev) b43_shm_clear_tssi(dev); } +static void b43_phy_inita(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + might_sleep(); + + if (phy->rev >= 6) { + if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) + b43_phy_set(dev, B43_PHY_ENCORE, 0x0010); + else + b43_phy_mask(dev, B43_PHY_ENCORE, ~0x1010); + } + + b43_wa_all(dev); + + if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL) + b43_phy_maskset(dev, B43_PHY_OFDM(0x6E), 0xE000, 0x3CF); +} + static void b43_phy_initg(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -2150,11 +2170,6 @@ static void default_radio_attenuation(struct b43_wldev *dev, } } - if (phy->type == B43_PHYTYPE_A) { - rf->att = 0x60; - return; - } - switch (phy->radio_ver) { case 0x2053: switch (phy->radio_rev) { diff --git a/drivers/net/wireless/broadcom/b43/wa.c b/drivers/net/wireless/broadcom/b43/wa.c index c218c08fb2f5..0e96c08d1e17 100644 --- a/drivers/net/wireless/broadcom/b43/wa.c +++ b/drivers/net/wireless/broadcom/b43/wa.c @@ -30,33 +30,6 @@ #include "phy_common.h" #include "wa.h" -static void b43_wa_papd(struct b43_wldev *dev) -{ - u16 backup; - - backup = b43_ofdmtab_read16(dev, B43_OFDMTAB_PWRDYN2, 0); - b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, 7); - b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 0, 0); - b43_dummy_transmission(dev, true, true); - b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, backup); -} - -static void b43_wa_auxclipthr(struct b43_wldev *dev) -{ - b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x3800); -} - -static void b43_wa_afcdac(struct b43_wldev *dev) -{ - b43_phy_write(dev, 0x0035, 0x03FF); - b43_phy_write(dev, 0x0036, 0x0400); -} - -static void b43_wa_txdc_offset(struct b43_wldev *dev) -{ - b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 0, 0x0051); -} - void b43_wa_initgains(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -81,41 +54,6 @@ void b43_wa_initgains(struct b43_wldev *dev) b43_phy_write(dev, 0x00BA, 0x3ED5); } -static void b43_wa_divider(struct b43_wldev *dev) -{ - b43_phy_mask(dev, 0x002B, ~0x0100); - b43_phy_write(dev, 0x008E, 0x58C1); -} - -static void b43_wa_gt(struct b43_wldev *dev) /* Gain table. */ -{ - if (dev->phy.rev <= 2) { - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 0, 15); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 1, 31); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 2, 42); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 3, 48); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 4, 58); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 0, 3); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 1, 3); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 2, 7); - } else { - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21); - b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25); - } -} - static void b43_wa_rssi_lt(struct b43_wldev *dev) /* RSSI lookup table */ { int i; @@ -133,15 +71,11 @@ static void b43_wa_rssi_lt(struct b43_wldev *dev) /* RSSI lookup table */ static void b43_wa_analog(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; u16 ofdmrev; ofdmrev = b43_phy_read(dev, B43_PHY_VERSION_OFDM) & B43_PHYVER_VERSION; if (ofdmrev > 2) { - if (phy->type == B43_PHYTYPE_A) - b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1808); - else - b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1000); + b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1000); } else { b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 3, 0x1044); b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 4, 0x7201); @@ -149,26 +83,13 @@ static void b43_wa_analog(struct b43_wldev *dev) } } -static void b43_wa_dac(struct b43_wldev *dev) -{ - if (dev->phy.analog == 1) - b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1, - (b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0034) | 0x0008); - else - b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1, - (b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0078) | 0x0010); -} - static void b43_wa_fft(struct b43_wldev *dev) /* Fine frequency table */ { int i; - if (dev->phy.type == B43_PHYTYPE_A) - for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqa[i]); - else - for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqg[i]); + for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, + b43_tab_finefreqg[i]); } static void b43_wa_nft(struct b43_wldev *dev) /* Noise figure table */ @@ -176,21 +97,14 @@ static void b43_wa_nft(struct b43_wldev *dev) /* Noise figure table */ struct b43_phy *phy = &dev->phy; int i; - if (phy->type == B43_PHYTYPE_A) { - if (phy->rev == 2) - for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea2[i]); - else - for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea3[i]); - } else { - if (phy->rev == 1) - for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg1[i]); - else - for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg2[i]); - } + if (phy->rev == 1) + for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, + b43_tab_noiseg1[i]); + else + for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, + b43_tab_noiseg2[i]); } static void b43_wa_rt(struct b43_wldev *dev) /* Rotor table */ @@ -201,14 +115,6 @@ static void b43_wa_rt(struct b43_wldev *dev) /* Rotor table */ b43_ofdmtab_write32(dev, B43_OFDMTAB_ROTOR, i, b43_tab_rotor[i]); } -static void b43_write_null_nst(struct b43_wldev *dev) -{ - int i; - - for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, i, 0); -} - static void b43_write_nst(struct b43_wldev *dev, const u16 *nst) { int i; @@ -221,24 +127,13 @@ static void b43_wa_nst(struct b43_wldev *dev) /* Noise scale table */ { struct b43_phy *phy = &dev->phy; - if (phy->type == B43_PHYTYPE_A) { - if (phy->rev <= 1) - b43_write_null_nst(dev); - else if (phy->rev == 2) - b43_write_nst(dev, b43_tab_noisescalea2); - else if (phy->rev == 3) - b43_write_nst(dev, b43_tab_noisescalea3); - else + if (phy->rev >= 6) { + if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) b43_write_nst(dev, b43_tab_noisescaleg3); + else + b43_write_nst(dev, b43_tab_noisescaleg2); } else { - if (phy->rev >= 6) { - if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) - b43_write_nst(dev, b43_tab_noisescaleg3); - else - b43_write_nst(dev, b43_tab_noisescaleg2); - } else { - b43_write_nst(dev, b43_tab_noisescaleg1); - } + b43_write_nst(dev, b43_tab_noisescaleg1); } } @@ -251,41 +146,13 @@ static void b43_wa_art(struct b43_wldev *dev) /* ADV retard table */ i, b43_tab_retard[i]); } -static void b43_wa_txlna_gain(struct b43_wldev *dev) -{ - b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 13, 0x0000); -} - -static void b43_wa_crs_reset(struct b43_wldev *dev) -{ - b43_phy_write(dev, 0x002C, 0x0064); -} - -static void b43_wa_2060txlna_gain(struct b43_wldev *dev) -{ - b43_hf_write(dev, b43_hf_read(dev) | - B43_HF_2060W); -} - -static void b43_wa_lms(struct b43_wldev *dev) -{ - b43_phy_maskset(dev, 0x0055, 0xFFC0, 0x0004); -} - -static void b43_wa_mixedsignal(struct b43_wldev *dev) -{ - b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1, 3); -} - static void b43_wa_msst(struct b43_wldev *dev) /* Min sigma square table */ { struct b43_phy *phy = &dev->phy; int i; const u16 *tab; - if (phy->type == B43_PHYTYPE_A) { - tab = b43_tab_sigmasqr1; - } else if (phy->type == B43_PHYTYPE_G) { + if (phy->type == B43_PHYTYPE_G) { tab = b43_tab_sigmasqr2; } else { B43_WARN_ON(1); @@ -298,13 +165,6 @@ static void b43_wa_msst(struct b43_wldev *dev) /* Min sigma square table */ } } -static void b43_wa_iqadc(struct b43_wldev *dev) -{ - if (dev->phy.analog == 4) - b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 0, - b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 0) & ~0xF000); -} - static void b43_wa_crs_ed(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -450,38 +310,6 @@ static void b43_wa_cpll_nonpilot(struct b43_wldev *dev) b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 1, 0); } -static void b43_wa_rssi_adc(struct b43_wldev *dev) -{ - if (dev->phy.analog == 4) - b43_phy_write(dev, 0x00DC, 0x7454); -} - -static void b43_wa_boards_a(struct b43_wldev *dev) -{ - if (dev->dev->board_vendor == SSB_BOARDVENDOR_BCM && - dev->dev->board_type == SSB_BOARD_BU4306 && - dev->dev->board_rev < 0x30) { - b43_phy_write(dev, 0x0010, 0xE000); - b43_phy_write(dev, 0x0013, 0x0140); - b43_phy_write(dev, 0x0014, 0x0280); - } else { - if (dev->dev->board_type == SSB_BOARD_MP4318 && - dev->dev->board_rev < 0x20) { - b43_phy_write(dev, 0x0013, 0x0210); - b43_phy_write(dev, 0x0014, 0x0840); - } else { - b43_phy_write(dev, 0x0013, 0x0140); - b43_phy_write(dev, 0x0014, 0x0280); - } - if (dev->phy.rev <= 4) - b43_phy_write(dev, 0x0010, 0xE000); - else - b43_phy_write(dev, 0x0010, 0x2000); - b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 1, 0x0039); - b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 7, 0x0040); - } -} - static void b43_wa_boards_g(struct b43_wldev *dev) { struct ssb_sprom *sprom = dev->dev->bus_sprom; @@ -518,80 +346,7 @@ void b43_wa_all(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - if (phy->type == B43_PHYTYPE_A) { - switch (phy->rev) { - case 2: - b43_wa_papd(dev); - b43_wa_auxclipthr(dev); - b43_wa_afcdac(dev); - b43_wa_txdc_offset(dev); - b43_wa_initgains(dev); - b43_wa_divider(dev); - b43_wa_gt(dev); - b43_wa_rssi_lt(dev); - b43_wa_analog(dev); - b43_wa_dac(dev); - b43_wa_fft(dev); - b43_wa_nft(dev); - b43_wa_rt(dev); - b43_wa_nst(dev); - b43_wa_art(dev); - b43_wa_txlna_gain(dev); - b43_wa_crs_reset(dev); - b43_wa_2060txlna_gain(dev); - b43_wa_lms(dev); - break; - case 3: - b43_wa_papd(dev); - b43_wa_mixedsignal(dev); - b43_wa_rssi_lt(dev); - b43_wa_txdc_offset(dev); - b43_wa_initgains(dev); - b43_wa_dac(dev); - b43_wa_nft(dev); - b43_wa_nst(dev); - b43_wa_msst(dev); - b43_wa_analog(dev); - b43_wa_gt(dev); - b43_wa_txpuoff_rxpuon(dev); - b43_wa_txlna_gain(dev); - break; - case 5: - b43_wa_iqadc(dev); - case 6: - b43_wa_papd(dev); - b43_wa_rssi_lt(dev); - b43_wa_txdc_offset(dev); - b43_wa_initgains(dev); - b43_wa_dac(dev); - b43_wa_nft(dev); - b43_wa_nst(dev); - b43_wa_msst(dev); - b43_wa_analog(dev); - b43_wa_gt(dev); - b43_wa_txpuoff_rxpuon(dev); - b43_wa_txlna_gain(dev); - break; - case 7: - b43_wa_iqadc(dev); - b43_wa_papd(dev); - b43_wa_rssi_lt(dev); - b43_wa_txdc_offset(dev); - b43_wa_initgains(dev); - b43_wa_dac(dev); - b43_wa_nft(dev); - b43_wa_nst(dev); - b43_wa_msst(dev); - b43_wa_analog(dev); - b43_wa_gt(dev); - b43_wa_txpuoff_rxpuon(dev); - b43_wa_txlna_gain(dev); - b43_wa_rssi_adc(dev); - default: - B43_WARN_ON(1); - } - b43_wa_boards_a(dev); - } else if (phy->type == B43_PHYTYPE_G) { + if (phy->type == B43_PHYTYPE_G) { switch (phy->rev) { case 1://XXX review rev1 b43_wa_crs_ed(dev); diff --git a/drivers/net/wireless/broadcom/b43/xmit.c b/drivers/net/wireless/broadcom/b43/xmit.c index f6201264de49..b068d5aeee24 100644 --- a/drivers/net/wireless/broadcom/b43/xmit.c +++ b/drivers/net/wireless/broadcom/b43/xmit.c @@ -205,7 +205,7 @@ static u16 b43_generate_tx_phy_ctl1(struct b43_wldev *dev, u8 bitrate) return control; } -static u8 b43_calc_fallback_rate(u8 bitrate) +static u8 b43_calc_fallback_rate(u8 bitrate, int gmode) { switch (bitrate) { case B43_CCK_RATE_1MB: @@ -216,8 +216,15 @@ static u8 b43_calc_fallback_rate(u8 bitrate) return B43_CCK_RATE_2MB; case B43_CCK_RATE_11MB: return B43_CCK_RATE_5MB; + /* + * Don't just fallback to CCK; it may be in 5GHz operation + * and falling back to CCK won't work out very well. + */ case B43_OFDM_RATE_6MB: - return B43_CCK_RATE_5MB; + if (gmode) + return B43_CCK_RATE_5MB; + else + return B43_OFDM_RATE_6MB; case B43_OFDM_RATE_9MB: return B43_OFDM_RATE_6MB; case B43_OFDM_RATE_12MB: @@ -438,7 +445,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB; rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); - rts_rate_fb = b43_calc_fallback_rate(rts_rate); + rts_rate_fb = b43_calc_fallback_rate(rts_rate, phy->gmode); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { @@ -642,11 +649,7 @@ static s8 b43_rssinoise_postprocess(struct b43_wldev *dev, u8 in_rssi) struct b43_phy *phy = &dev->phy; s8 ret; - if (phy->type == B43_PHYTYPE_A) { - //TODO: Incomplete specs. - ret = 0; - } else - ret = b43_rssi_postprocess(dev, in_rssi, 0, 1, 1); + ret = b43_rssi_postprocess(dev, in_rssi, 0, 1, 1); return ret; } @@ -663,7 +666,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) u16 uninitialized_var(chanstat), uninitialized_var(mactime); u32 uninitialized_var(macstat); u16 chanid; - u16 phytype; int padding, rate_idx; memset(&status, 0, sizeof(status)); @@ -684,7 +686,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) chanstat = le16_to_cpu(rxhdr->format_351.channel); break; } - phytype = chanstat & B43_RX_CHAN_PHYTYPE; if (unlikely(macstat & B43_RX_MAC_FCSERR)) { dev->wl->ieee_stats.dot11FCSErrorCount++; @@ -755,7 +756,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) else status.signal = max(rxhdr->power0, rxhdr->power1); break; - case B43_PHYTYPE_A: case B43_PHYTYPE_B: case B43_PHYTYPE_G: case B43_PHYTYPE_LP: @@ -802,14 +802,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT; switch (chanstat & B43_RX_CHAN_PHYTYPE) { - case B43_PHYTYPE_A: - status.band = NL80211_BAND_5GHZ; - B43_WARN_ON(1); - /* FIXME: We don't really know which value the "chanid" contains. - * So the following assignment might be wrong. */ - status.freq = - ieee80211_channel_to_frequency(chanid, status.band); - break; case B43_PHYTYPE_G: status.band = NL80211_BAND_2GHZ; /* Somewhere between 478.104 and 508.1084 firmware for G-PHY diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index c7550dab6a23..f549c25608d6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -166,41 +166,45 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) sdio_claim_irq(sdiodev->func[1], brcmf_sdiod_ib_irqhandler); sdio_claim_irq(sdiodev->func[2], brcmf_sdiod_dummy_irqhandler); sdio_release_host(sdiodev->func[1]); + sdiodev->sd_irq_requested = true; } return 0; } -int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) +void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) { - struct brcmfmac_sdio_pd *pdata; - brcmf_dbg(SDIO, "Entering\n"); + brcmf_dbg(SDIO, "Entering oob=%d sd=%d\n", + sdiodev->oob_irq_requested, + sdiodev->sd_irq_requested); - pdata = &sdiodev->settings->bus.sdio; - if (pdata->oob_irq_supported) { + if (sdiodev->oob_irq_requested) { + struct brcmfmac_sdio_pd *pdata; + + pdata = &sdiodev->settings->bus.sdio; sdio_claim_host(sdiodev->func[1]); brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL); brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL); sdio_release_host(sdiodev->func[1]); - if (sdiodev->oob_irq_requested) { - sdiodev->oob_irq_requested = false; - if (sdiodev->irq_wake) { - disable_irq_wake(pdata->oob_irq_nr); - sdiodev->irq_wake = false; - } - free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev); - sdiodev->irq_en = false; + sdiodev->oob_irq_requested = false; + if (sdiodev->irq_wake) { + disable_irq_wake(pdata->oob_irq_nr); + sdiodev->irq_wake = false; } - } else { + free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev); + sdiodev->irq_en = false; + sdiodev->oob_irq_requested = false; + } + + if (sdiodev->sd_irq_requested) { sdio_claim_host(sdiodev->func[1]); sdio_release_irq(sdiodev->func[2]); sdio_release_irq(sdiodev->func[1]); sdio_release_host(sdiodev->func[1]); + sdiodev->sd_irq_requested = false; } - - return 0; } void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev, @@ -722,8 +726,10 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, return -ENOMEM; err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr, glom_skb); - if (err) + if (err) { + brcmu_pkt_buf_free_skb(glom_skb); goto done; + } skb_queue_walk(pktq, skb) { memcpy(skb->data, glom_skb->data, skb->len); @@ -1197,12 +1203,17 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func) brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device); brcmf_dbg(SDIO, "Function: %d\n", func->num); - if (func->num != 1) - return; - bus_if = dev_get_drvdata(&func->dev); if (bus_if) { sdiodev = bus_if->bus_priv.sdio; + + /* start by unregistering irqs */ + brcmf_sdiod_intr_unregister(sdiodev); + + if (func->num != 1) + return; + + /* only proceed with rest of cleanup if func 1 */ brcmf_sdiod_remove(sdiodev); dev_set_drvdata(&sdiodev->func[1]->dev, NULL); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 62f475e31077..2628d5e12c64 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -541,6 +541,21 @@ brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev) ADDR_INDIRECT); } +static int brcmf_get_first_free_bsscfgidx(struct brcmf_pub *drvr) +{ + int bsscfgidx; + + for (bsscfgidx = 0; bsscfgidx < BRCMF_MAX_IFS; bsscfgidx++) { + /* bsscfgidx 1 is reserved for legacy P2P */ + if (bsscfgidx == 1) + continue; + if (!drvr->iflist[bsscfgidx]) + return bsscfgidx; + } + + return -ENOMEM; +} + static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp) { struct brcmf_mbss_ssid_le mbss_ssid_le; @@ -548,7 +563,7 @@ static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp) int err; memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le)); - bsscfgidx = brcmf_get_next_free_bsscfgidx(ifp->drvr); + bsscfgidx = brcmf_get_first_free_bsscfgidx(ifp->drvr); if (bsscfgidx < 0) return bsscfgidx; @@ -586,7 +601,7 @@ struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name, brcmf_dbg(INFO, "Adding vif \"%s\"\n", name); - vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP, false); + vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP); if (IS_ERR(vif)) return (struct wireless_dev *)vif; @@ -669,20 +684,24 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, return ERR_PTR(-EOPNOTSUPP); case NL80211_IFTYPE_AP: wdev = brcmf_ap_add_vif(wiphy, name, flags, params); - if (!IS_ERR(wdev)) - brcmf_cfg80211_update_proto_addr_mode(wdev); - return wdev; + break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_DEVICE: wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params); - if (!IS_ERR(wdev)) - brcmf_cfg80211_update_proto_addr_mode(wdev); - return wdev; + break; case NL80211_IFTYPE_UNSPECIFIED: default: return ERR_PTR(-EINVAL); } + + if (IS_ERR(wdev)) + brcmf_err("add iface %s type %d failed: err=%d\n", + name, type, (int)PTR_ERR(wdev)); + else + brcmf_cfg80211_update_proto_addr_mode(wdev); + + return wdev; } static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc) @@ -756,9 +775,13 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, if (!aborted) cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); } else if (scan_request) { + struct cfg80211_scan_info info = { + .aborted = aborted, + }; + brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n", aborted ? "Aborted" : "Done"); - cfg80211_scan_done(scan_request, aborted); + cfg80211_scan_done(scan_request, &info); } if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n"); @@ -766,12 +789,48 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, return err; } +static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); + struct net_device *ndev = wdev->netdev; + struct brcmf_if *ifp = netdev_priv(ndev); + int ret; + int err; + + brcmf_cfg80211_arm_vif_event(cfg, ifp->vif); + + err = brcmf_fil_bsscfg_data_set(ifp, "interface_remove", NULL, 0); + if (err) { + brcmf_err("interface_remove failed %d\n", err); + goto err_unarm; + } + + /* wait for firmware event */ + ret = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL, + BRCMF_VIF_EVENT_TIMEOUT); + if (!ret) { + brcmf_err("timeout occurred\n"); + err = -EIO; + goto err_unarm; + } + + brcmf_remove_interface(ifp, true); + +err_unarm: + brcmf_cfg80211_arm_vif_event(cfg, NULL); + return err; +} + static int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) { struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); struct net_device *ndev = wdev->netdev; + if (ndev && ndev == cfg_to_ndev(cfg)) + return -ENOTSUPP; + /* vif event pending in firmware */ if (brcmf_cfg80211_vif_event_armed(cfg)) return -EBUSY; @@ -788,12 +847,13 @@ int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) switch (wdev->iftype) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MESH_POINT: return -EOPNOTSUPP; + case NL80211_IFTYPE_AP: + return brcmf_cfg80211_del_ap_iface(wiphy, wdev); case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_DEVICE: @@ -2750,7 +2810,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, if (!bi->ctl_ch) { ch.chspec = le16_to_cpu(bi->chanspec); cfg->d11inf.decchspec(&ch); - bi->ctl_ch = ch.chnum; + bi->ctl_ch = ch.control_ch_num; } channel = bi->ctl_ch; @@ -2868,7 +2928,7 @@ static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg, else band = wiphy->bands[NL80211_BAND_5GHZ]; - freq = ieee80211_channel_to_frequency(ch.chnum, band->band); + freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band); cfg->channel = freq; notify_channel = ieee80211_get_channel(wiphy, freq); @@ -2878,7 +2938,7 @@ static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg, notify_ielen = le32_to_cpu(bi->ie_length); notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; - brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq); + brcmf_dbg(CONN, "channel: %d(%d)\n", ch.control_ch_num, freq); brcmf_dbg(CONN, "capability: %X\n", notify_capability); brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval); brcmf_dbg(CONN, "signal: %d\n", notify_signal); @@ -4439,7 +4499,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_join_params join_params; enum nl80211_iftype dev_role; struct brcmf_fil_bss_enable_le bss_enable; - u16 chanspec; + u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef); bool mbss; int is_11d; @@ -4515,16 +4575,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); + /* Parameters shared by all radio interfaces */ if (!mbss) { - chanspec = chandef_to_chanspec(&cfg->d11inf, - &settings->chandef); - err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); - if (err < 0) { - brcmf_err("Set Channel failed: chspec=%d, %d\n", - chanspec, err); - goto exit; - } - if (is_11d != ifp->vif->is_11d) { err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY, is_11d); @@ -4572,6 +4624,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, err = -EINVAL; goto exit; } + + /* Interface specific setup */ if (dev_role == NL80211_IFTYPE_AP) { if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss)) brcmf_fil_iovar_int_set(ifp, "mbss", 1); @@ -4581,6 +4635,17 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("setting AP mode failed %d\n", err); goto exit; } + if (!mbss) { + /* Firmware 10.x requires setting channel after enabling + * AP and before bringing interface up. + */ + err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); + if (err < 0) { + brcmf_err("Set Channel failed: chspec=%d, %d\n", + chanspec, err); + goto exit; + } + } err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); if (err < 0) { brcmf_err("BRCMF_C_UP error (%d)\n", err); @@ -4601,8 +4666,23 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("SET SSID error (%d)\n", err); goto exit; } + + if (settings->hidden_ssid) { + err = brcmf_fil_iovar_int_set(ifp, "closednet", 1); + if (err) { + brcmf_err("closednet error (%d)\n", err); + goto exit; + } + } + brcmf_dbg(TRACE, "AP mode configuration complete\n"); - } else { + } else if (dev_role == NL80211_IFTYPE_P2P_GO) { + err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); + if (err < 0) { + brcmf_err("Set Channel failed: chspec=%d, %d\n", + chanspec, err); + goto exit; + } err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le, sizeof(ssid_le)); if (err < 0) { @@ -4619,7 +4699,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, } brcmf_dbg(TRACE, "GO mode configuration complete\n"); + } else { + WARN_ON(1); } + set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); brcmf_net_setcarrier(ifp, true); @@ -4650,6 +4733,10 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) return err; } + /* First BSS doesn't get a full reset */ + if (ifp->bsscfgidx == 0) + brcmf_fil_iovar_int_set(ifp, "closednet", 0); + memset(&join_params, 0, sizeof(join_params)); err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, &join_params, sizeof(join_params)); @@ -4908,6 +4995,68 @@ exit: return err; } +static int brcmf_cfg80211_get_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef) +{ + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct net_device *ndev = wdev->netdev; + struct brcmf_if *ifp; + struct brcmu_chan ch; + enum nl80211_band band = 0; + enum nl80211_chan_width width = 0; + u32 chanspec; + int freq, err; + + if (!ndev) + return -ENODEV; + ifp = netdev_priv(ndev); + + err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec); + if (err) { + brcmf_err("chanspec failed (%d)\n", err); + return err; + } + + ch.chspec = chanspec; + cfg->d11inf.decchspec(&ch); + + switch (ch.band) { + case BRCMU_CHAN_BAND_2G: + band = NL80211_BAND_2GHZ; + break; + case BRCMU_CHAN_BAND_5G: + band = NL80211_BAND_5GHZ; + break; + } + + switch (ch.bw) { + case BRCMU_CHAN_BW_80: + width = NL80211_CHAN_WIDTH_80; + break; + case BRCMU_CHAN_BW_40: + width = NL80211_CHAN_WIDTH_40; + break; + case BRCMU_CHAN_BW_20: + width = NL80211_CHAN_WIDTH_20; + break; + case BRCMU_CHAN_BW_80P80: + width = NL80211_CHAN_WIDTH_80P80; + break; + case BRCMU_CHAN_BW_160: + width = NL80211_CHAN_WIDTH_160; + break; + } + + freq = ieee80211_channel_to_frequency(ch.control_ch_num, band); + chandef->chan = ieee80211_get_channel(wiphy, freq); + chandef->width = width; + chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band); + chandef->center_freq2 = 0; + + return 0; +} + static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy, struct wireless_dev *wdev, enum nl80211_crit_proto_id proto, @@ -5070,6 +5219,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { .mgmt_tx = brcmf_cfg80211_mgmt_tx, .remain_on_channel = brcmf_p2p_remain_on_channel, .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel, + .get_channel = brcmf_cfg80211_get_channel, .start_p2p_device = brcmf_p2p_start_device, .stop_p2p_device = brcmf_p2p_stop_device, .crit_proto_start = brcmf_cfg80211_crit_proto_start, @@ -5078,8 +5228,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { }; struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, - enum nl80211_iftype type, - bool pm_block) + enum nl80211_iftype type) { struct brcmf_cfg80211_vif *vif_walk; struct brcmf_cfg80211_vif *vif; @@ -5094,8 +5243,6 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, vif->wdev.wiphy = cfg->wiphy; vif->wdev.iftype = type; - vif->pm_block = pm_block; - brcmf_init_prof(&vif->profile); if (type == NL80211_IFTYPE_AP) { @@ -5296,7 +5443,7 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, else band = wiphy->bands[NL80211_BAND_5GHZ]; - freq = ieee80211_channel_to_frequency(ch.chnum, band->band); + freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band); notify_channel = ieee80211_get_channel(wiphy, freq); done: @@ -5352,7 +5499,6 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { - struct brcmf_if *ifp = netdev_priv(ndev); static int generation; u32 event = e->event_code; u32 reason = e->reason; @@ -5363,8 +5509,6 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, ndev != cfg_to_ndev(cfg)) { brcmf_dbg(CONN, "AP mode link down\n"); complete(&cfg->vif_disabled); - if (ifp->vif->mbss) - brcmf_remove_interface(ifp); return 0; } @@ -5818,14 +5962,15 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg, channel = band->channels; index = band->n_channels; for (j = 0; j < band->n_channels; j++) { - if (channel[j].hw_value == ch.chnum) { + if (channel[j].hw_value == ch.control_ch_num) { index = j; break; } } channel[index].center_freq = - ieee80211_channel_to_frequency(ch.chnum, band->band); - channel[index].hw_value = ch.chnum; + ieee80211_channel_to_frequency(ch.control_ch_num, + band->band); + channel[index].hw_value = ch.control_ch_num; /* assuming the chanspecs order is HT20, * HT40 upper, HT40 lower, and VHT80. @@ -5927,7 +6072,7 @@ static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg) 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) + if (band->channels[j].hw_value == ch.control_ch_num) break; } if (WARN_ON(j == band->n_channels)) @@ -6193,29 +6338,15 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) if (!combo) goto err; - c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL); - if (!c0_limits) - goto err; - - if (p2p) { - p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL); - if (!p2p_limits) - goto err; - } - - if (mbss) { - mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL); - if (!mbss_limits) - goto err; - } - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); c = 0; i = 0; - combo[c].num_different_channels = 1; + c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL); + if (!c0_limits) + goto err; c0_limits[i].max = 1; c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION); if (p2p) { @@ -6233,6 +6364,7 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) c0_limits[i].max = 1; c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); } + combo[c].num_different_channels = 1; combo[c].max_interfaces = i; combo[c].n_limits = i; combo[c].limits = c0_limits; @@ -6240,7 +6372,9 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) if (p2p) { c++; i = 0; - combo[c].num_different_channels = 1; + p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL); + if (!p2p_limits) + goto err; p2p_limits[i].max = 1; p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION); p2p_limits[i].max = 1; @@ -6249,6 +6383,7 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT); p2p_limits[i].max = 1; p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); + combo[c].num_different_channels = 1; combo[c].max_interfaces = i; combo[c].n_limits = i; combo[c].limits = p2p_limits; @@ -6256,14 +6391,19 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) if (mbss) { c++; + i = 0; + mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL); + if (!mbss_limits) + goto err; + mbss_limits[i].max = 4; + mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP); combo[c].beacon_int_infra_match = true; combo[c].num_different_channels = 1; - mbss_limits[0].max = 4; - mbss_limits[0].types = BIT(NL80211_IFTYPE_AP); combo[c].max_interfaces = 4; - combo[c].n_limits = 1; + combo[c].n_limits = i; combo[c].limits = mbss_limits; } + wiphy->n_iface_combinations = n_combos; wiphy->iface_combinations = combo; return 0; @@ -6715,11 +6855,10 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, return NULL; } - ops = kzalloc(sizeof(*ops), GFP_KERNEL); + ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL); if (!ops) return NULL; - memcpy(ops, &brcmf_cfg80211_ops, sizeof(*ops)); ifp = netdev_priv(ndev); #ifdef CONFIG_PM if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) @@ -6740,7 +6879,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, init_vif_event(&cfg->vif_event); INIT_LIST_HEAD(&cfg->vif_list); - vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false); + vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION); if (IS_ERR(vif)) goto wiphy_out; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 95e35bcc16ce..7d77f869b7f1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -20,6 +20,10 @@ /* for brcmu_d11inf */ #include <brcmu_d11.h> +#include "core.h" +#include "fwil_types.h" +#include "p2p.h" + #define WL_NUM_SCAN_MAX 10 #define WL_TLV_INFO_MAX 1024 #define WL_BSS_INFO_MAX 2048 @@ -167,7 +171,6 @@ struct vif_saved_ie { * @wdev: wireless device. * @profile: profile information. * @sme_state: SME state using enum brcmf_vif_status bits. - * @pm_block: power-management blocked. * @list: linked list. * @mgmt_rx_reg: registered rx mgmt frame types. * @mbss: Multiple BSS type, set if not first AP (not relevant for P2P). @@ -177,7 +180,6 @@ struct brcmf_cfg80211_vif { struct wireless_dev wdev; struct brcmf_cfg80211_profile profile; unsigned long sme_state; - bool pm_block; struct vif_saved_ie saved_ie; struct list_head list; u16 mgmt_rx_reg; @@ -388,8 +390,7 @@ s32 brcmf_cfg80211_down(struct net_device *ndev); enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp); struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, - enum nl80211_iftype type, - bool pm_block); + enum nl80211_iftype type); void brcmf_free_vif(struct brcmf_cfg80211_vif *vif); s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index d3fd6b1db1d9..05f22ff81d60 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -685,6 +685,8 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) case BRCM_CC_43602_CHIP_ID: case BRCM_CC_4371_CHIP_ID: return 0x180000; + case BRCM_CC_43465_CHIP_ID: + case BRCM_CC_43525_CHIP_ID: case BRCM_CC_4365_CHIP_ID: case BRCM_CC_4366_CHIP_ID: return 0x200000; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index b590499f6883..8d16f0204985 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -516,7 +516,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) /* set appropriate operations */ ndev->netdev_ops = &brcmf_netdev_ops_pri; - ndev->hard_header_len += drvr->hdrlen; + ndev->needed_headroom += drvr->hdrlen; ndev->ethtool_ops = &brcmf_ethtool_ops; drvr->rxsz = ndev->mtu + ndev->hard_header_len + @@ -548,12 +548,16 @@ fail: return -EBADE; } -static void brcmf_net_detach(struct net_device *ndev) +static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked) { - if (ndev->reg_state == NETREG_REGISTERED) - unregister_netdev(ndev); - else + if (ndev->reg_state == NETREG_REGISTERED) { + if (rtnl_locked) + unregister_netdevice(ndev); + else + unregister_netdev(ndev); + } else { brcmf_cfg80211_free_netdev(ndev); + } } void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on) @@ -634,7 +638,7 @@ fail: } struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, - bool is_p2pdev, char *name, u8 *mac_addr) + bool is_p2pdev, const char *name, u8 *mac_addr) { struct brcmf_if *ifp; struct net_device *ndev; @@ -651,7 +655,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, brcmf_err("ERROR: netdev:%s already exists\n", ifp->ndev->name); netif_stop_queue(ifp->ndev); - brcmf_net_detach(ifp->ndev); + brcmf_net_detach(ifp->ndev, false); drvr->iflist[bsscfgidx] = NULL; } else { brcmf_dbg(INFO, "netdev:%s ignore IF event\n", @@ -699,7 +703,8 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, return ifp; } -static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx) +static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx, + bool rtnl_locked) { struct brcmf_if *ifp; @@ -729,7 +734,7 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx) cancel_work_sync(&ifp->multicast_work); cancel_work_sync(&ifp->ndoffload_work); } - brcmf_net_detach(ifp->ndev); + brcmf_net_detach(ifp->ndev, rtnl_locked); } else { /* Only p2p device interfaces which get dynamically created * end up here. In this case the p2p module should be informed @@ -743,38 +748,14 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx) } } -void brcmf_remove_interface(struct brcmf_if *ifp) +void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked) { if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bsscfgidx] != ifp)) return; brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", ifp->bsscfgidx, ifp->ifidx); brcmf_fws_del_interface(ifp); - brcmf_del_if(ifp->drvr, ifp->bsscfgidx); -} - -int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr) -{ - int ifidx; - int bsscfgidx; - bool available; - int highest; - - available = false; - bsscfgidx = 2; - highest = 2; - for (ifidx = 0; ifidx < BRCMF_MAX_IFS; ifidx++) { - if (drvr->iflist[ifidx]) { - if (drvr->iflist[ifidx]->bsscfgidx == bsscfgidx) - bsscfgidx = highest + 1; - else if (drvr->iflist[ifidx]->bsscfgidx > highest) - highest = drvr->iflist[ifidx]->bsscfgidx; - } else { - available = true; - } - } - - return available ? bsscfgidx : -ENOMEM; + brcmf_del_if(ifp->drvr, ifp->bsscfgidx, rtnl_locked); } #ifdef CONFIG_INET @@ -1081,9 +1062,9 @@ fail: brcmf_fws_deinit(drvr); } if (ifp) - brcmf_net_detach(ifp->ndev); + brcmf_net_detach(ifp->ndev, false); if (p2p_ifp) - brcmf_net_detach(p2p_ifp->ndev); + brcmf_net_detach(p2p_ifp->ndev, false); drvr->iflist[0] = NULL; drvr->iflist[1] = NULL; if (drvr->settings->ignore_probe_fail) @@ -1152,7 +1133,7 @@ void brcmf_detach(struct device *dev) /* make sure primary interface removed last */ for (i = BRCMF_MAX_IFS-1; i > -1; i--) - brcmf_remove_interface(drvr->iflist[i]); + brcmf_remove_interface(drvr->iflist[i], false); brcmf_cfg80211_detach(drvr->config); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index 647d3cc2a4dc..8fa34cad5a96 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -215,9 +215,8 @@ char *brcmf_ifname(struct brcmf_if *ifp); struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx); int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, - bool is_p2pdev, char *name, u8 *mac_addr); -void brcmf_remove_interface(struct brcmf_if *ifp); -int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr); + bool is_p2pdev, const char *name, u8 *mac_addr); +void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked); void brcmf_txflowblock_if(struct brcmf_if *ifp, enum brcmf_netif_stop_reason reason, bool state); void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c index b390561255b3..79c081fd560f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c @@ -18,6 +18,7 @@ #include "brcmu_wifi.h" #include "brcmu_utils.h" +#include "cfg80211.h" #include "core.h" #include "debug.h" #include "tracepoint.h" @@ -182,8 +183,13 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); - if (ifp && ifevent->action == BRCMF_E_IF_DEL) - brcmf_remove_interface(ifp); + if (ifp && ifevent->action == BRCMF_E_IF_DEL) { + bool armed = brcmf_cfg80211_vif_event_armed(drvr->config); + + /* Default handling in case no-one waits for this event */ + if (!armed) + brcmf_remove_interface(ifp, false); + } } /** diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c index 5b30922b67ec..9f9024a7bd64 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c @@ -2101,7 +2101,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto)); /* determine the priority */ - if (!skb->priority) + if ((skb->priority == 0) || (skb->priority > 7)) skb->priority = cfg80211_classify8021d(skb, NULL); drvr->tx_multicast += !!multicast; @@ -2469,10 +2469,22 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb) void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked) { struct brcmf_fws_info *fws = drvr->fws; + struct brcmf_if *ifp; + int i; - fws->bus_flow_blocked = flow_blocked; - if (!flow_blocked) - brcmf_fws_schedule_deq(fws); - else - fws->stats.bus_flow_block++; + if (fws->avoid_queueing) { + for (i = 0; i < BRCMF_MAX_IFS; i++) { + ifp = drvr->iflist[i]; + if (!ifp || !ifp->ndev) + continue; + brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, + flow_blocked); + } + } else { + fws->bus_flow_blocked = flow_blocked; + if (!flow_blocked) + brcmf_fws_schedule_deq(fws); + else + fws->stats.bus_flow_block++; + } } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index a70cda6c0592..66f942f7448e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -1246,7 +1246,7 @@ bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg, if (!bi->ctl_ch) { ch.chspec = le16_to_cpu(bi->chanspec); cfg->d11inf.decchspec(&ch); - bi->ctl_ch = ch.chnum; + bi->ctl_ch = ch.control_ch_num; } afx_hdl->peer_chan = bi->ctl_ch; brcmf_dbg(TRACE, "ACTION FRAME SCAN : Peer %pM found, channel : %d\n", @@ -1385,7 +1385,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) && (ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) { - afx_hdl->peer_chan = ch.chnum; + afx_hdl->peer_chan = ch.control_ch_num; brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n", afx_hdl->peer_chan); complete(&afx_hdl->act_frm_scan); @@ -1428,7 +1428,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, memcpy(&mgmt_frame->u, frame, mgmt_frame_len); mgmt_frame_len += offsetof(struct ieee80211_mgmt, u); - freq = ieee80211_channel_to_frequency(ch.chnum, + freq = ieee80211_channel_to_frequency(ch.control_ch_num, ch.band == BRCMU_CHAN_BAND_2G ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ); @@ -1873,7 +1873,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) && (ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) { - afx_hdl->peer_chan = ch.chnum; + afx_hdl->peer_chan = ch.control_ch_num; brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n", afx_hdl->peer_chan); complete(&afx_hdl->act_frm_scan); @@ -1898,7 +1898,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, mgmt_frame = (u8 *)(rxframe + 1); mgmt_frame_len = e->datalen - sizeof(*rxframe); - freq = ieee80211_channel_to_frequency(ch.chnum, + freq = ieee80211_channel_to_frequency(ch.control_ch_num, ch.band == BRCMU_CHAN_BAND_2G ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ); @@ -2030,8 +2030,6 @@ static int brcmf_p2p_request_p2p_if(struct brcmf_p2p_info *p2p, err = brcmf_fil_iovar_data_set(ifp, "p2p_ifadd", &if_request, sizeof(if_request)); - if (err) - return err; return err; } @@ -2076,8 +2074,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif) return ERR_PTR(-ENOSPC); - p2p_vif = brcmf_alloc_vif(p2p->cfg, NL80211_IFTYPE_P2P_DEVICE, - false); + p2p_vif = brcmf_alloc_vif(p2p->cfg, NL80211_IFTYPE_P2P_DEVICE); if (IS_ERR(p2p_vif)) { brcmf_err("could not create discovery vif\n"); return (struct wireless_dev *)p2p_vif; @@ -2177,7 +2174,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, return ERR_PTR(-EOPNOTSUPP); } - vif = brcmf_alloc_vif(cfg, type, false); + vif = brcmf_alloc_vif(cfg, type); if (IS_ERR(vif)) return (struct wireless_dev *)vif; brcmf_cfg80211_arm_vif_event(cfg, vif); @@ -2264,6 +2261,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) return 0; brcmf_p2p_cancel_remain_on_channel(vif->ifp); brcmf_p2p_deinit_discovery(p2p); + break; + default: return -ENOTSUPP; } @@ -2289,8 +2288,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) else err = 0; } - if (err) - brcmf_remove_interface(vif->ifp); + brcmf_remove_interface(vif->ifp, true); brcmf_cfg80211_arm_vif_event(cfg, NULL); if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE) @@ -2396,7 +2394,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) if (vif != NULL) { brcmf_p2p_cancel_remain_on_channel(vif->ifp); brcmf_p2p_deinit_discovery(p2p); - brcmf_remove_interface(vif->ifp); + brcmf_remove_interface(vif->ifp, false); } /* just set it all to zero */ memset(p2p, 0, sizeof(*p2p)); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 0af8db82da0c..3deba90c7eb5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -54,21 +54,25 @@ BRCMF_FW_NVRAM_DEF(43570, "brcmfmac43570-pcie.bin", "brcmfmac43570-pcie.txt"); BRCMF_FW_NVRAM_DEF(4358, "brcmfmac4358-pcie.bin", "brcmfmac4358-pcie.txt"); BRCMF_FW_NVRAM_DEF(4359, "brcmfmac4359-pcie.bin", "brcmfmac4359-pcie.txt"); BRCMF_FW_NVRAM_DEF(4365B, "brcmfmac4365b-pcie.bin", "brcmfmac4365b-pcie.txt"); +BRCMF_FW_NVRAM_DEF(4365C, "brcmfmac4365c-pcie.bin", "brcmfmac4365c-pcie.txt"); BRCMF_FW_NVRAM_DEF(4366B, "brcmfmac4366b-pcie.bin", "brcmfmac4366b-pcie.txt"); BRCMF_FW_NVRAM_DEF(4366C, "brcmfmac4366c-pcie.bin", "brcmfmac4366c-pcie.txt"); BRCMF_FW_NVRAM_DEF(4371, "brcmfmac4371-pcie.bin", "brcmfmac4371-pcie.txt"); static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43465_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4350_CHIP_ID, 0x000000FF, 4350C), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4350_CHIP_ID, 0xFFFFFF00, 4350), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43525_CHIP_ID, 0xFFFFFFF0, 4365C), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43567_CHIP_ID, 0xFFFFFFFF, 43570), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43570), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43570_CHIP_ID, 0xFFFFFFFF, 43570), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFFF, 4365B), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0x0000000F, 4365B), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFF0, 4365C), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 67e69bff2545..68ab3ac15650 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -1384,8 +1384,7 @@ static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header, return -ENXIO; } if (rd->seq_num != rx_seq) { - brcmf_err("seq %d: sequence number error, expect %d\n", - rx_seq, rd->seq_num); + brcmf_dbg(SDIO, "seq %d, expected %d\n", rx_seq, rd->seq_num); bus->sdcnt.rx_badseq++; rd->seq_num = rx_seq; } @@ -3306,10 +3305,6 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, goto err; } - /* Allow full data communication using DPC from now on. */ - brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA); - bcmerror = 0; - err: brcmf_sdio_clkctl(bus, CLK_SDONLY, false); sdio_release_host(bus->sdiodev->func[1]); @@ -3666,7 +3661,7 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, str_shift = 11; break; default: - brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", + brcmf_dbg(INFO, "No SDIO driver strength init needed for chip %s rev %d pmurev %d\n", ci->name, ci->chiprev, ci->pmurev); break; } @@ -4047,6 +4042,9 @@ static void brcmf_sdio_firmware_callback(struct device *dev, } if (err == 0) { + /* Allow full data communication using DPC from now on. */ + brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA); + err = brcmf_sdiod_intr_register(sdiodev); if (err != 0) brcmf_err("intr register failed:%d\n", err); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h index dcf0ce8cd2c1..f3da32fc6360 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h @@ -186,6 +186,7 @@ struct brcmf_sdio_dev { struct brcmf_bus *bus_if; struct brcmf_mp_device *settings; bool oob_irq_requested; + bool sd_irq_requested; bool irq_en; /* irq enable flags */ spinlock_t irq_en_lock; bool irq_wake; /* irq wake enable flags */ @@ -293,7 +294,7 @@ struct sdpcmd_regs { /* Register/deregister interrupt handler. */ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev); -int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev); +void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev); /* sdio device register access interface */ u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c index 796f5f9d5d5a..b7df576bb84d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c @@ -1079,8 +1079,10 @@ bool dma_rxfill(struct dma_pub *pub) pa = dma_map_single(di->dmadev, p->data, di->rxbufsize, DMA_FROM_DEVICE); - if (dma_mapping_error(di->dmadev, pa)) + if (dma_mapping_error(di->dmadev, pa)) { + brcmu_pkt_buf_free_skb(p); return false; + } /* save the free packet pointer */ di->rxp[rxout] = p; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c index e16ee60639f5..c2a938b59044 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c @@ -3349,8 +3349,8 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc) dma_rxfill(wlc_hw->di[RX_FIFO]); } -void -static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) { +static void brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) +{ u32 macintmask; bool fastclk; struct brcms_c_info *wlc = wlc_hw->wlc; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c index 99dac9b8a082..b3aab2fe96eb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c @@ -27017,7 +27017,7 @@ wlc_phy_rxcal_gainctrl_nphy_rev5(struct brcms_phy *pi, u8 rx_core, tx_core = 1 - rx_core; num_samps = 1024; - desired_log2_pwr = (cal_type == 0) ? 13 : 13; + desired_log2_pwr = 13; wlc_phy_rx_iq_coeffs_nphy(pi, 0, &save_comp); zero_comp.a0 = zero_comp.b0 = zero_comp.a1 = zero_comp.b1 = 0x0; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.c index dd9162722495..0ab865de1491 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.c @@ -87,7 +87,7 @@ void brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel, u16 chanspec) { - struct tx_power power; + struct tx_power power = { }; u8 siso_mcs_id, cdd_mcs_id, stbc_mcs_id; /* Clear previous settings */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c index 2b2522bdd8eb..d8b79cb72b58 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c @@ -107,6 +107,7 @@ static void brcmu_d11n_decchspec(struct brcmu_chan *ch) u16 val; ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK); + ch->control_ch_num = ch->chnum; switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) { case BRCMU_CHSPEC_D11N_BW_20: @@ -118,10 +119,10 @@ static void brcmu_d11n_decchspec(struct brcmu_chan *ch) val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK; if (val == BRCMU_CHSPEC_D11N_SB_L) { ch->sb = BRCMU_CHAN_SB_L; - ch->chnum -= CH_10MHZ_APART; + ch->control_ch_num -= CH_10MHZ_APART; } else { ch->sb = BRCMU_CHAN_SB_U; - ch->chnum += CH_10MHZ_APART; + ch->control_ch_num += CH_10MHZ_APART; } break; default: @@ -147,6 +148,7 @@ static void brcmu_d11ac_decchspec(struct brcmu_chan *ch) u16 val; ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK); + ch->control_ch_num = ch->chnum; switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) { case BRCMU_CHSPEC_D11AC_BW_20: @@ -158,10 +160,10 @@ static void brcmu_d11ac_decchspec(struct brcmu_chan *ch) val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK; if (val == BRCMU_CHSPEC_D11AC_SB_L) { ch->sb = BRCMU_CHAN_SB_L; - ch->chnum -= CH_10MHZ_APART; + ch->control_ch_num -= CH_10MHZ_APART; } else if (val == BRCMU_CHSPEC_D11AC_SB_U) { ch->sb = BRCMU_CHAN_SB_U; - ch->chnum += CH_10MHZ_APART; + ch->control_ch_num += CH_10MHZ_APART; } else { WARN_ON_ONCE(1); } @@ -172,16 +174,16 @@ static void brcmu_d11ac_decchspec(struct brcmu_chan *ch) BRCMU_CHSPEC_D11AC_SB_SHIFT); switch (ch->sb) { case BRCMU_CHAN_SB_LL: - ch->chnum -= CH_30MHZ_APART; + ch->control_ch_num -= CH_30MHZ_APART; break; case BRCMU_CHAN_SB_LU: - ch->chnum -= CH_10MHZ_APART; + ch->control_ch_num -= CH_10MHZ_APART; break; case BRCMU_CHAN_SB_UL: - ch->chnum += CH_10MHZ_APART; + ch->control_ch_num += CH_10MHZ_APART; break; case BRCMU_CHAN_SB_UU: - ch->chnum += CH_30MHZ_APART; + ch->control_ch_num += CH_30MHZ_APART; break; default: WARN_ON_ONCE(1); diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h index 699f2c2782ee..3cc42bef6245 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -40,7 +40,9 @@ #define BRCM_CC_4339_CHIP_ID 0x4339 #define BRCM_CC_43430_CHIP_ID 43430 #define BRCM_CC_4345_CHIP_ID 0x4345 +#define BRCM_CC_43465_CHIP_ID 43465 #define BRCM_CC_4350_CHIP_ID 0x4350 +#define BRCM_CC_43525_CHIP_ID 43525 #define BRCM_CC_4354_CHIP_ID 0x4354 #define BRCM_CC_4356_CHIP_ID 0x4356 #define BRCM_CC_43566_CHIP_ID 43566 diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h index f9745ea8b3e0..8b8b2ecb3199 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h @@ -125,14 +125,36 @@ enum brcmu_chan_sb { BRCMU_CHAN_SB_UU = BRCMU_CHAN_SB_LUU, }; +/** + * struct brcmu_chan - stores channel formats + * + * This structure can be used with functions translating chanspec into generic + * channel info and the other way. + * + * @chspec: firmware specific format + * @chnum: center channel number + * @control_ch_num: control channel number + * @band: frequency band + * @bw: channel width + * @sb: control sideband (location of control channel against the center one) + */ struct brcmu_chan { u16 chspec; u8 chnum; + u8 control_ch_num; u8 band; enum brcmu_chan_bw bw; enum brcmu_chan_sb sb; }; +/** + * struct brcmu_d11inf - provides functions translating channel format + * + * @io_type: determines version of channel format used by firmware + * @encchspec: encodes channel info into a chanspec, requires center channel + * number, ignores control one + * @decchspec: decodes chanspec into generic info + */ struct brcmu_d11inf { u8 io_type; diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c index ca3cd2102bd6..69b826d229c5 100644 --- a/drivers/net/wireless/cisco/airo.c +++ b/drivers/net/wireless/cisco/airo.c @@ -1102,8 +1102,8 @@ static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)"; struct airo_info; static int get_dec_u16( char *buffer, int *start, int limit ); -static void OUT4500( struct airo_info *, u16 register, u16 value ); -static unsigned short IN4500( struct airo_info *, u16 register ); +static void OUT4500( struct airo_info *, u16 reg, u16 value ); +static unsigned short IN4500( struct airo_info *, u16 reg ); static u16 setup_card(struct airo_info*, u8 *mac, int lock); static int enable_MAC(struct airo_info *ai, int lock); static void disable_MAC(struct airo_info *ai, int lock); diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index 5adb7cefb2fe..bfd68612a535 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -4093,7 +4093,7 @@ static const char *ipw_get_status_code(u16 status) return "Unknown status value."; } -static void inline average_init(struct average *avg) +static inline void average_init(struct average *avg) { memset(avg, 0, sizeof(*avg)); } diff --git a/drivers/net/wireless/intel/iwlegacy/3945.c b/drivers/net/wireless/intel/iwlegacy/3945.c index 7bcedbb53d94..209dc9988455 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945.c +++ b/drivers/net/wireless/intel/iwlegacy/3945.c @@ -1019,12 +1019,13 @@ il3945_hw_txq_ctx_free(struct il_priv *il) int txq_id; /* Tx queues */ - if (il->txq) + if (il->txq) { for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) if (txq_id == IL39_CMD_QUEUE_NUM) il_cmd_queue_free(il); else il_tx_queue_free(il, txq_id); + } /* free tx queue structure */ il_free_txq_mem(il); diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index eb24b9241bb2..140b6ea8f7cc 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -1305,10 +1305,14 @@ il_send_scan_abort(struct il_priv *il) static void il_complete_scan(struct il_priv *il, bool aborted) { + struct cfg80211_scan_info info = { + .aborted = aborted, + }; + /* check if scan was requested from mac80211 */ if (il->scan_request) { D_SCAN("Complete scan in mac80211\n"); - ieee80211_scan_completed(il->hw, aborted); + ieee80211_scan_completed(il->hw, &info); } il->scan_vif = NULL; diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 05828c61d1ab..6e7ed908de0c 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -8,7 +8,7 @@ iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o -iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o iwl-9000.o +iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o iwl-9000.o iwl-a000.o iwlwifi-objs += iwl-trans.o iwlwifi-objs += $(iwlwifi-m) diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c index 8dda52ae3bb5..6c2d6da7eec6 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c @@ -205,23 +205,6 @@ static const __le32 iwlagn_def_3w_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = { cpu_to_le32(0xf0005000), }; - -/* Loose Coex */ -static const __le32 iwlagn_loose_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = { - cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xaeaaaaaa), - cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xcc00ff28), - cpu_to_le32(0x0000aaaa), - cpu_to_le32(0xcc00aaaa), - cpu_to_le32(0x0000aaaa), - cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0xf0005000), - cpu_to_le32(0xf0005000), -}; - /* Full concurrency */ static const __le32 iwlagn_concurrent_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = { cpu_to_le32(0xaaaaaaaa), diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index 37b32a6f60fd..b49848683587 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1317,6 +1317,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); switch (iwlwifi_mod_params.amsdu_size) { + case IWL_AMSDU_DEF: case IWL_AMSDU_4K: trans_cfg.rx_buf_size = IWL_AMSDU_4K; break; @@ -1336,6 +1337,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, trans_cfg.command_groups_size = ARRAY_SIZE(iwl_dvm_groups); trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM; + trans_cfg.cb_data_offs = offsetof(struct ieee80211_tx_info, + driver_data[2]); WARN_ON(sizeof(priv->transport_queue_stop) * BITS_PER_BYTE < priv->cfg->base_params->num_of_queues); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c index b228552184b5..087e579854ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c @@ -523,11 +523,6 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv, return ret; } - if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION && - priv->cfg->ht_params && priv->cfg->ht_params->smps_mode) - ieee80211_request_smps(ctx->vif, - priv->cfg->ht_params->smps_mode); - return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/scan.c b/drivers/net/wireless/intel/iwlwifi/dvm/scan.c index d01766f16175..17e6a32384d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/scan.c @@ -94,10 +94,14 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) { + struct cfg80211_scan_info info = { + .aborted = aborted, + }; + /* check if scan was requested from mac80211 */ if (priv->scan_request) { IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n"); - ieee80211_scan_completed(priv->hw, aborted); + ieee80211_scan_completed(priv->hw, &info); } priv->scan_type = IWL_SCAN_NORMAL; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c index f4d92155fa76..64690c14ff4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c @@ -73,8 +73,8 @@ /* Highest firmware API version supported */ #define IWL7260_UCODE_API_MAX 17 #define IWL7265_UCODE_API_MAX 17 -#define IWL7265D_UCODE_API_MAX 21 -#define IWL3168_UCODE_API_MAX 21 +#define IWL7265D_UCODE_API_MAX 24 +#define IWL3168_UCODE_API_MAX 24 /* Lowest firmware API version supported */ #define IWL7260_UCODE_API_MIN 16 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c index 8bf11c918dfd..6c6725e808d4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c @@ -70,8 +70,8 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 21 -#define IWL8265_UCODE_API_MAX 21 +#define IWL8000_UCODE_API_MAX 24 +#define IWL8265_UCODE_API_MAX 24 /* Lowest firmware API version supported */ #define IWL8000_UCODE_API_MIN 16 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index 3ac298fdd3cd..fbaf705f3fa7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -55,7 +55,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL9000_UCODE_API_MAX 21 +#define IWL9000_UCODE_API_MAX 24 /* Lowest firmware API version supported */ #define IWL9000_UCODE_API_MIN 16 @@ -178,6 +178,7 @@ const struct iwl_cfg iwl5165_2ac_cfg = { .nvm_ver = IWL9000_NVM_VERSION, .nvm_calib_ver = IWL9000_TX_POWER_VERSION, .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, }; MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c new file mode 100644 index 000000000000..4d78232c8afe --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c @@ -0,0 +1,131 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015-2016 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015-2016 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include <linux/module.h> +#include <linux/stringify.h> +#include "iwl-config.h" +#include "iwl-agn-hw.h" + +/* Highest firmware API version supported */ +#define IWL_A000_UCODE_API_MAX 24 + +/* Lowest firmware API version supported */ +#define IWL_A000_UCODE_API_MIN 24 + +/* NVM versions */ +#define IWL_A000_NVM_VERSION 0x0a1d +#define IWL_A000_TX_POWER_VERSION 0xffff /* meaningless */ + +/* Memory offsets and lengths */ +#define IWL_A000_DCCM_OFFSET 0x800000 +#define IWL_A000_DCCM_LEN 0x18000 +#define IWL_A000_DCCM2_OFFSET 0x880000 +#define IWL_A000_DCCM2_LEN 0x8000 +#define IWL_A000_SMEM_OFFSET 0x400000 +#define IWL_A000_SMEM_LEN 0x68000 + +#define IWL_A000_FW_PRE "iwlwifi-Qu-a0-jf-b0-" +#define IWL_A000_MODULE_FIRMWARE(api) \ + IWL_A000_FW_PRE "-" __stringify(api) ".ucode" + +#define NVM_HW_SECTION_NUM_FAMILY_A000 10 + +static const struct iwl_base_params iwl_a000_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_A000, + .num_of_queues = 31, + .shadow_ram_support = true, + .led_compensation = 57, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = true, + .pcie_l1_allowed = true, +}; + +static const struct iwl_ht_params iwl_a000_ht_params = { + .stbc = true, + .ldpc = true, + .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), +}; + +#define IWL_DEVICE_A000 \ + .ucode_api_max = IWL_A000_UCODE_API_MAX, \ + .ucode_api_min = IWL_A000_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_8000, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .base_params = &iwl_a000_base_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_A000, \ + .non_shared_ant = ANT_A, \ + .dccm_offset = IWL_A000_DCCM_OFFSET, \ + .dccm_len = IWL_A000_DCCM_LEN, \ + .dccm2_offset = IWL_A000_DCCM2_OFFSET, \ + .dccm2_len = IWL_A000_DCCM2_LEN, \ + .smem_offset = IWL_A000_SMEM_OFFSET, \ + .smem_len = IWL_A000_SMEM_LEN, \ + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \ + .apmg_not_supported = true, \ + .mq_rx_supported = true, \ + .vht_mu_mimo_supported = true, \ + .mac_addr_from_csr = true, \ + .use_tfh = true + +const struct iwl_cfg iwla000_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC a000", + .fw_name_pre = IWL_A000_FW_PRE, + IWL_DEVICE_A000, + .ht_params = &iwl_a000_ht_params, + .nvm_ver = IWL_A000_NVM_VERSION, + .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + +MODULE_FIRMWARE(IWL_A000_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 4a0af7de82fd..423b23320d4f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -66,8 +66,9 @@ #define __IWL_CONFIG_H__ #include <linux/types.h> -#include <net/mac80211.h> - +#include <linux/netdevice.h> +#include <linux/ieee80211.h> +#include <linux/nl80211.h> enum iwl_device_family { IWL_DEVICE_FAMILY_UNDEFINED, @@ -192,7 +193,6 @@ struct iwl_base_params { * @ht40_bands: bitmap of bands (using %NL80211_BAND_*) that support HT40 */ struct iwl_ht_params { - enum ieee80211_smps_mode smps_mode; u8 ht_greenfield_support:1, stbc:1, ldpc:1, @@ -261,6 +261,7 @@ struct iwl_tt_params { #define OTP_LOW_IMAGE_SIZE_FAMILY_7000 (16 * 512 * sizeof(u16)) /* 16 KB */ #define OTP_LOW_IMAGE_SIZE_FAMILY_8000 (32 * 512 * sizeof(u16)) /* 32 KB */ #define OTP_LOW_IMAGE_SIZE_FAMILY_9000 OTP_LOW_IMAGE_SIZE_FAMILY_8000 +#define OTP_LOW_IMAGE_SIZE_FAMILY_A000 OTP_LOW_IMAGE_SIZE_FAMILY_9000 struct iwl_eeprom_params { const u8 regulatory_bands[7]; @@ -319,6 +320,7 @@ struct iwl_pwr_tx_backoff { * @mq_rx_supported: multi-queue rx support * @vht_mu_mimo_supported: VHT MU-MIMO support * @rf_id: need to read rf_id to determine the firmware image + * @integrated: discrete or integrated * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -362,7 +364,9 @@ struct iwl_cfg { apmg_not_supported:1, mq_rx_supported:1, vht_mu_mimo_supported:1, - rf_id:1; + rf_id:1, + integrated:1, + use_tfh:1; u8 valid_tx_ant; u8 valid_rx_ant; u8 non_shared_ant; @@ -448,6 +452,7 @@ extern const struct iwl_cfg iwl4165_2ac_sdio_cfg; extern const struct iwl_cfg iwl9260_2ac_cfg; extern const struct iwl_cfg iwl9260lc_2ac_cfg; extern const struct iwl_cfg iwl5165_2ac_cfg; +extern const struct iwl_cfg iwla000_2ac_cfg; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index b52913448c4a..871ad02fdb17 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -145,8 +145,10 @@ #define CSR_LED_REG (CSR_BASE+0x094) #define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) -#define CSR_MAC_SHADOW_REG_CTRL (CSR_BASE+0x0A8) /* 6000 and up */ - +#define CSR_MAC_SHADOW_REG_CTRL (CSR_BASE + 0x0A8) /* 6000 and up */ +#define CSR_MAC_SHADOW_REG_CTRL_RX_WAKE BIT(20) +#define CSR_MAC_SHADOW_REG_CTL2 (CSR_BASE + 0x0AC) +#define CSR_MAC_SHADOW_REG_CTL2_RX_WAKE 0xFFFF /* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-debug.h b/drivers/net/wireless/intel/iwlwifi/iwl-debug.h index 110333208450..cd77c6971753 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-debug.h @@ -41,6 +41,7 @@ static inline bool iwl_have_debug_level(u32 level) #endif } +struct device; void __iwl_err(struct device *dev, bool rfkill_prefix, bool only_trace, const char *fmt, ...) __printf(4, 5); void __iwl_warn(struct device *dev, const char *fmt, ...) __printf(2, 3); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h index 27914eedc146..1dccae6532cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -83,6 +84,23 @@ TRACE_EVENT(iwlwifi_dev_iowrite32, __get_str(dev), __entry->offs, __entry->val) ); +TRACE_EVENT(iwlwifi_dev_iowrite64, + TP_PROTO(const struct device *dev, u64 offs, u64 val), + TP_ARGS(dev, offs, val), + TP_STRUCT__entry( + DEV_ENTRY + __field(u64, offs) + __field(u64, val) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->offs = offs; + __entry->val = val; + ), + TP_printk("[%s] write io[%llu] = %llu)", + __get_str(dev), __entry->offs, __entry->val) +); + TRACE_EVENT(iwlwifi_dev_iowrite_prph32, TP_PROTO(const struct device *dev, u32 offs, u32 val), TP_ARGS(dev, offs, val), @@ -100,6 +118,23 @@ TRACE_EVENT(iwlwifi_dev_iowrite_prph32, __get_str(dev), __entry->offs, __entry->val) ); +TRACE_EVENT(iwlwifi_dev_iowrite_prph64, + TP_PROTO(const struct device *dev, u64 offs, u64 val), + TP_ARGS(dev, offs, val), + TP_STRUCT__entry( + DEV_ENTRY + __field(u64, offs) + __field(u64, val) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->offs = offs; + __entry->val = val; + ), + TP_printk("[%s] write PRPH[%llu] = %llu)", + __get_str(dev), __entry->offs, __entry->val) +); + TRACE_EVENT(iwlwifi_dev_ioread_prph32, TP_PROTO(const struct device *dev, u32 offs, u32 val), TP_ARGS(dev, offs, val), diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h index f4d3cd010087..545d14b0bc92 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. + * Copyright(C) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -33,11 +34,29 @@ static inline bool iwl_trace_data(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (void *)skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + __le16 fc = hdr->frame_control; + int offs = 24; /* start with normal header length */ - if (!ieee80211_is_data(hdr->frame_control)) + if (!ieee80211_is_data(fc)) return false; - return !(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO); + + /* Try to determine if the frame is EAPOL. This might have false + * positives (if there's no RFC 1042 header and we compare to some + * payload instead) but since we're only doing tracing that's not + * a problem. + */ + + if (ieee80211_has_a4(fc)) + offs += 6; + if (ieee80211_is_data_qos(fc)) + offs += 2; + /* don't account for crypto - these are unencrypted */ + + /* also account for the RFC 1042 header, of course */ + offs += 6; + + return skb->len > offs + 2 && + *(__be16 *)(skb->data + offs) == cpu_to_be16(ETH_P_PAE); } static inline size_t iwl_rx_trace_len(const struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index f52ff75f6f80..45b2f679e4d8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -129,8 +129,8 @@ struct iwl_drv { }; enum { - DVM_OP_MODE = 0, - MVM_OP_MODE = 1, + DVM_OP_MODE, + MVM_OP_MODE, }; /* Protects the table contents, i.e. the ops pointer & drv list */ @@ -326,8 +326,6 @@ static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len) int i, j; struct iwl_fw_cscheme_list *l = (struct iwl_fw_cscheme_list *)data; struct iwl_fw_cipher_scheme *fwcs; - struct ieee80211_cipher_scheme *cs; - u32 cipher; if (len < sizeof(*l) || len < sizeof(l->size) + l->size * sizeof(l->cs[0])) @@ -335,22 +333,12 @@ static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len) for (i = 0, j = 0; i < IWL_UCODE_MAX_CS && i < l->size; i++) { fwcs = &l->cs[j]; - cipher = le32_to_cpu(fwcs->cipher); /* we skip schemes with zero cipher suite selector */ - if (!cipher) + if (!fwcs->cipher) continue; - cs = &fw->cs[j++]; - cs->cipher = cipher; - cs->iftype = BIT(NL80211_IFTYPE_STATION); - cs->hdr_len = fwcs->hdr_len; - cs->pn_len = fwcs->pn_len; - cs->pn_off = fwcs->pn_off; - cs->key_idx_off = fwcs->key_idx_off; - cs->key_idx_mask = fwcs->key_idx_mask; - cs->key_idx_shift = fwcs->key_idx_shift; - cs->mic_len = fwcs->mic_len; + fw->cs[j++] = *fwcs; } return 0; @@ -795,17 +783,17 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, case IWL_UCODE_TLV_SEC_RT: iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR, tlv_len); - drv->fw.mvm_fw = true; + drv->fw.type = IWL_FW_MVM; break; case IWL_UCODE_TLV_SEC_INIT: iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT, tlv_len); - drv->fw.mvm_fw = true; + drv->fw.type = IWL_FW_MVM; break; case IWL_UCODE_TLV_SEC_WOWLAN: iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN, tlv_len); - drv->fw.mvm_fw = true; + drv->fw.type = IWL_FW_MVM; break; case IWL_UCODE_TLV_DEF_CALIB: if (tlv_len != sizeof(struct iwl_tlv_calib_data)) @@ -827,17 +815,17 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, case IWL_UCODE_TLV_SECURE_SEC_RT: iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR, tlv_len); - drv->fw.mvm_fw = true; + drv->fw.type = IWL_FW_MVM; break; case IWL_UCODE_TLV_SECURE_SEC_INIT: iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT, tlv_len); - drv->fw.mvm_fw = true; + drv->fw.type = IWL_FW_MVM; break; case IWL_UCODE_TLV_SECURE_SEC_WOWLAN: iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN, tlv_len); - drv->fw.mvm_fw = true; + drv->fw.type = IWL_FW_MVM; break; case IWL_UCODE_TLV_NUM_OF_CPU: if (tlv_len != sizeof(u32)) @@ -1275,7 +1263,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) * In mvm uCode there is no difference between data and instructions * sections. */ - if (!fw->mvm_fw && validate_sec_sizes(drv, pieces, drv->cfg)) + if (fw->type == IWL_FW_DVM && validate_sec_sizes(drv, pieces, drv->cfg)) goto try_again; /* Allocate ucode buffers for card's bus-master loading ... */ @@ -1403,10 +1391,16 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) release_firmware(ucode_raw); mutex_lock(&iwlwifi_opmode_table_mtx); - if (fw->mvm_fw) - op = &iwlwifi_opmode_table[MVM_OP_MODE]; - else + switch (fw->type) { + case IWL_FW_DVM: op = &iwlwifi_opmode_table[DVM_OP_MODE]; + break; + default: + WARN(1, "Invalid fw type %d\n", fw->type); + case IWL_FW_MVM: + op = &iwlwifi_opmode_table[MVM_OP_MODE]; + break; + } IWL_INFO(drv, "loaded firmware version %s op_mode %s\n", drv->fw.fw_version, op->name); @@ -1658,7 +1652,8 @@ MODULE_PARM_DESC(11n_disable, "disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX"); module_param_named(amsdu_size, iwlwifi_mod_params.amsdu_size, int, S_IRUGO); -MODULE_PARM_DESC(amsdu_size, "amsdu size 0:4K 1:8K 2:12K (default 0)"); +MODULE_PARM_DESC(amsdu_size, + "amsdu size 0: 12K for multi Rx queue devices, 4K for other devices 1:4K 2:8K 3:12K (default 0)"); module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, bool, S_IRUGO); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)"); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c index bf1b69aec813..3199d345b427 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c @@ -766,7 +766,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, if (cfg->ht_params->ldpc) ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; - if (iwlwifi_mod_params.amsdu_size >= IWL_AMSDU_8K) + if ((cfg->mq_rx_supported && + iwlwifi_mod_params.amsdu_size != IWL_AMSDU_4K) || + iwlwifi_mod_params.amsdu_size >= IWL_AMSDU_8K) ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; ht_info->ampdu_factor = cfg->max_ht_ampdu_exponent; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h index 1f4e50289c14..e04a91d70a15 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h @@ -66,6 +66,7 @@ #include <linux/types.h> #include <linux/if_ether.h> +#include <net/cfg80211.h> #include "iwl-trans.h" struct iwl_nvm_data { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index 270f39ecd2d4..1d6f5d21a663 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -77,6 +77,7 @@ */ #define FH_MEM_LOWER_BOUND (0x1000) #define FH_MEM_UPPER_BOUND (0x2000) +#define TFH_MEM_LOWER_BOUND (0xA06000) /** * Keep-Warm (KW) buffer base address. @@ -118,10 +119,17 @@ #define FH_MEM_CBBC_16_19_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) #define FH_MEM_CBBC_20_31_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xB20) #define FH_MEM_CBBC_20_31_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xB80) +/* a000 TFD table address, 64 bit */ +#define TFH_TFDQ_CBB_TABLE (TFH_MEM_LOWER_BOUND + 0x1C00) /* Find TFD CB base pointer for given queue */ -static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) +static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, + unsigned int chnl) { + if (trans->cfg->use_tfh) { + WARN_ON_ONCE(chnl >= 64); + return TFH_TFDQ_CBB_TABLE + 8 * chnl; + } if (chnl < 16) return FH_MEM_CBBC_0_15_LOWER_BOUND + 4 * chnl; if (chnl < 20) @@ -130,6 +138,65 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) return FH_MEM_CBBC_20_31_LOWER_BOUND + 4 * (chnl - 20); } +/* a000 configuration registers */ + +/* + * TFH Configuration register. + * + * BIT fields: + * + * Bits 3:0: + * Define the maximum number of pending read requests. + * Maximum configration value allowed is 0xC + * Bits 9:8: + * Define the maximum transfer size. (64 / 128 / 256) + * Bit 10: + * When bit is set and transfer size is set to 128B, the TFH will enable + * reading chunks of more than 64B only if the read address is aligned to 128B. + * In case of DRAM read address which is not aligned to 128B, the TFH will + * enable transfer size which doesn't cross 64B DRAM address boundary. +*/ +#define TFH_TRANSFER_MODE (TFH_MEM_LOWER_BOUND + 0x1F40) +#define TFH_TRANSFER_MAX_PENDING_REQ 0xc +#define TFH_CHUNK_SIZE_128 BIT(8) +#define TFH_CHUNK_SPLIT_MODE BIT(10) +/* + * Defines the offset address in dwords referring from the beginning of the + * Tx CMD which will be updated in DRAM. + * Note that the TFH offset address for Tx CMD update is always referring to + * the start of the TFD first TB. + * In case of a DRAM Tx CMD update the TFH will update PN and Key ID + */ +#define TFH_TXCMD_UPDATE_CFG (TFH_MEM_LOWER_BOUND + 0x1F48) +/* + * Controls TX DMA operation + * + * BIT fields: + * + * Bits 31:30: Enable the SRAM DMA channel. + * Turning on bit 31 will kick the SRAM2DRAM DMA. + * Note that the sram2dram may be enabled only after configuring the DRAM and + * SRAM addresses registers and the byte count register. + * Bits 25:24: Defines the interrupt target upon dram2sram transfer done. When + * set to 1 - interrupt is sent to the driver + * Bit 0: Indicates the snoop configuration +*/ +#define TFH_SRV_DMA_CHNL0_CTRL (TFH_MEM_LOWER_BOUND + 0x1F60) +#define TFH_SRV_DMA_SNOOP BIT(0) +#define TFH_SRV_DMA_TO_DRIVER BIT(24) +#define TFH_SRV_DMA_START BIT(31) + +/* Defines the DMA SRAM write start address to transfer a data block */ +#define TFH_SRV_DMA_CHNL0_SRAM_ADDR (TFH_MEM_LOWER_BOUND + 0x1F64) + +/* Defines the 64bits DRAM start address to read the DMA data block from */ +#define TFH_SRV_DMA_CHNL0_DRAM_ADDR (TFH_MEM_LOWER_BOUND + 0x1F68) + +/* + * Defines the number of bytes to transfer from DRAM to SRAM. + * Note that this register may be configured with non-dword aligned size. + */ +#define TFH_SRV_DMA_CHNL0_BC (TFH_MEM_LOWER_BOUND + 0x1F70) /** * Rx SRAM Control and Status Registers (RSCSR) @@ -344,6 +411,32 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) #define RFH_RBDBUF_RBD0_LSB 0xA08300 #define RFH_RBDBUF_RBD_LSB(q) (RFH_RBDBUF_RBD0_LSB + (q) * 8) +/** + * RFH Status Register + * + * Bit fields: + * + * Bit 29: RBD_FETCH_IDLE + * This status flag is set by the RFH when there is no active RBD fetch from + * DRAM. + * Once the RFH RBD controller starts fetching (or when there is a pending + * RBD read response from DRAM), this flag is immediately turned off. + * + * Bit 30: SRAM_DMA_IDLE + * This status flag is set by the RFH when there is no active transaction from + * SRAM to DRAM. + * Once the SRAM to DRAM DMA is active, this flag is immediately turned off. + * + * Bit 31: RXF_DMA_IDLE + * This status flag is set by the RFH when there is no active transaction from + * RXF to DRAM. + * Once the RXF-to-DRAM DMA is active, this flag is immediately turned off. + */ +#define RFH_GEN_STATUS 0xA09808 +#define RBD_FETCH_IDLE BIT(29) +#define SRAM_DMA_IDLE BIT(30) +#define RXF_DMA_IDLE BIT(31) + /* DMA configuration */ #define RFH_RXF_DMA_CFG 0xA09820 /* RB size */ @@ -384,7 +477,9 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) #define RFH_GEN_CFG 0xA09800 #define RFH_GEN_CFG_SERVICE_DMA_SNOOP BIT(0) #define RFH_GEN_CFG_RFH_DMA_SNOOP BIT(1) -#define RFH_GEN_CFG_RB_CHUNK_SIZE BIT(4) /* 0 - 64B, 1- 128B */ +#define RFH_GEN_CFG_RB_CHUNK_SIZE_POS 4 +#define RFH_GEN_CFG_RB_CHUNK_SIZE_128 1 +#define RFH_GEN_CFG_RB_CHUNK_SIZE_64 0 #define RFH_GEN_CFG_DEFAULT_RXQ_NUM_MASK 0xF00 #define RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS 8 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h index 09b7ea28f4a0..420c31dab263 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h @@ -89,6 +89,9 @@ * @IWL_FW_ERROR_PAGING: UMAC's image memory segments which were * paged to the DRAM. * @IWL_FW_ERROR_DUMP_RADIO_REG: Dump the radio registers. + * @IWL_FW_ERROR_DUMP_EXTERNAL: used only by external code utilities, and + * for that reason is not in use in any other place in the Linux Wi-Fi + * stack. */ enum iwl_fw_error_dump_type { /* 0 is deprecated */ @@ -106,6 +109,7 @@ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_PAGING = 12, IWL_FW_ERROR_DUMP_RADIO_REG = 13, IWL_FW_ERROR_DUMP_INTERNAL_TXF = 14, + IWL_FW_ERROR_DUMP_EXTERNAL = 15, /* Do not move */ IWL_FW_ERROR_DUMP_MAX, }; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index 37dc09e8b6a7..1b1e045f8907 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -301,7 +301,8 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command * @IWL_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics - * @IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD: support p2p standalone U-APSD + * @IWL_UCODE_TLV_CAPA_P2P_SCM_UAPSD: supports U-APSD on p2p interface when it + * is standalone or with a BSS station interface in the same binding. * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running * @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different * sources for the MCC. This TLV bit is a future replacement to @@ -312,6 +313,9 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement * @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT + * @IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD: the firmware supports CSA + * countdown offloading. Beacon notifications are not sent to the host. + * The fw also offloads TBTT alignment. * @IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what * antenna the beacon should be transmitted * @IWL_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon @@ -326,6 +330,9 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG: support getting more shared * memory addresses from the firmware. * @IWL_UCODE_TLV_CAPA_LQM_SUPPORT: supports Link Quality Measurement + * @IWL_UCODE_TLV_CAPA_TX_POWER_ACK: reduced TX power API has larger + * command size (command version 4) that supports toggling ACK TX + * power reduction. * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ @@ -347,7 +354,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT = (__force iwl_ucode_tlv_capa_t)19, IWL_UCODE_TLV_CAPA_CSUM_SUPPORT = (__force iwl_ucode_tlv_capa_t)21, IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = (__force iwl_ucode_tlv_capa_t)22, - IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD = (__force iwl_ucode_tlv_capa_t)26, + IWL_UCODE_TLV_CAPA_P2P_SCM_UAPSD = (__force iwl_ucode_tlv_capa_t)26, IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = (__force iwl_ucode_tlv_capa_t)28, IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29, IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30, @@ -356,6 +363,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65, IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67, IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT = (__force iwl_ucode_tlv_capa_t)68, + IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD = (__force iwl_ucode_tlv_capa_t)70, IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = (__force iwl_ucode_tlv_capa_t)71, IWL_UCODE_TLV_CAPA_BEACON_STORING = (__force iwl_ucode_tlv_capa_t)72, IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73, @@ -365,6 +373,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED = (__force iwl_ucode_tlv_capa_t)77, IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG = (__force iwl_ucode_tlv_capa_t)80, IWL_UCODE_TLV_CAPA_LQM_SUPPORT = (__force iwl_ucode_tlv_capa_t)81, + IWL_UCODE_TLV_CAPA_TX_POWER_ACK = (__force iwl_ucode_tlv_capa_t)84, NUM_IWL_UCODE_TLV_CAPA #ifdef __CHECKER__ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw.h index e461d631893a..74ea68d1063c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw.h @@ -67,7 +67,6 @@ #ifndef __iwl_fw_h__ #define __iwl_fw_h__ #include <linux/types.h> -#include <net/mac80211.h> #include "iwl-fw-file.h" #include "iwl-fw-error-dump.h" @@ -231,6 +230,16 @@ struct iwl_gscan_capabilities { }; /** + * enum iwl_fw_type - iwlwifi firmware type + * @IWL_FW_DVM: DVM firmware + * @IWL_FW_MVM: MVM firmware + */ +enum iwl_fw_type { + IWL_FW_DVM, + IWL_FW_MVM, +}; + +/** * struct iwl_fw - variables associated with the firmware * * @ucode_ver: ucode version from the ucode file @@ -244,7 +253,7 @@ struct iwl_gscan_capabilities { * @inst_evtlog_ptr: event log offset for runtime ucode. * @inst_evtlog_size: event log size for runtime ucode. * @inst_errlog_ptr: error log offfset for runtime ucode. - * @mvm_fw: indicates this is MVM firmware + * @type: firmware type (&enum iwl_fw_type) * @cipher_scheme: optional external cipher scheme. * @human_readable: human readable version * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until @@ -275,9 +284,9 @@ struct iwl_fw { u8 valid_tx_ant; u8 valid_rx_ant; - bool mvm_fw; + enum iwl_fw_type type; - struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; + struct iwl_fw_cipher_scheme cs[IWL_UCODE_MAX_CS]; u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; u32 sdio_adma_addr; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index 32c8f84ae519..92c8b5f9a9cb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -1,7 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project. * @@ -51,6 +51,14 @@ void iwl_write32(struct iwl_trans *trans, u32 ofs, u32 val) } IWL_EXPORT_SYMBOL(iwl_write32); +void iwl_write64(struct iwl_trans *trans, u64 ofs, u64 val) +{ + trace_iwlwifi_dev_iowrite64(trans->dev, ofs, val); + iwl_trans_write32(trans, ofs, val & 0xffffffff); + iwl_trans_write32(trans, ofs + 4, val >> 32); +} +IWL_EXPORT_SYMBOL(iwl_write64); + u32 iwl_read32(struct iwl_trans *trans, u32 ofs) { u32 val = iwl_trans_read32(trans, ofs); @@ -102,6 +110,17 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) } IWL_EXPORT_SYMBOL(iwl_write_direct32); +void iwl_write_direct64(struct iwl_trans *trans, u64 reg, u64 value) +{ + unsigned long flags; + + if (iwl_trans_grab_nic_access(trans, &flags)) { + iwl_write64(trans, reg, value); + iwl_trans_release_nic_access(trans, &flags); + } +} +IWL_EXPORT_SYMBOL(iwl_write_direct64); + int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, int timeout) { @@ -133,6 +152,14 @@ void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val) } IWL_EXPORT_SYMBOL(iwl_write_prph_no_grab); +void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val) +{ + trace_iwlwifi_dev_iowrite_prph64(trans->dev, ofs, val); + iwl_write_prph_no_grab(trans, ofs, val & 0xffffffff); + iwl_write_prph_no_grab(trans, ofs + 4, val >> 32); +} +IWL_EXPORT_SYMBOL(iwl_write_prph64_no_grab); + u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) { unsigned long flags; @@ -228,9 +255,117 @@ void iwl_force_nmi(struct iwl_trans *trans) } IWL_EXPORT_SYMBOL(iwl_force_nmi); -static const char *get_fh_string(int cmd) +static const char *get_rfh_string(int cmd) { #define IWL_CMD(x) case x: return #x +#define IWL_CMD_MQ(arg, reg, q) { if (arg == reg(q)) return #reg; } + + int i; + + for (i = 0; i < IWL_MAX_RX_HW_QUEUES; i++) { + IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_BA_LSB, i); + IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_WIDX, i); + IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_RIDX, i); + IWL_CMD_MQ(cmd, RFH_Q_URBD_STTS_WPTR_LSB, i); + }; + + switch (cmd) { + IWL_CMD(RFH_RXF_DMA_CFG); + IWL_CMD(RFH_GEN_CFG); + IWL_CMD(RFH_GEN_STATUS); + IWL_CMD(FH_TSSR_TX_STATUS_REG); + IWL_CMD(FH_TSSR_TX_ERROR_REG); + default: + return "UNKNOWN"; + } +#undef IWL_CMD_MQ +} + +struct reg { + u32 addr; + bool is64; +}; + +static int iwl_dump_rfh(struct iwl_trans *trans, char **buf) +{ + int i, q; + int num_q = trans->num_rx_queues; + static const u32 rfh_tbl[] = { + RFH_RXF_DMA_CFG, + RFH_GEN_CFG, + RFH_GEN_STATUS, + FH_TSSR_TX_STATUS_REG, + FH_TSSR_TX_ERROR_REG, + }; + static const struct reg rfh_mq_tbl[] = { + { RFH_Q0_FRBDCB_BA_LSB, true }, + { RFH_Q0_FRBDCB_WIDX, false }, + { RFH_Q0_FRBDCB_RIDX, false }, + { RFH_Q0_URBD_STTS_WPTR_LSB, true }, + }; + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (buf) { + int pos = 0; + /* + * Register (up to 34 for name + 8 blank/q for MQ): 40 chars + * Colon + space: 2 characters + * 0X%08x: 10 characters + * New line: 1 character + * Total of 53 characters + */ + size_t bufsz = ARRAY_SIZE(rfh_tbl) * 53 + + ARRAY_SIZE(rfh_mq_tbl) * 53 * num_q + 40; + + *buf = kmalloc(bufsz, GFP_KERNEL); + if (!*buf) + return -ENOMEM; + + pos += scnprintf(*buf + pos, bufsz - pos, + "RFH register values:\n"); + + for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++) + pos += scnprintf(*buf + pos, bufsz - pos, + "%40s: 0X%08x\n", + get_rfh_string(rfh_tbl[i]), + iwl_read_prph(trans, rfh_tbl[i])); + + for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++) + for (q = 0; q < num_q; q++) { + u32 addr = rfh_mq_tbl[i].addr; + + addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4); + pos += scnprintf(*buf + pos, bufsz - pos, + "%34s(q %2d): 0X%08x\n", + get_rfh_string(addr), q, + iwl_read_prph(trans, addr)); + } + + return pos; + } +#endif + + IWL_ERR(trans, "RFH register values:\n"); + for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++) + IWL_ERR(trans, " %34s: 0X%08x\n", + get_rfh_string(rfh_tbl[i]), + iwl_read_prph(trans, rfh_tbl[i])); + + for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++) + for (q = 0; q < num_q; q++) { + u32 addr = rfh_mq_tbl[i].addr; + + addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4); + IWL_ERR(trans, " %34s(q %d): 0X%08x\n", + get_rfh_string(addr), q, + iwl_read_prph(trans, addr)); + } + + return 0; +} + +static const char *get_fh_string(int cmd) +{ switch (cmd) { IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); @@ -262,6 +397,9 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf) FH_TSSR_TX_ERROR_REG }; + if (trans->cfg->mq_rx_supported) + return iwl_dump_rfh(trans, buf); + #ifdef CONFIG_IWLWIFI_DEBUGFS if (buf) { int pos = 0; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-io.h index a9bcc788cae1..5c8c0e130194 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.h @@ -34,6 +34,7 @@ void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val); void iwl_write32(struct iwl_trans *trans, u32 ofs, u32 val); +void iwl_write64(struct iwl_trans *trans, u64 ofs, u64 val); u32 iwl_read32(struct iwl_trans *trans, u32 ofs); static inline void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) @@ -53,11 +54,13 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg); void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value); +void iwl_write_direct64(struct iwl_trans *trans, u64 reg, u64 value); u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs); u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs); void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val); +void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val); void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val); int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, u32 bits, u32 mask, int timeout); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h index 6c5c2f9f73a2..4d32b10fe50c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h @@ -66,7 +66,6 @@ #include <linux/types.h> #include <linux/spinlock.h> #include <linux/gfp.h> -#include <net/mac80211.h> extern struct iwl_mod_params iwlwifi_mod_params; @@ -87,9 +86,10 @@ enum iwl_disable_11n { }; enum iwl_amsdu_size { - IWL_AMSDU_4K = 0, - IWL_AMSDU_8K = 1, - IWL_AMSDU_12K = 2, + IWL_AMSDU_DEF = 0, + IWL_AMSDU_4K = 1, + IWL_AMSDU_8K = 2, + IWL_AMSDU_12K = 3, }; enum iwl_uapsd_disable { @@ -105,7 +105,7 @@ enum iwl_uapsd_disable { * @sw_crypto: using hardware encryption, default = 0 * @disable_11n: disable 11n capabilities, default = 0, * use IWL_[DIS,EN]ABLE_HT_* constants - * @amsdu_size: enable 8K amsdu size, default = 4K. enum iwl_amsdu_size. + * @amsdu_size: See &enum iwl_amsdu_size. * @restart_fw: restart firmware, default = 1 * @bt_coex_active: enable bt coex, default = true * @led_mode: system default, default = 0 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 21653fee806c..43f8f7d45ddb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -397,6 +397,13 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; switch (iwlwifi_mod_params.amsdu_size) { + case IWL_AMSDU_DEF: + if (cfg->mq_rx_supported) + vht_cap->cap |= + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; + else + vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; + break; case IWL_AMSDU_4K: vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; break; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 6c1d20ded04b..459bf736fd5b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -417,5 +417,6 @@ enum { }; #define UREG_CHICK (0xA05C00) +#define UREG_CHICK_MSI_ENABLE BIT(24) #define UREG_CHICK_MSIX_ENABLE BIT(25) #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 8193d36ae2dd..5535e2238da3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -211,6 +211,9 @@ struct iwl_cmd_header_wide { #define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */ #define FH_RSCSR_FRAME_INVALID 0x55550000 #define FH_RSCSR_FRAME_ALIGN 0x40 +#define FH_RSCSR_RPA_EN BIT(25) +#define FH_RSCSR_RXQ_POS 16 +#define FH_RSCSR_RXQ_MASK 0x3F0000 struct iwl_rx_packet { /* @@ -220,7 +223,13 @@ struct iwl_rx_packet { * 31: flag flush RB request * 30: flag ignore TC (terminal counter) request * 29: flag fast IRQ request - * 28-14: Reserved + * 28-26: Reserved + * 25: Offload enabled + * 24: RPF enabled + * 23: RSS enabled + * 22: Checksum enabled + * 21-16: RX queue + * 15-14: Reserved * 13-00: RX frame size */ __le32 len_n_flags; @@ -383,11 +392,6 @@ static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r) #define MAX_NO_RECLAIM_CMDS 6 -/* - * The first entry in driver_data array in ieee80211_tx_info - * that can be used by the transport. - */ -#define IWL_TRANS_FIRST_DRIVER_DATA 2 #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) /* @@ -491,6 +495,8 @@ struct iwl_hcmd_arr { * @command_groups_size: number of command groups, to avoid illegal access * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until * we get the ALIVE from the uCode + * @cb_data_offs: offset inside skb->cb to store transport data at, must have + * space for at least two pointers */ struct iwl_trans_config { struct iwl_op_mode *op_mode; @@ -510,6 +516,8 @@ struct iwl_trans_config { int command_groups_size; u32 sdio_adma_addr; + + u8 cb_data_offs; }; struct iwl_trans_dump_data { @@ -574,6 +582,7 @@ struct iwl_trans_txq_scd_cfg { * configured. May sleep. * @txq_disable: de-configure a Tx queue to send AMPDUs * Must be atomic + * @txq_set_shared_mode: change Tx queue shared/unshared marking * @wait_tx_queue_empty: wait until tx queues are empty. May sleep. * @freeze_txq_timer: prevents the timer of the queue from firing until the * queue is set to awake. Must be atomic. @@ -637,6 +646,9 @@ struct iwl_trans_ops { void (*txq_disable)(struct iwl_trans *trans, int queue, bool configure_scd); + void (*txq_set_shared_mode)(struct iwl_trans *trans, u32 txq_id, + bool shared); + int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm); void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs, bool freeze); @@ -749,6 +761,7 @@ enum iwl_plat_pm_mode { * @ops - pointer to iwl_trans_ops * @op_mode - pointer to the op_mode * @cfg - pointer to the configuration + * @drv - pointer to iwl_drv * @status: a bit-mask of transport status flags * @dev - pointer to struct device * that represents the device * @max_skb_frags: maximum number of fragments an SKB can have when transmitted. @@ -792,6 +805,7 @@ struct iwl_trans { const struct iwl_trans_ops *ops; struct iwl_op_mode *op_mode; const struct iwl_cfg *cfg; + struct iwl_drv *drv; enum iwl_trans_state state; unsigned long status; @@ -1052,6 +1066,13 @@ iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout); } +static inline void iwl_trans_txq_set_shared_mode(struct iwl_trans *trans, + int queue, bool shared_mode) +{ + if (trans->ops->txq_set_shared_mode) + trans->ops->txq_set_shared_mode(trans, queue, shared_mode); +} + static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, int fifo, int sta_id, int tid, int frame_limit, u16 ssn, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index a63f5bbb1ba7..5bdb6c2c8390 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -142,7 +142,7 @@ static const __le64 iwl_ci_mask[][3] = { cpu_to_le64(0x0) }, { - cpu_to_le64(0xFFC0000000ULL), + cpu_to_le64(0xFE00000000ULL), cpu_to_le64(0x0ULL), cpu_to_le64(0x0ULL) }, @@ -615,8 +615,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, * don't reduce the Tx power if one of these is true: * we are in LOOSE * single share antenna product - * BT is active - * we are associated + * BT is inactive + * we are not associated */ if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 406cf1cb945c..b34489817c70 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1020,6 +1020,8 @@ static ssize_t iwl_dbgfs_max_amsdu_len_write(struct iwl_mvm *mvm, int ret; ret = kstrtouint(buf, 0, &max_amsdu_len); + if (ret) + return ret; if (max_amsdu_len > IEEE80211_MAX_MPDU_LEN_VHT_11454) return -EINVAL; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h index 2a33b694ba10..204c1b13988b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h @@ -70,85 +70,6 @@ #define BITS(nb) (BIT(nb) - 1) -/** - * enum iwl_bt_coex_flags - flags for BT_COEX command - * @BT_COEX_MODE_POS: - * @BT_COEX_MODE_MSK: - * @BT_COEX_DISABLE_OLD: - * @BT_COEX_2W_OLD: - * @BT_COEX_3W_OLD: - * @BT_COEX_NW_OLD: - * @BT_COEX_AUTO_OLD: - * @BT_COEX_BT_OLD: Antenna is for BT (manufacuring tests) - * @BT_COEX_WIFI_OLD: Antenna is for BT (manufacuring tests) - * @BT_COEX_SYNC2SCO: - * @BT_COEX_CORUNNING: - * @BT_COEX_MPLUT: - * @BT_COEX_TTC: - * @BT_COEX_RRC: - * - * The COEX_MODE must be set for each command. Even if it is not changed. - */ -enum iwl_bt_coex_flags { - BT_COEX_MODE_POS = 3, - BT_COEX_MODE_MSK = BITS(3) << BT_COEX_MODE_POS, - BT_COEX_DISABLE_OLD = 0x0 << BT_COEX_MODE_POS, - BT_COEX_2W_OLD = 0x1 << BT_COEX_MODE_POS, - BT_COEX_3W_OLD = 0x2 << BT_COEX_MODE_POS, - BT_COEX_NW_OLD = 0x3 << BT_COEX_MODE_POS, - BT_COEX_AUTO_OLD = 0x5 << BT_COEX_MODE_POS, - BT_COEX_BT_OLD = 0x6 << BT_COEX_MODE_POS, - BT_COEX_WIFI_OLD = 0x7 << BT_COEX_MODE_POS, - BT_COEX_SYNC2SCO = BIT(7), - BT_COEX_CORUNNING = BIT(8), - BT_COEX_MPLUT = BIT(9), - BT_COEX_TTC = BIT(20), - BT_COEX_RRC = BIT(21), -}; - -/* - * indicates what has changed in the BT_COEX command. - * BT_VALID_ENABLE must be set for each command. Commands without this bit will - * discarded by the firmware - */ -enum iwl_bt_coex_valid_bit_msk { - BT_VALID_ENABLE = BIT(0), - BT_VALID_BT_PRIO_BOOST = BIT(1), - BT_VALID_MAX_KILL = BIT(2), - BT_VALID_3W_TMRS = BIT(3), - BT_VALID_KILL_ACK = BIT(4), - BT_VALID_KILL_CTS = BIT(5), - BT_VALID_REDUCED_TX_POWER = BIT(6), - BT_VALID_LUT = BIT(7), - BT_VALID_WIFI_RX_SW_PRIO_BOOST = BIT(8), - BT_VALID_WIFI_TX_SW_PRIO_BOOST = BIT(9), - BT_VALID_MULTI_PRIO_LUT = BIT(10), - BT_VALID_TRM_KICK_FILTER = BIT(11), - BT_VALID_CORUN_LUT_20 = BIT(12), - BT_VALID_CORUN_LUT_40 = BIT(13), - BT_VALID_ANT_ISOLATION = BIT(14), - BT_VALID_ANT_ISOLATION_THRS = BIT(15), - BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16), - BT_VALID_TXRX_MAX_FREQ_0 = BIT(17), - BT_VALID_SYNC_TO_SCO = BIT(18), - BT_VALID_TTC = BIT(20), - BT_VALID_RRC = BIT(21), -}; - -/** - * enum iwl_bt_reduced_tx_power - allows to reduce txpower for WiFi frames. - * @BT_REDUCED_TX_POWER_CTL: reduce Tx power for control frames - * @BT_REDUCED_TX_POWER_DATA: reduce Tx power for data frames - * - * This mechanism allows to have BT and WiFi run concurrently. Since WiFi - * reduces its Tx power, it can work along with BT, hence reducing the amount - * of WiFi frames being killed by BT. - */ -enum iwl_bt_reduced_tx_power { - BT_REDUCED_TX_POWER_CTL = BIT(0), - BT_REDUCED_TX_POWER_DATA = BIT(1), -}; - enum iwl_bt_coex_lut_type { BT_COEX_TIGHT_LUT = 0, BT_COEX_LOOSE_LUT, @@ -158,64 +79,9 @@ enum iwl_bt_coex_lut_type { BT_COEX_INVALID_LUT = 0xff, }; /* BT_COEX_DECISION_LUT_INDEX_API_E_VER_1 */ -#define BT_COEX_LUT_SIZE (12) #define BT_COEX_CORUN_LUT_SIZE (32) -#define BT_COEX_MULTI_PRIO_LUT_SIZE (2) -#define BT_COEX_BOOST_SIZE (4) #define BT_REDUCED_TX_POWER_BIT BIT(7) -/** - * struct iwl_bt_coex_cmd_old - bt coex configuration command - * @flags:&enum iwl_bt_coex_flags - * @max_kill: - * @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power - * @override_primary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT - * should be set by default - * @override_secondary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT - * should be set by default - * @bt4_antenna_isolation: antenna isolation - * @bt4_antenna_isolation_thr: antenna threshold value - * @bt4_tx_tx_delta_freq_thr: TxTx delta frequency - * @bt4_tx_rx_max_freq0: TxRx max frequency - * @bt_prio_boost: BT priority boost registers - * @wifi_tx_prio_boost: SW boost of wifi tx priority - * @wifi_rx_prio_boost: SW boost of wifi rx priority - * @kill_ack_msk: kill ACK mask. 1 - Tx ACK, 0 - kill Tx of ACK. - * @kill_cts_msk: kill CTS mask. 1 - Tx CTS, 0 - kill Tx of CTS. - * @decision_lut: PTA decision LUT, per Prio-Ch - * @bt4_multiprio_lut: multi priority LUT configuration - * @bt4_corun_lut20: co-running 20 MHz LUT configuration - * @bt4_corun_lut40: co-running 40 MHz LUT configuration - * @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk - * - * The structure is used for the BT_COEX command. - */ -struct iwl_bt_coex_cmd_old { - __le32 flags; - u8 max_kill; - u8 bt_reduced_tx_power; - u8 override_primary_lut; - u8 override_secondary_lut; - - u8 bt4_antenna_isolation; - u8 bt4_antenna_isolation_thr; - u8 bt4_tx_tx_delta_freq_thr; - u8 bt4_tx_rx_max_freq0; - - __le32 bt_prio_boost[BT_COEX_BOOST_SIZE]; - __le32 wifi_tx_prio_boost; - __le32 wifi_rx_prio_boost; - __le32 kill_ack_msk; - __le32 kill_cts_msk; - - __le32 decision_lut[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE]; - __le32 bt4_multiprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE]; - __le32 bt4_corun_lut20[BT_COEX_CORUN_LUT_SIZE]; - __le32 bt4_corun_lut40[BT_COEX_CORUN_LUT_SIZE]; - - __le32 valid_bit_msk; -} __packed; /* BT_COEX_CMD_API_S_VER_5 */ - enum iwl_bt_coex_mode { BT_COEX_DISABLE = 0x0, BT_COEX_NW = 0x1, @@ -385,92 +251,4 @@ struct iwl_bt_coex_profile_notif { u8 reserved[3]; } __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_4 */ -enum iwl_bt_coex_prio_table_event { - BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0, - BT_COEX_PRIO_TBL_EVT_INIT_CALIB2 = 1, - BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1 = 2, - BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2 = 3, - BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1 = 4, - BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2 = 5, - BT_COEX_PRIO_TBL_EVT_DTIM = 6, - BT_COEX_PRIO_TBL_EVT_SCAN52 = 7, - BT_COEX_PRIO_TBL_EVT_SCAN24 = 8, - BT_COEX_PRIO_TBL_EVT_IDLE = 9, - BT_COEX_PRIO_TBL_EVT_MAX = 16, -}; /* BT_COEX_PRIO_TABLE_EVENTS_API_E_VER_1 */ - -enum iwl_bt_coex_prio_table_prio { - BT_COEX_PRIO_TBL_DISABLED = 0, - BT_COEX_PRIO_TBL_PRIO_LOW = 1, - BT_COEX_PRIO_TBL_PRIO_HIGH = 2, - BT_COEX_PRIO_TBL_PRIO_BYPASS = 3, - BT_COEX_PRIO_TBL_PRIO_COEX_OFF = 4, - BT_COEX_PRIO_TBL_PRIO_COEX_ON = 5, - BT_COEX_PRIO_TBL_PRIO_COEX_IDLE = 6, - BT_COEX_PRIO_TBL_MAX = 8, -}; /* BT_COEX_PRIO_TABLE_PRIORITIES_API_E_VER_1 */ - -#define BT_COEX_PRIO_TBL_SHRD_ANT_POS (0) -#define BT_COEX_PRIO_TBL_PRIO_POS (1) -#define BT_COEX_PRIO_TBL_RESERVED_POS (4) - -/** - * struct iwl_bt_coex_prio_tbl_cmd - priority table for BT coex - * @prio_tbl: - */ -struct iwl_bt_coex_prio_tbl_cmd { - u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX]; -} __packed; - -/** - * struct iwl_bt_coex_ci_cmd_old - bt coex channel inhibition command - * @bt_primary_ci: - * @bt_secondary_ci: - * @co_run_bw_primary: - * @co_run_bw_secondary: - * @primary_ch_phy_id: - * @secondary_ch_phy_id: - * - * Used for BT_COEX_CI command - */ -struct iwl_bt_coex_ci_cmd_old { - __le64 bt_primary_ci; - __le64 bt_secondary_ci; - - u8 co_run_bw_primary; - u8 co_run_bw_secondary; - u8 primary_ch_phy_id; - u8 secondary_ch_phy_id; -} __packed; /* BT_CI_MSG_API_S_VER_1 */ - -/** - * struct iwl_bt_coex_profile_notif_old - notification about BT coex - * @mbox_msg: message from BT to WiFi - * @msg_idx: the index of the message - * @bt_status: 0 - off, 1 - on - * @bt_open_conn: number of BT connections open - * @bt_traffic_load: load of BT traffic - * @bt_agg_traffic_load: aggregated load of BT traffic - * @bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant - * @primary_ch_lut: LUT used for primary channel - * @secondary_ch_lut: LUT used for secondary channel - * @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading - */ -struct iwl_bt_coex_profile_notif_old { - __le32 mbox_msg[4]; - __le32 msg_idx; - u8 bt_status; - u8 bt_open_conn; - u8 bt_traffic_load; - u8 bt_agg_traffic_load; - u8 bt_ci_compliance; - u8 ttc_enabled; - u8 rrc_enabled; - u8 reserved; - - __le32 primary_ch_lut; - __le32 secondary_ch_lut; - __le32 bt_activity_grading; -} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_3 */ - #endif /* __fw_api_bt_coex_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h index 95ac59d088b1..0246506ab595 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h @@ -72,6 +72,9 @@ #define NUM_MAC_INDEX_DRIVER MAC_INDEX_AUX #define NUM_MAC_INDEX (MAC_INDEX_AUX + 1) +#define IWL_MVM_STATION_COUNT 16 +#define IWL_MVM_TDLS_STA_COUNT 4 + enum iwl_ac { AC_BK, AC_BE, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h index 65a7c8a4cacf..404b0de9e2dc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -310,7 +310,8 @@ enum iwl_dev_tx_power_cmd_mode { IWL_TX_POWER_MODE_SET_MAC = 0, IWL_TX_POWER_MODE_SET_DEVICE = 1, IWL_TX_POWER_MODE_SET_CHAINS = 2, -}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_2 */; + IWL_TX_POWER_MODE_SET_ACK = 3, +}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_4 */; /** * struct iwl_dev_tx_power_cmd_v2 - TX power reduction command @@ -338,7 +339,7 @@ struct iwl_dev_tx_power_cmd_v2 { * @v2: version 2 of the command, embedded here for easier software handling * @per_chain_restriction: per chain restrictions */ -struct iwl_dev_tx_power_cmd { +struct iwl_dev_tx_power_cmd_v3 { /* v3 is just an extension of v2 - keep this here */ struct iwl_dev_tx_power_cmd_v2 v2; __le16 per_chain_restriction[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS]; @@ -347,6 +348,19 @@ struct iwl_dev_tx_power_cmd { #define IWL_DEV_MAX_TX_POWER 0x7FFF /** + * struct iwl_dev_tx_power_cmd - TX power reduction command + * @v3: version 3 of the command, embedded here for easier software handling + * @enable_ack_reduction: enable or disable close range ack TX power + * reduction. + */ +struct iwl_dev_tx_power_cmd { + /* v4 is just an extension of v3 - keep this here */ + struct iwl_dev_tx_power_cmd_v3 v3; + u8 enable_ack_reduction; + u8 reserved[3]; +} __packed; /* TX_REDUCED_POWER_API_S_VER_4 */ + +/** * struct iwl_beacon_filter_cmd * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) * @id_and_color: MAC contex identifier diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index 1ca8e4988b88..acc5cd53e4ba 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -296,7 +296,7 @@ enum iwl_rx_mpdu_status { IWL_RX_MPDU_STATUS_OVERRUN_OK = BIT(1), IWL_RX_MPDU_STATUS_SRC_STA_FOUND = BIT(2), IWL_RX_MPDU_STATUS_KEY_VALID = BIT(3), - IWL_RX_MPDU_STATUS_KEY_ERROR = BIT(4), + IWL_RX_MPDU_STATUS_KEY_PARAM_OK = BIT(4), IWL_RX_MPDU_STATUS_ICV_OK = BIT(5), IWL_RX_MPDU_STATUS_MIC_OK = BIT(6), IWL_RX_MPDU_RES_STATUS_TTAK_OK = BIT(7), @@ -311,7 +311,7 @@ enum iwl_rx_mpdu_status { IWL_RX_MPDU_STATUS_WEP_MATCH = BIT(12), IWL_RX_MPDU_STATUS_EXT_IV_MATCH = BIT(13), IWL_RX_MPDU_STATUS_KEY_ID_MATCH = BIT(14), - IWL_RX_MPDU_STATUS_KEY_COLOR = BIT(15), + IWL_RX_MPDU_STATUS_ROBUST_MNG_FRAME = BIT(15), }; enum iwl_rx_mpdu_hash_filter { @@ -336,6 +336,18 @@ enum iwl_rx_mpdu_reorder_data { IWL_RX_MPDU_REORDER_BA_OLD_SN = 0x80000000, }; +enum iwl_rx_mpdu_phy_info { + IWL_RX_MPDU_PHY_AMPDU = BIT(5), + IWL_RX_MPDU_PHY_AMPDU_TOGGLE = BIT(6), + IWL_RX_MPDU_PHY_SHORT_PREAMBLE = BIT(7), + IWL_RX_MPDU_PHY_TSF_OVERLOAD = BIT(8), +}; + +enum iwl_rx_mpdu_mac_info { + IWL_RX_MPDU_PHY_MAC_INDEX_MASK = 0x0f, + IWL_RX_MPDU_PHY_PHY_INDEX_MASK = 0xf0, +}; + struct iwl_rx_mpdu_desc { /* DW2 */ __le16 mpdu_len; @@ -343,9 +355,9 @@ struct iwl_rx_mpdu_desc { u8 mac_flags2; /* DW3 */ u8 amsdu_info; - __le16 reserved_for_software; + __le16 phy_info; u8 mac_phy_idx; - /* DW4 */ + /* DW4 - carries csum data only when rpa_en == 1 */ __le16 raw_csum; /* alledgedly unreliable */ __le16 l3l4_flags; /* DW5 */ @@ -354,17 +366,17 @@ struct iwl_rx_mpdu_desc { u8 sta_id_flags; /* DW6 */ __le32 reorder_data; - /* DW7 */ + /* DW7 - carries rss_hash only when rpa_en == 1 */ __le32 rss_hash; - /* DW8 */ + /* DW8 - carries filter_match only when rpa_en == 1 */ __le32 filter_match; /* DW9 */ __le32 rate_n_flags; /* DW10 */ - u8 energy_a, energy_b, channel, reserved; + u8 energy_a, energy_b, channel, mac_context; /* DW11 */ __le32 gp2_on_air_rise; - /* DW12 & DW13 */ + /* DW12 & DW13 - carries TSF only TSF_OVERLOAD bit == 0 */ __le64 tsf_on_air_rise; } __packed; @@ -435,26 +447,26 @@ struct iwl_rxq_sync_notification { } __packed; /* MULTI_QUEUE_DRV_SYNC_HDR_CMD_API_S_VER_1 */ /** -* Internal message identifier -* -* @IWL_MVM_RXQ_EMPTY: empty sync notification -* @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA -*/ + * Internal message identifier + * + * @IWL_MVM_RXQ_EMPTY: empty sync notification + * @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA + */ enum iwl_mvm_rxq_notif_type { IWL_MVM_RXQ_EMPTY, IWL_MVM_RXQ_NOTIF_DEL_BA, }; /** -* struct iwl_mvm_internal_rxq_notif - Internal representation of the data sent -* in &iwl_rxq_sync_cmd. Should be DWORD aligned. -* FW is agnostic to the payload, so there are no endianity requirements. -* -* @type: value from &iwl_mvm_rxq_notif_type -* @sync: ctrl path is waiting for all notifications to be received -* @cookie: internal cookie to identify old notifications -* @data: payload -*/ + * struct iwl_mvm_internal_rxq_notif - Internal representation of the data sent + * in &iwl_rxq_sync_cmd. Should be DWORD aligned. + * FW is agnostic to the payload, so there are no endianity requirements. + * + * @type: value from &iwl_mvm_rxq_notif_type + * @sync: ctrl path is waiting for all notifications to be received + * @cookie: internal cookie to identify old notifications + * @data: payload + */ struct iwl_mvm_internal_rxq_notif { u16 type; u16 sync; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index 38b1d045be8e..d1c4fb849111 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -141,6 +141,7 @@ enum iwl_sta_flags { * @STA_KEY_FLG_CCM: CCMP encryption algorithm * @STA_KEY_FLG_TKIP: TKIP encryption algorithm * @STA_KEY_FLG_EXT: extended cipher algorithm (depends on the FW support) + * @STA_KEY_FLG_GCMP: GCMP encryption algorithm * @STA_KEY_FLG_CMAC: CMAC encryption algorithm * @STA_KEY_FLG_ENC_UNKNOWN: unknown encryption algorithm * @STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value @@ -149,6 +150,7 @@ enum iwl_sta_flags { * @STA_KEY_FLG_KEYID_MSK: the index of the key * @STA_KEY_NOT_VALID: key is invalid * @STA_KEY_FLG_WEP_13BYTES: set for 13 bytes WEP key + * @STA_KEY_FLG_KEY_32BYTES for non-wep key set for 32 bytes key * @STA_KEY_MULTICAST: set for multical key * @STA_KEY_MFP: key is used for Management Frame Protection */ @@ -158,6 +160,7 @@ enum iwl_sta_key_flag { STA_KEY_FLG_CCM = (2 << 0), STA_KEY_FLG_TKIP = (3 << 0), STA_KEY_FLG_EXT = (4 << 0), + STA_KEY_FLG_GCMP = (5 << 0), STA_KEY_FLG_CMAC = (6 << 0), STA_KEY_FLG_ENC_UNKNOWN = (7 << 0), STA_KEY_FLG_EN_MSK = (7 << 0), @@ -167,6 +170,7 @@ enum iwl_sta_key_flag { STA_KEY_FLG_KEYID_MSK = (3 << STA_KEY_FLG_KEYID_POS), STA_KEY_NOT_VALID = BIT(11), STA_KEY_FLG_WEP_13BYTES = BIT(12), + STA_KEY_FLG_KEY_32BYTES = BIT(12), STA_KEY_MULTICAST = BIT(14), STA_KEY_MFP = BIT(15), }; @@ -388,7 +392,6 @@ struct iwl_mvm_add_sta_cmd { * @key_offset: key offset in key storage * @key_flags: type %iwl_sta_key_flag * @key: key material data - * @key2: key material data * @rx_secur_seq_cnt: RX security sequence counter for the key * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx @@ -397,8 +400,7 @@ struct iwl_mvm_add_sta_key_cmd { u8 sta_id; u8 key_offset; __le16 key_flags; - u8 key[16]; - u8 key2[16]; + u8 key[32]; u8 rx_secur_seq_cnt[16]; u8 tkip_rx_tsc_byte2; u8 reserved; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h index 438665a54923..4e638a44babb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -252,6 +253,20 @@ struct mvm_statistics_general_v8 { u8 reserved[4 - (NUM_MAC_INDEX % 4)]; } __packed; /* STATISTICS_GENERAL_API_S_VER_8 */ +/** + * struct mvm_statistics_load - RX statistics for multi-queue devices + * @air_time: accumulated air time, per mac + * @byte_count: accumulated byte count, per mac + * @pkt_count: accumulated packet count, per mac + * @avg_energy: average RSSI, per station + */ +struct mvm_statistics_load { + __le32 air_time[NUM_MAC_INDEX]; + __le32 byte_count[NUM_MAC_INDEX]; + __le32 pkt_count[NUM_MAC_INDEX]; + u8 avg_energy[IWL_MVM_STATION_COUNT]; +} __packed; /* STATISTICS_RX_MAC_STATION_S_VER_1 */ + struct mvm_statistics_rx { struct mvm_statistics_rx_phy ofdm; struct mvm_statistics_rx_phy cck; @@ -266,7 +281,6 @@ struct mvm_statistics_rx { * while associated. To disable this behavior, set DISABLE_NOTIF flag in the * STATISTICS_CMD (0x9c), below. */ - struct iwl_notif_statistics_v10 { __le32 flag; struct mvm_statistics_rx rx; @@ -274,6 +288,14 @@ struct iwl_notif_statistics_v10 { struct mvm_statistics_general_v8 general; } __packed; /* STATISTICS_NTFY_API_S_VER_10 */ +struct iwl_notif_statistics_v11 { + __le32 flag; + struct mvm_statistics_rx rx; + struct mvm_statistics_tx tx; + struct mvm_statistics_general_v8 general; + struct mvm_statistics_load load_stats; +} __packed; /* STATISTICS_NTFY_API_S_VER_11 */ + #define IWL_STATISTICS_FLG_CLEAR 0x1 #define IWL_STATISTICS_FLG_DISABLE_NOTIF 0x2 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index dadcccd88255..4144623e1616 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -137,17 +137,32 @@ enum iwl_tx_pm_timeouts { PM_FRAME_ASSOC = 3, }; -/* - * TX command security control - */ -#define TX_CMD_SEC_WEP 0x01 -#define TX_CMD_SEC_CCM 0x02 -#define TX_CMD_SEC_TKIP 0x03 -#define TX_CMD_SEC_EXT 0x04 #define TX_CMD_SEC_MSK 0x07 #define TX_CMD_SEC_WEP_KEY_IDX_POS 6 #define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0 -#define TX_CMD_SEC_KEY128 0x08 + +/** + * enum iwl_tx_cmd_sec_ctrl - bitmasks for security control in TX command + * @TX_CMD_SEC_WEP: WEP encryption algorithm. + * @TX_CMD_SEC_CCM: CCM encryption algorithm. + * @TX_CMD_SEC_TKIP: TKIP encryption algorithm. + * @TX_CMD_SEC_EXT: extended cipher algorithm. + * @TX_CMD_SEC_GCMP: GCMP encryption algorithm. + * @TX_CMD_SEC_KEY128: set for 104 bits WEP key. + * @TC_CMD_SEC_KEY_FROM_TABLE: for a non-WEP key, set if the key should be taken + * from the table instead of from the TX command. + * If the key is taken from the key table its index should be given by the + * first byte of the TX command key field. + */ +enum iwl_tx_cmd_sec_ctrl { + TX_CMD_SEC_WEP = 0x01, + TX_CMD_SEC_CCM = 0x02, + TX_CMD_SEC_TKIP = 0x03, + TX_CMD_SEC_EXT = 0x04, + TX_CMD_SEC_GCMP = 0x05, + TX_CMD_SEC_KEY128 = 0x08, + TC_CMD_SEC_KEY_FROM_TABLE = 0x08, +}; /* TODO: how does these values are OK with only 16 bit variable??? */ /* @@ -562,8 +577,8 @@ struct iwl_mvm_ba_notif { u8 reserved1; } __packed; -/* - * struct iwl_mac_beacon_cmd - beacon template command +/** + * struct iwl_mac_beacon_cmd_v6 - beacon template command * @tx: the tx commands associated with the beacon frame * @template_id: currently equal to the mac context id of the coresponding * mac. @@ -571,13 +586,34 @@ struct iwl_mvm_ba_notif { * @tim_size: the length of the tim IE * @frame: the template of the beacon frame */ +struct iwl_mac_beacon_cmd_v6 { + struct iwl_tx_cmd tx; + __le32 template_id; + __le32 tim_idx; + __le32 tim_size; + struct ieee80211_hdr frame[0]; +} __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_6 */ + +/** + * struct iwl_mac_beacon_cmd - beacon template command with offloaded CSA + * @tx: the tx commands associated with the beacon frame + * @template_id: currently equal to the mac context id of the coresponding + * mac. + * @tim_idx: the offset of the tim IE in the beacon + * @tim_size: the length of the tim IE + * @ecsa_offset: offset to the ECSA IE if present + * @csa_offset: offset to the CSA IE if present + * @frame: the template of the beacon frame + */ struct iwl_mac_beacon_cmd { struct iwl_tx_cmd tx; __le32 template_id; __le32 tim_idx; __le32 tim_size; + __le32 ecsa_offset; + __le32 csa_offset; struct ieee80211_hdr frame[0]; -} __packed; +} __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_7 */ struct iwl_beacon_notif { struct iwl_mvm_tx_resp beacon_notify_hdr; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 41b80ae2d5f8..71076f02796e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -90,6 +90,7 @@ enum { * DQA queue numbers * * @IWL_MVM_DQA_CMD_QUEUE: a queue reserved for sending HCMDs to the FW + * @IWL_MVM_DQA_AUX_QUEUE: a queue reserved for aux frames * @IWL_MVM_DQA_P2P_DEVICE_QUEUE: a queue reserved for P2P device frames * @IWL_MVM_DQA_GCAST_QUEUE: a queue reserved for P2P GO/SoftAP GCAST frames * @IWL_MVM_DQA_BSS_CLIENT_QUEUE: a queue reserved for BSS activity, to ensure @@ -108,6 +109,7 @@ enum { */ enum iwl_mvm_dqa_txq { IWL_MVM_DQA_CMD_QUEUE = 0, + IWL_MVM_DQA_AUX_QUEUE = 1, IWL_MVM_DQA_P2P_DEVICE_QUEUE = 2, IWL_MVM_DQA_GCAST_QUEUE = 3, IWL_MVM_DQA_BSS_CLIENT_QUEUE = 4, @@ -127,9 +129,6 @@ enum iwl_mvm_tx_fifo { IWL_MVM_TX_FIFO_CMD = 7, }; -#define IWL_MVM_STATION_COUNT 16 - -#define IWL_MVM_TDLS_STA_COUNT 4 /* commands */ enum { @@ -314,6 +313,7 @@ enum { enum iwl_mac_conf_subcmd_ids { LINK_QUALITY_MEASUREMENT_CMD = 0x1, LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF = 0xFE, + CHANNEL_SWITCH_NOA_NOTIF = 0xFF, }; enum iwl_phy_ops_subcmd_ids { @@ -329,6 +329,7 @@ enum iwl_system_subcmd_ids { }; enum iwl_data_path_subcmd_ids { + DQA_ENABLE_CMD = 0x0, UPDATE_MU_GROUPS_CMD = 0x1, TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2, MU_GROUP_MGMT_NOTIF = 0xFE, @@ -359,6 +360,14 @@ struct iwl_cmd_response { }; /* + * struct iwl_dqa_enable_cmd + * @cmd_queue: the TXQ number of the command queue + */ +struct iwl_dqa_enable_cmd { + __le32 cmd_queue; +} __packed; /* DQA_CONTROL_CMD_API_S_VER_1 */ + +/* * struct iwl_tx_ant_cfg_cmd * @valid: valid antenna configuration */ @@ -732,7 +741,7 @@ enum iwl_time_event_type { /* P2P GO Events */ TE_P2P_GO_ASSOC_PROT, - TE_P2P_GO_REPETITIVE_NOA, + TE_P2P_GO_REPETITIVET_NOA, TE_P2P_GO_CT_WINDOW, /* WiDi Sync Events */ @@ -2111,4 +2120,13 @@ struct iwl_link_qual_msrmnt_notif { __le32 reserved[3]; } __packed; /* LQM_MEASUREMENT_COMPLETE_NTF_API_S_VER1 */ +/** + * Channel switch NOA notification + * + * @id_and_color: ID and color of the MAC + */ +struct iwl_channel_switch_noa_notif { + __le32 id_and_color; +} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */ + #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index e1b6b2c665eb..1abcabb9b6cd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -288,7 +288,8 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, fifo_hdr->fifo_num = cpu_to_le32(i); /* Mark the number of TXF we're pulling now */ - iwl_trans_write_prph(mvm->trans, TXF_CPU2_NUM, i); + iwl_trans_write_prph(mvm->trans, TXF_CPU2_NUM, i + + ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size)); fifo_hdr->available_bytes = cpu_to_le32(iwl_trans_read_prph(mvm->trans, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 7057f35cb2e7..7e0cdbf8bf74 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -65,6 +65,7 @@ *****************************************************************************/ #include <net/mac80211.h> #include <linux/netdevice.h> +#include <linux/acpi.h> #include "iwl-trans.h" #include "iwl-op-mode.h" @@ -122,6 +123,9 @@ static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm) IWL_RSS_HASH_TYPE_IPV6_PAYLOAD, }; + if (mvm->trans->num_rx_queues == 1) + return 0; + /* Do not direct RSS traffic to Q 0 which is our fallback queue */ for (i = 0; i < ARRAY_SIZE(cmd.indirection_table); i++) cmd.indirection_table[i] = @@ -131,6 +135,23 @@ static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm) return iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd); } +static int iwl_mvm_send_dqa_cmd(struct iwl_mvm *mvm) +{ + struct iwl_dqa_enable_cmd dqa_cmd = { + .cmd_queue = cpu_to_le32(IWL_MVM_DQA_CMD_QUEUE), + }; + u32 cmd_id = iwl_cmd_id(DQA_ENABLE_CMD, DATA_PATH_GROUP, 0); + int ret; + + ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(dqa_cmd), &dqa_cmd); + if (ret) + IWL_ERR(mvm, "Failed to send DQA enabling command: %d\n", ret); + else + IWL_DEBUG_FW(mvm, "Working in DQA mode\n"); + + return ret; +} + void iwl_free_fw_paging(struct iwl_mvm *mvm) { int i; @@ -139,17 +160,21 @@ void iwl_free_fw_paging(struct iwl_mvm *mvm) return; for (i = 0; i < NUM_OF_FW_PAGING_BLOCKS; i++) { - if (!mvm->fw_paging_db[i].fw_paging_block) { + struct iwl_fw_paging *paging = &mvm->fw_paging_db[i]; + + if (!paging->fw_paging_block) { IWL_DEBUG_FW(mvm, "Paging: block %d already freed, continue to next page\n", i); continue; } + dma_unmap_page(mvm->trans->dev, paging->fw_paging_phys, + paging->fw_paging_size, DMA_BIDIRECTIONAL); - __free_pages(mvm->fw_paging_db[i].fw_paging_block, - get_order(mvm->fw_paging_db[i].fw_paging_size)); - mvm->fw_paging_db[i].fw_paging_block = NULL; + __free_pages(paging->fw_paging_block, + get_order(paging->fw_paging_size)); + paging->fw_paging_block = NULL; } kfree(mvm->trans->paging_download_buf); mvm->trans->paging_download_buf = NULL; @@ -882,6 +907,177 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) sizeof(cmd), &cmd); } +#define ACPI_WRDS_METHOD "WRDS" +#define ACPI_WRDS_WIFI (0x07) +#define ACPI_WRDS_TABLE_SIZE 10 + +struct iwl_mvm_sar_table { + bool enabled; + u8 values[ACPI_WRDS_TABLE_SIZE]; +}; + +#ifdef CONFIG_ACPI +static int iwl_mvm_sar_get_wrds(struct iwl_mvm *mvm, union acpi_object *wrds, + struct iwl_mvm_sar_table *sar_table) +{ + union acpi_object *data_pkg; + u32 i; + + /* We need at least two packages, one for the revision and one + * for the data itself. Also check that the revision is valid + * (i.e. it is an integer set to 0). + */ + if (wrds->type != ACPI_TYPE_PACKAGE || + wrds->package.count < 2 || + wrds->package.elements[0].type != ACPI_TYPE_INTEGER || + wrds->package.elements[0].integer.value != 0) { + IWL_DEBUG_RADIO(mvm, "Unsupported wrds structure\n"); + return -EINVAL; + } + + /* loop through all the packages to find the one for WiFi */ + for (i = 1; i < wrds->package.count; i++) { + union acpi_object *domain; + + data_pkg = &wrds->package.elements[i]; + + /* Skip anything that is not a package with the right + * amount of elements (i.e. domain_type, + * enabled/disabled plus the sar table size. + */ + if (data_pkg->type != ACPI_TYPE_PACKAGE || + data_pkg->package.count != ACPI_WRDS_TABLE_SIZE + 2) + continue; + + domain = &data_pkg->package.elements[0]; + if (domain->type == ACPI_TYPE_INTEGER && + domain->integer.value == ACPI_WRDS_WIFI) + break; + + data_pkg = NULL; + } + + if (!data_pkg) + return -ENOENT; + + if (data_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) + return -EINVAL; + + sar_table->enabled = !!(data_pkg->package.elements[1].integer.value); + + for (i = 0; i < ACPI_WRDS_TABLE_SIZE; i++) { + union acpi_object *entry; + + entry = &data_pkg->package.elements[i + 2]; + if ((entry->type != ACPI_TYPE_INTEGER) || + (entry->integer.value > U8_MAX)) + return -EINVAL; + + sar_table->values[i] = entry->integer.value; + } + + return 0; +} + +static int iwl_mvm_sar_get_table(struct iwl_mvm *mvm, + struct iwl_mvm_sar_table *sar_table) +{ + acpi_handle root_handle; + acpi_handle handle; + struct acpi_buffer wrds = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_status status; + int ret; + + root_handle = ACPI_HANDLE(mvm->dev); + if (!root_handle) { + IWL_DEBUG_RADIO(mvm, + "Could not retrieve root port ACPI handle\n"); + return -ENOENT; + } + + /* Get the method's handle */ + status = acpi_get_handle(root_handle, (acpi_string)ACPI_WRDS_METHOD, + &handle); + if (ACPI_FAILURE(status)) { + IWL_DEBUG_RADIO(mvm, "WRDS method not found\n"); + return -ENOENT; + } + + /* Call WRDS with no arguments */ + status = acpi_evaluate_object(handle, NULL, NULL, &wrds); + if (ACPI_FAILURE(status)) { + IWL_DEBUG_RADIO(mvm, "WRDS invocation failed (0x%x)\n", status); + return -ENOENT; + } + + ret = iwl_mvm_sar_get_wrds(mvm, wrds.pointer, sar_table); + kfree(wrds.pointer); + + return ret; +} +#else /* CONFIG_ACPI */ +static int iwl_mvm_sar_get_table(struct iwl_mvm *mvm, + struct iwl_mvm_sar_table *sar_table) +{ + return -ENOENT; +} +#endif /* CONFIG_ACPI */ + +static int iwl_mvm_sar_init(struct iwl_mvm *mvm) +{ + struct iwl_mvm_sar_table sar_table; + struct iwl_dev_tx_power_cmd cmd = { + .v3.v2.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS), + }; + int ret, i, j, idx; + int len = sizeof(cmd); + + /* we can't do anything with the table if the FW doesn't support it */ + if (!fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_TX_POWER_CHAIN)) { + IWL_DEBUG_RADIO(mvm, + "FW doesn't support per-chain TX power settings.\n"); + return 0; + } + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) + len = sizeof(cmd.v3); + + ret = iwl_mvm_sar_get_table(mvm, &sar_table); + if (ret < 0) { + IWL_DEBUG_RADIO(mvm, + "SAR BIOS table invalid or unavailable. (%d)\n", + ret); + /* we don't fail if the table is not available */ + return 0; + } + + if (!sar_table.enabled) + return 0; + + IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n"); + + BUILD_BUG_ON(IWL_NUM_CHAIN_LIMITS * IWL_NUM_SUB_BANDS != + ACPI_WRDS_TABLE_SIZE); + + for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { + IWL_DEBUG_RADIO(mvm, " Chain[%d]:\n", i); + for (j = 0; j < IWL_NUM_SUB_BANDS; j++) { + idx = (i * IWL_NUM_SUB_BANDS) + j; + cmd.v3.per_chain_restriction[i][j] = + cpu_to_le16(sar_table.values[idx]); + IWL_DEBUG_RADIO(mvm, " Band[%d] = %d * .125dBm\n", + j, sar_table.values[idx]); + } + } + + ret = iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); + if (ret) + IWL_ERR(mvm, "failed to set per-chain TX power: %d\n", ret); + + return ret; +} + int iwl_mvm_up(struct iwl_mvm *mvm) { int ret, i; @@ -976,6 +1172,15 @@ int iwl_mvm_up(struct iwl_mvm *mvm) /* reset quota debouncing buffer - 0xff will yield invalid data */ memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); + /* Enable DQA-mode if required */ + if (iwl_mvm_is_dqa_supported(mvm)) { + ret = iwl_mvm_send_dqa_cmd(mvm); + if (ret) + goto error; + } else { + IWL_DEBUG_FW(mvm, "Working in non-DQA mode\n"); + } + /* Add auxiliary station for scanning */ ret = iwl_mvm_add_aux_sta(mvm); if (ret) @@ -1048,6 +1253,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); + ret = iwl_mvm_sar_init(mvm); + if (ret) + goto error; + IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); return 0; error: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 7aae068c02e5..69c42ce45b8a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1006,7 +1006,7 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm, } static void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm, - struct iwl_mac_beacon_cmd *beacon_cmd, + struct iwl_mac_beacon_cmd_v6 *beacon_cmd, u8 *beacon, u32 frame_size) { u32 tim_idx; @@ -1030,6 +1030,23 @@ static void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm, } } +static u32 iwl_mvm_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size) +{ + struct ieee80211_mgmt *mgmt = (void *)beacon; + const u8 *ie; + + if (WARN_ON_ONCE(frame_size <= (mgmt->u.beacon.variable - beacon))) + return 0; + + frame_size -= mgmt->u.beacon.variable - beacon; + + ie = cfg80211_find_ie(eid, mgmt->u.beacon.variable, frame_size); + if (!ie) + return 0; + + return ie - beacon; +} + static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct sk_buff *beacon) @@ -1039,7 +1056,10 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, .id = BEACON_TEMPLATE_CMD, .flags = CMD_ASYNC, }; - struct iwl_mac_beacon_cmd beacon_cmd = {}; + union { + struct iwl_mac_beacon_cmd_v6 beacon_cmd_v6; + struct iwl_mac_beacon_cmd beacon_cmd; + } u = {}; struct ieee80211_tx_info *info; u32 beacon_skb_len; u32 rate, tx_flags; @@ -1051,18 +1071,18 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, /* TODO: for now the beacon template id is set to be the mac context id. * Might be better to handle it as another resource ... */ - beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id); + u.beacon_cmd_v6.template_id = cpu_to_le32((u32)mvmvif->id); info = IEEE80211_SKB_CB(beacon); /* Set up TX command fields */ - beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len); - beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id; - beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); + u.beacon_cmd_v6.tx.len = cpu_to_le16((u16)beacon_skb_len); + u.beacon_cmd_v6.tx.sta_id = mvmvif->bcast_sta.sta_id; + u.beacon_cmd_v6.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF; tx_flags |= iwl_mvm_bt_coex_tx_prio(mvm, (void *)beacon->data, info, 0) << TX_CMD_FLG_BT_PRIO_POS; - beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags); + u.beacon_cmd_v6.tx.tx_flags = cpu_to_le32(tx_flags); if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION)) { @@ -1071,7 +1091,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, mvm->mgmt_last_antenna_idx); } - beacon_cmd.tx.rate_n_flags = + u.beacon_cmd_v6.tx.rate_n_flags = cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS); @@ -1079,20 +1099,37 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, rate = IWL_FIRST_OFDM_RATE; } else { rate = IWL_FIRST_CCK_RATE; - beacon_cmd.tx.rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK); + u.beacon_cmd_v6.tx.rate_n_flags |= + cpu_to_le32(RATE_MCS_CCK_MSK); } - beacon_cmd.tx.rate_n_flags |= + u.beacon_cmd_v6.tx.rate_n_flags |= cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(rate)); /* Set up TX beacon command fields */ if (vif->type == NL80211_IFTYPE_AP) - iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd, + iwl_mvm_mac_ctxt_set_tim(mvm, &u.beacon_cmd_v6, beacon->data, beacon_skb_len); /* Submit command */ - cmd.len[0] = sizeof(beacon_cmd); - cmd.data[0] = &beacon_cmd; + + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD)) { + u.beacon_cmd.csa_offset = + cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data, + WLAN_EID_CHANNEL_SWITCH, + beacon_skb_len)); + u.beacon_cmd.ecsa_offset = + cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data, + WLAN_EID_EXT_CHANSWITCH_ANN, + beacon_skb_len)); + + cmd.len[0] = sizeof(u.beacon_cmd); + } else { + cmd.len[0] = sizeof(u.beacon_cmd_v6); + } + + cmd.data[0] = &u; cmd.dataflags[0] = 0; cmd.len[1] = beacon_skb_len; cmd.data[1] = beacon->data; @@ -1538,3 +1575,48 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, /* pass it as regular rx to mac80211 */ ieee80211_rx_napi(mvm->hw, NULL, skb, NULL); } + +void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_channel_switch_noa_notif *notif = (void *)pkt->data; + struct ieee80211_vif *csa_vif; + struct iwl_mvm_vif *mvmvif; + int len = iwl_rx_packet_payload_len(pkt); + u32 id_n_color; + + if (WARN_ON_ONCE(len < sizeof(*notif))) + return; + + rcu_read_lock(); + + csa_vif = rcu_dereference(mvm->csa_vif); + if (WARN_ON(!csa_vif || !csa_vif->csa_active)) + goto out_unlock; + + id_n_color = le32_to_cpu(notif->id_and_color); + + mvmvif = iwl_mvm_vif_from_mac80211(csa_vif); + if (WARN(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color) != id_n_color, + "channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)", + FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color), id_n_color)) + goto out_unlock; + + IWL_DEBUG_INFO(mvm, "Channel Switch Started Notification\n"); + + queue_delayed_work(system_wq, &mvm->cs_tx_unblock_dwork, + msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT * + csa_vif->bss_conf.beacon_int)); + + ieee80211_csa_finish(csa_vif); + + rcu_read_unlock(); + + RCU_INIT_POINTER(mvm->csa_vif, NULL); + + return; + +out_unlock: + rcu_read_unlock(); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 18a8474b5760..6d6064534d59 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -465,11 +465,20 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; - BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 2); + BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 4); memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers)); hw->wiphy->n_cipher_suites = ARRAY_SIZE(mvm_ciphers); hw->wiphy->cipher_suites = mvm->ciphers; + if (iwl_mvm_has_new_rx_api(mvm)) { + mvm->ciphers[hw->wiphy->n_cipher_suites] = + WLAN_CIPHER_SUITE_GCMP; + hw->wiphy->n_cipher_suites++; + mvm->ciphers[hw->wiphy->n_cipher_suites] = + WLAN_CIPHER_SUITE_GCMP_256; + hw->wiphy->n_cipher_suites++; + } + /* * Enable 11w if advertised by firmware and software crypto * is not enabled (as the firmware will interpret some mgmt @@ -485,10 +494,23 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) /* currently FW API supports only one optional cipher scheme */ if (mvm->fw->cs[0].cipher) { + const struct iwl_fw_cipher_scheme *fwcs = &mvm->fw->cs[0]; + struct ieee80211_cipher_scheme *cs = &mvm->cs[0]; + mvm->hw->n_cipher_schemes = 1; - mvm->hw->cipher_schemes = &mvm->fw->cs[0]; - mvm->ciphers[hw->wiphy->n_cipher_suites] = - mvm->fw->cs[0].cipher; + + cs->cipher = le32_to_cpu(fwcs->cipher); + cs->iftype = BIT(NL80211_IFTYPE_STATION); + cs->hdr_len = fwcs->hdr_len; + cs->pn_len = fwcs->pn_len; + cs->pn_off = fwcs->pn_off; + cs->key_idx_off = fwcs->key_idx_off; + cs->key_idx_mask = fwcs->key_idx_mask; + cs->key_idx_shift = fwcs->key_idx_shift; + cs->mic_len = fwcs->mic_len; + + mvm->hw->cipher_schemes = mvm->cs; + mvm->ciphers[hw->wiphy->n_cipher_suites] = cs->cipher; hw->wiphy->n_cipher_suites++; } @@ -1011,11 +1033,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) memset(mvm->sta_deferred_frames, 0, sizeof(mvm->sta_deferred_frames)); memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_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); @@ -1199,6 +1217,8 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) flush_work(&mvm->async_handlers_wk); flush_work(&mvm->add_stream_wk); cancel_delayed_work_sync(&mvm->fw_dump_wk); + cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork); + cancel_delayed_work_sync(&mvm->scan_timeout_dwork); iwl_mvm_free_fw_dump_desc(mvm); mutex_lock(&mvm->mutex); @@ -1230,18 +1250,20 @@ static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, s16 tx_power) { struct iwl_dev_tx_power_cmd cmd = { - .v2.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC), - .v2.mac_context_id = + .v3.v2.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC), + .v3.v2.mac_context_id = cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id), - .v2.pwr_restriction = cpu_to_le16(8 * tx_power), + .v3.v2.pwr_restriction = cpu_to_le16(8 * tx_power), }; int len = sizeof(cmd); if (tx_power == IWL_DEFAULT_MAX_TX_POWER) - cmd.v2.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER); + cmd.v3.v2.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER); + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) + len = sizeof(cmd.v3); if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TX_POWER_CHAIN)) - len = sizeof(cmd.v2); + len = sizeof(cmd.v3.v2); return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); } @@ -2360,7 +2382,7 @@ static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT)) return; - if (vif->p2p && !iwl_mvm_is_p2p_standalone_uapsd_supported(mvm)) { + if (vif->p2p && !iwl_mvm_is_p2p_scm_uapsd_supported(mvm)) { vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD; return; } @@ -2719,6 +2741,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; break; case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; break; case WLAN_CIPHER_SUITE_AES_CMAC: @@ -2780,7 +2804,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, sta && iwl_mvm_has_new_rx_api(mvm) && key->flags & IEEE80211_KEY_FLAG_PAIRWISE && (key->cipher == WLAN_CIPHER_SUITE_CCMP || - key->cipher == WLAN_CIPHER_SUITE_GCMP)) { + key->cipher == WLAN_CIPHER_SUITE_GCMP || + key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) { struct ieee80211_key_seq seq; int tid, q; @@ -2834,7 +2859,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, if (sta && iwl_mvm_has_new_rx_api(mvm) && key->flags & IEEE80211_KEY_FLAG_PAIRWISE && (key->cipher == WLAN_CIPHER_SUITE_CCMP || - key->cipher == WLAN_CIPHER_SUITE_GCMP)) { + key->cipher == WLAN_CIPHER_SUITE_GCMP || + key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) { mvmsta = iwl_mvm_sta_from_mac80211(sta); ptk_pn = rcu_dereference_protected( mvmsta->ptk_pn[keyidx], @@ -3687,6 +3713,13 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, goto out_unlock; } + /* we still didn't unblock tx. prevent new CS meanwhile */ + if (rcu_dereference_protected(mvm->csa_tx_blocked_vif, + lockdep_is_held(&mvm->mutex))) { + ret = -EBUSY; + goto out_unlock; + } + rcu_assign_pointer(mvm->csa_vif, vif); if (WARN_ONCE(mvmvif->csa_countdown, @@ -3695,6 +3728,8 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, goto out_unlock; } + mvmvif->csa_target_freq = chsw->chandef.chan->center_freq; + break; case NL80211_IFTYPE_STATION: if (mvmvif->lqm_active) @@ -3898,6 +3933,11 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + if (mvmsta->avg_energy) { + sinfo->signal_avg = mvmsta->avg_energy; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG); + } + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS)) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index ffbd41dcc0d4..b4fc86d5d7ef 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -452,6 +452,7 @@ struct iwl_mvm_vif { /* Indicates that CSA countdown may be started */ bool csa_countdown; bool csa_failed; + u16 csa_target_freq; /* TCP Checksum Offload */ netdev_features_t features; @@ -686,13 +687,28 @@ struct iwl_mvm_baid_data { * This is the state of a queue that has been fully configured (including * SCD pointers, etc), has a specific RA/TID assigned to it, and can be * used to send traffic. + * @IWL_MVM_QUEUE_SHARED: queue is shared, or in a process of becoming shared + * This is a state in which a single queue serves more than one TID, all of + * which are not aggregated. Note that the queue is only associated to one + * RA. + * @IWL_MVM_QUEUE_INACTIVE: queue is allocated but no traffic on it + * This is a state of a queue that has had traffic on it, but during the + * last %IWL_MVM_DQA_QUEUE_TIMEOUT time period there has been no traffic on + * it. In this state, when a new queue is needed to be allocated but no + * such free queue exists, an inactive queue might be freed and given to + * the new RA/TID. */ enum iwl_mvm_queue_status { IWL_MVM_QUEUE_FREE, IWL_MVM_QUEUE_RESERVED, IWL_MVM_QUEUE_READY, + IWL_MVM_QUEUE_SHARED, + IWL_MVM_QUEUE_INACTIVE, }; +#define IWL_MVM_DQA_QUEUE_TIMEOUT (5 * HZ) +#define IWL_MVM_NUM_CIPHERS 8 + struct iwl_mvm { /* for logger access */ struct device *dev; @@ -731,6 +747,7 @@ struct iwl_mvm { struct iwl_sf_region sf_space; u32 ampdu_ref; + bool ampdu_toggle; struct iwl_notif_wait_data notif_wait; @@ -748,11 +765,16 @@ struct iwl_mvm { u32 hw_queue_to_mac80211; u8 hw_queue_refcount; u8 ra_sta_id; /* The RA this queue is mapped to, if exists */ + bool reserved; /* Is this the TXQ reserved for a STA */ + u8 mac80211_ac; /* The mac80211 AC this queue is mapped to */ u16 tid_bitmap; /* Bitmap of the TIDs mapped to this queue */ + /* Timestamp for inactivation per TID of this queue */ + unsigned long last_frame_time[IWL_MAX_TID_COUNT + 1]; enum iwl_mvm_queue_status status; } queue_info[IWL_MAX_HW_QUEUES]; spinlock_t queue_info_lock; /* For syncing queue mgmt operations */ struct work_struct add_stream_wk; /* To add streams to queues */ + atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES]; const char *nvm_file_name; @@ -787,7 +809,7 @@ struct iwl_mvm { struct iwl_mcast_filter_cmd *mcast_filter_cmd; enum iwl_mvm_scan_type scan_type; enum iwl_mvm_sched_scan_pass_all_states sched_scan_pass_all; - struct timer_list scan_timer; + struct delayed_work scan_timeout_dwork; /* max number of simultaneous scans the FW supports */ unsigned int max_scans; @@ -910,11 +932,6 @@ struct iwl_mvm { wait_queue_head_t d0i3_exit_waitq; /* BT-Coex */ - 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; struct iwl_bt_coex_profile_notif last_bt_notif; struct iwl_bt_coex_ci_cmd last_bt_ci_cmd; @@ -994,7 +1011,8 @@ struct iwl_mvm { struct iwl_mvm_shared_mem_cfg shared_mem_cfg; - u32 ciphers[6]; + u32 ciphers[IWL_MVM_NUM_CIPHERS]; + struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; struct iwl_mvm_tof_data tof_data; struct ieee80211_vif *nan_vif; @@ -1006,6 +1024,8 @@ struct iwl_mvm { * clients. */ bool drop_bcn_ap_mode; + + struct delayed_work cs_tx_unblock_dwork; }; /* Extract MVM priv from op_mode and _hw */ @@ -1158,10 +1178,10 @@ static inline bool iwl_mvm_is_mplut_supported(struct iwl_mvm *mvm) } static inline -bool iwl_mvm_is_p2p_standalone_uapsd_supported(struct iwl_mvm *mvm) +bool iwl_mvm_is_p2p_scm_uapsd_supported(struct iwl_mvm *mvm) { return fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD) && + IWL_UCODE_TLV_CAPA_P2P_SCM_UAPSD) && !(iwlwifi_mod_params.uapsd_disable & IWL_DISABLE_UAPSD_P2P_CLIENT); } @@ -1321,7 +1341,6 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb); -void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue); void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, @@ -1381,6 +1400,8 @@ void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif); unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, struct ieee80211_vif *exclude_vif); +void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); /* Bindings */ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); @@ -1397,7 +1418,7 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm); int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify); int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm); void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm); -void iwl_mvm_scan_timeout(unsigned long data); +void iwl_mvm_scan_timeout_wk(struct work_struct *work); /* Scheduled scan */ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, @@ -1613,7 +1634,7 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, */ void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, u8 tid, u8 flags); -int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 minq, u8 maxq); +int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq); /* Return a bitmask with all the hw supported queues, except for the * command queue, which can't be flushed. @@ -1720,6 +1741,8 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, void iwl_mvm_reorder_timer_expired(unsigned long data); struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm); +void iwl_mvm_inactivity_check(struct iwl_mvm *mvm); + void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 25a98401a64f..7a686f67f007 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -66,7 +66,6 @@ *****************************************************************************/ #include <linux/firmware.h> #include <linux/rtnetlink.h> -#include <linux/pci.h> #include <linux/acpi.h> #include "iwl-trans.h" #include "iwl-csr.h" @@ -667,8 +666,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, .mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]), .source_id = (u8)src_id, }; - struct iwl_mcc_update_resp *mcc_resp, *resp_cp = NULL; - struct iwl_mcc_update_resp_v1 *mcc_resp_v1 = NULL; + struct iwl_mcc_update_resp *resp_cp; struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = MCC_UPDATE_CMD, @@ -701,34 +699,36 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, /* Extract MCC response */ if (resp_v2) { - mcc_resp = (void *)pkt->data; + struct iwl_mcc_update_resp *mcc_resp = (void *)pkt->data; + n_channels = __le32_to_cpu(mcc_resp->n_channels); + resp_len = sizeof(struct iwl_mcc_update_resp) + + n_channels * sizeof(__le32); + resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); } else { - mcc_resp_v1 = (void *)pkt->data; + struct iwl_mcc_update_resp_v1 *mcc_resp_v1 = (void *)pkt->data; + n_channels = __le32_to_cpu(mcc_resp_v1->n_channels); + resp_len = sizeof(struct iwl_mcc_update_resp) + + n_channels * sizeof(__le32); + resp_cp = kzalloc(resp_len, GFP_KERNEL); + + if (resp_cp) { + resp_cp->status = mcc_resp_v1->status; + resp_cp->mcc = mcc_resp_v1->mcc; + resp_cp->cap = mcc_resp_v1->cap; + resp_cp->source_id = mcc_resp_v1->source_id; + resp_cp->n_channels = mcc_resp_v1->n_channels; + memcpy(resp_cp->channels, mcc_resp_v1->channels, + n_channels * sizeof(__le32)); + } } - resp_len = sizeof(struct iwl_mcc_update_resp) + n_channels * - sizeof(__le32); - - resp_cp = kzalloc(resp_len, GFP_KERNEL); if (!resp_cp) { ret = -ENOMEM; goto exit; } - if (resp_v2) { - memcpy(resp_cp, mcc_resp, resp_len); - } else { - resp_cp->status = mcc_resp_v1->status; - resp_cp->mcc = mcc_resp_v1->mcc; - resp_cp->cap = mcc_resp_v1->cap; - resp_cp->source_id = mcc_resp_v1->source_id; - resp_cp->n_channels = mcc_resp_v1->n_channels; - memcpy(resp_cp->channels, mcc_resp_v1->channels, - n_channels * sizeof(__le32)); - } - status = le32_to_cpu(resp_cp->status); mcc = le16_to_cpu(resp_cp->mcc); @@ -802,9 +802,8 @@ static int iwl_mvm_get_bios_mcc(struct iwl_mvm *mvm, char *mcc) struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL}; acpi_status status; u32 mcc_val; - struct pci_dev *pdev = to_pci_dev(mvm->dev); - root_handle = ACPI_HANDLE(&pdev->dev); + root_handle = ACPI_HANDLE(mvm->dev); if (!root_handle) { IWL_DEBUG_LAR(mvm, "Could not retrieve root port ACPI handle\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index a68054f127fa..55d9096da68c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -431,6 +431,7 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = { static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = { HCMD_NAME(LINK_QUALITY_MEASUREMENT_CMD), HCMD_NAME(LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF), + HCMD_NAME(CHANNEL_SWITCH_NOA_NOTIF), }; /* Please keep this array *SORTED* by hex value. @@ -494,6 +495,29 @@ static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg) static void iwl_mvm_fw_error_dump_wk(struct work_struct *work); +static void iwl_mvm_tx_unblock_dwork(struct work_struct *work) +{ + struct iwl_mvm *mvm = + container_of(work, struct iwl_mvm, cs_tx_unblock_dwork.work); + struct ieee80211_vif *tx_blocked_vif; + struct iwl_mvm_vif *mvmvif; + + mutex_lock(&mvm->mutex); + + tx_blocked_vif = + rcu_dereference_protected(mvm->csa_tx_blocked_vif, + lockdep_is_held(&mvm->mutex)); + + if (!tx_blocked_vif) + goto unlock; + + mvmvif = iwl_mvm_vif_from_mac80211(tx_blocked_vif); + iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, false); + RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL); +unlock: + mutex_unlock(&mvm->mutex); +} + static struct iwl_op_mode * iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) @@ -553,18 +577,21 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0; - mvm->aux_queue = 15; if (!iwl_mvm_is_dqa_supported(mvm)) { - mvm->first_agg_queue = 16; mvm->last_agg_queue = mvm->cfg->base_params->num_of_queues - 1; + + if (mvm->cfg->base_params->num_of_queues == 16) { + mvm->aux_queue = 11; + mvm->first_agg_queue = 12; + } else { + mvm->aux_queue = 15; + mvm->first_agg_queue = 16; + } } else { + mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE; mvm->first_agg_queue = IWL_MVM_DQA_MIN_DATA_QUEUE; mvm->last_agg_queue = IWL_MVM_DQA_MAX_DATA_QUEUE; } - if (mvm->cfg->base_params->num_of_queues == 16) { - mvm->aux_queue = 11; - mvm->first_agg_queue = 12; - } mvm->sf_state = SF_UNINIT; mvm->cur_ucode = IWL_UCODE_INIT; mvm->drop_bcn_ap_mode = true; @@ -584,6 +611,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); INIT_DELAYED_WORK(&mvm->fw_dump_wk, iwl_mvm_fw_error_dump_wk); INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work); + INIT_DELAYED_WORK(&mvm->scan_timeout_dwork, iwl_mvm_scan_timeout_wk); INIT_WORK(&mvm->add_stream_wk, iwl_mvm_add_new_dqa_stream_wk); spin_lock_init(&mvm->d0i3_tx_lock); @@ -595,6 +623,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev); + INIT_DELAYED_WORK(&mvm->cs_tx_unblock_dwork, iwl_mvm_tx_unblock_dwork); + /* * Populate the state variables that the transport layer needs * to know about. @@ -603,6 +633,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); switch (iwlwifi_mod_params.amsdu_size) { + case IWL_AMSDU_DEF: case IWL_AMSDU_4K: trans_cfg.rx_buf_size = IWL_AMSDU_4K; break; @@ -617,6 +648,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwlwifi_mod_params.amsdu_size); trans_cfg.rx_buf_size = IWL_AMSDU_4K; } + + /* the hardware splits the A-MSDU */ + if (mvm->cfg->mq_rx_supported) + trans_cfg.rx_buf_size = IWL_AMSDU_4K; trans_cfg.wide_cmd_header = fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WIDE_CMD_HDR); @@ -633,6 +668,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; trans_cfg.scd_set_active = true; + trans_cfg.cb_data_offs = offsetof(struct ieee80211_tx_info, + driver_data[2]); + trans_cfg.sdio_adma_addr = fw->sdio_adma_addr; trans_cfg.sw_csum_tx = IWL_MVM_SW_TX_CSUM_OFFLOAD; @@ -735,9 +773,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_mvm_tof_init(mvm); - setup_timer(&mvm->scan_timer, iwl_mvm_scan_timeout, - (unsigned long)mvm); - return op_mode; out_unregister: @@ -791,8 +826,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) iwl_mvm_tof_clean(mvm); - del_timer_sync(&mvm->scan_timer); - mutex_destroy(&mvm->mutex); mutex_destroy(&mvm->d0i3_suspend_mutex); @@ -936,8 +969,6 @@ static void iwl_mvm_rx(struct iwl_op_mode *op_mode, if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) iwl_mvm_rx_rx_mpdu(mvm, napi, rxb); - else if (pkt->hdr.cmd == FRAME_RELEASE) - iwl_mvm_rx_frame_release(mvm, napi, rxb, 0); else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD) iwl_mvm_rx_rx_phy_cmd(mvm, rxb); else @@ -953,11 +984,11 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode, if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, 0); - else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD) - iwl_mvm_rx_phy_cmd_mq(mvm, rxb); else if (unlikely(pkt->hdr.group_id == DATA_PATH_GROUP && pkt->hdr.cmd == RX_QUEUES_NOTIFICATION)) iwl_mvm_rx_queue_notif(mvm, rxb, 0); + else if (pkt->hdr.cmd == FRAME_RELEASE) + iwl_mvm_rx_frame_release(mvm, napi, rxb, 0); else iwl_mvm_rx_common(mvm, rxb, pkt); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index 7b1f6ad6062b..ff85865b1dda 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -308,7 +308,7 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, /* Allow U-APSD only if p2p is stand alone */ bool is_p2p_standalone = true; - if (!iwl_mvm_is_p2p_standalone_uapsd_supported(mvm)) + if (!iwl_mvm_is_p2p_scm_uapsd_supported(mvm)) return false; ieee80211_iterate_active_interfaces_atomic(mvm->hw, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 81dd2f6a48a5..227c5ed9cbe6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -211,6 +211,9 @@ static bool rs_sgi_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (is_ht80(rate) && (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80)) return true; + if (is_ht160(rate) && (vht_cap->cap & + IEEE80211_VHT_CAP_SHORT_GI_160)) + return true; return false; } @@ -399,7 +402,7 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) static void rs_rate_scale_perform(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, - int tid); + int tid, bool ndp); static void rs_fill_lq_cmd(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, @@ -445,6 +448,13 @@ static const u16 expected_tpt_siso_80MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 241, 0, 475, 701, 921, 1343, 1741, 1931, 2117, 2468, 2691}, }; +static const u16 expected_tpt_siso_160MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 191, 0, 244, 288, 298, 308, 313, 318, 323, 328, 330}, + {0, 0, 0, 0, 200, 0, 251, 293, 302, 312, 317, 322, 327, 332, 334}, + {0, 0, 0, 0, 439, 0, 875, 1307, 1736, 2584, 3419, 3831, 4240, 5049, 5581}, + {0, 0, 0, 0, 488, 0, 972, 1451, 1925, 2864, 3785, 4240, 4691, 5581, 6165}, +}; + static const u16 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250, 261, 0}, {0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256, 267, 0}, @@ -466,6 +476,13 @@ static const u16 expected_tpt_mimo2_80MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 474, 0, 920, 1338, 1732, 2464, 3116, 3418, 3705, 4225, 4545}, }; +static const u16 expected_tpt_mimo2_160MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 240, 0, 278, 308, 313, 319, 322, 324, 328, 330, 334}, + {0, 0, 0, 0, 247, 0, 282, 310, 315, 320, 323, 325, 329, 332, 338}, + {0, 0, 0, 0, 875, 0, 1735, 2582, 3414, 5043, 6619, 7389, 8147, 9629, 10592}, + {0, 0, 0, 0, 971, 0, 1925, 2861, 3779, 5574, 7304, 8147, 8976, 10592, 11640}, +}; + /* mbps, mcs */ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { { "1", "BPSK DSSS"}, @@ -901,7 +918,6 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, } } - WARN_ON_ONCE(rate->bw == RATE_MCS_CHAN_WIDTH_160); WARN_ON_ONCE(rate->bw == RATE_MCS_CHAN_WIDTH_80 && !is_vht(rate)); @@ -1161,7 +1177,7 @@ static u8 rs_get_tid(struct ieee80211_hdr *hdr) } void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int tid, struct ieee80211_tx_info *info) + int tid, struct ieee80211_tx_info *info, bool ndp) { int legacy_success; int retries; @@ -1384,7 +1400,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, done: /* See if there's a better rate or modulation mode to try. */ if (sta->supp_rates[info->band]) - rs_rate_scale_perform(mvm, sta, lq_sta, tid); + rs_rate_scale_perform(mvm, sta, lq_sta, tid, ndp); } /* @@ -1407,7 +1423,8 @@ static void rs_mac80211_tx_status(void *mvm_r, info->flags & IEEE80211_TX_CTL_NO_ACK) return; - iwl_mvm_rs_tx_status(mvm, sta, rs_get_tid(hdr), info); + iwl_mvm_rs_tx_status(mvm, sta, rs_get_tid(hdr), info, + ieee80211_is_qos_nullfunc(hdr->frame_control)); } /* @@ -1494,6 +1511,9 @@ static const u16 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta, case RATE_MCS_CHAN_WIDTH_80: ht_tbl_pointer = expected_tpt_siso_80MHz; break; + case RATE_MCS_CHAN_WIDTH_160: + ht_tbl_pointer = expected_tpt_siso_160MHz; + break; default: WARN_ON_ONCE(1); } @@ -1508,6 +1528,9 @@ static const u16 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta, case RATE_MCS_CHAN_WIDTH_80: ht_tbl_pointer = expected_tpt_mimo2_80MHz; break; + case RATE_MCS_CHAN_WIDTH_160: + ht_tbl_pointer = expected_tpt_mimo2_160MHz; + break; default: WARN_ON_ONCE(1); } @@ -1582,12 +1605,17 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta) { - if (sta->bandwidth >= IEEE80211_STA_RX_BW_80) + switch (sta->bandwidth) { + case IEEE80211_STA_RX_BW_160: + return RATE_MCS_CHAN_WIDTH_160; + case IEEE80211_STA_RX_BW_80: return RATE_MCS_CHAN_WIDTH_80; - else if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) + case IEEE80211_STA_RX_BW_40: return RATE_MCS_CHAN_WIDTH_40; - - return RATE_MCS_CHAN_WIDTH_20; + case IEEE80211_STA_RX_BW_20: + default: + return RATE_MCS_CHAN_WIDTH_20; + } } /* @@ -2213,7 +2241,7 @@ static bool rs_tpc_perform(struct iwl_mvm *mvm, static void rs_rate_scale_perform(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, - int tid) + int tid, bool ndp) { int low = IWL_RATE_INVALID; int high = IWL_RATE_INVALID; @@ -2512,7 +2540,7 @@ lq_update: (lq_sta->tx_agg_tid_en & (1 << tid)) && (tid != IWL_MAX_TID_COUNT)) { tid_data = &sta_priv->tid_data[tid]; - if (tid_data->state == IWL_AGG_OFF) { + if (tid_data->state == IWL_AGG_OFF && !ndp) { IWL_DEBUG_RATE(mvm, "try to aggregate tid %d\n", tid); @@ -2565,6 +2593,9 @@ static const struct rs_init_rate_info rs_optimal_rates_ht[] = { { S8_MIN, IWL_RATE_MCS_0_INDEX}, }; +/* MCS index 9 is not valid for 20MHz VHT channel width, + * but is ok for 40, 80 and 160MHz channels. + */ static const struct rs_init_rate_info rs_optimal_rates_vht_20mhz[] = { { -60, IWL_RATE_MCS_8_INDEX }, { -64, IWL_RATE_MCS_7_INDEX }, @@ -2577,7 +2608,7 @@ static const struct rs_init_rate_info rs_optimal_rates_vht_20mhz[] = { { S8_MIN, IWL_RATE_MCS_0_INDEX}, }; -static const struct rs_init_rate_info rs_optimal_rates_vht_40_80mhz[] = { +static const struct rs_init_rate_info rs_optimal_rates_vht[] = { { -60, IWL_RATE_MCS_9_INDEX }, { -64, IWL_RATE_MCS_8_INDEX }, { -68, IWL_RATE_MCS_7_INDEX }, @@ -2640,9 +2671,9 @@ static void rs_init_optimal_rate(struct iwl_mvm *mvm, lq_sta->optimal_nentries = ARRAY_SIZE(rs_optimal_rates_vht_20mhz); } else { - lq_sta->optimal_rates = rs_optimal_rates_vht_40_80mhz; + lq_sta->optimal_rates = rs_optimal_rates_vht; lq_sta->optimal_nentries = - ARRAY_SIZE(rs_optimal_rates_vht_40_80mhz); + ARRAY_SIZE(rs_optimal_rates_vht); } } else if (is_ht(rate)) { lq_sta->optimal_rates = rs_optimal_rates_ht; @@ -2734,23 +2765,25 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, */ if (sta->vht_cap.vht_supported && best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) { - if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) { - initial_rates = rs_optimal_rates_vht_40_80mhz; - nentries = ARRAY_SIZE(rs_optimal_rates_vht_40_80mhz); - if (sta->bandwidth >= IEEE80211_STA_RX_BW_80) - rate->bw = RATE_MCS_CHAN_WIDTH_80; - else - rate->bw = RATE_MCS_CHAN_WIDTH_40; - } else if (sta->bandwidth == IEEE80211_STA_RX_BW_20) { + switch (sta->bandwidth) { + case IEEE80211_STA_RX_BW_160: + case IEEE80211_STA_RX_BW_80: + case IEEE80211_STA_RX_BW_40: + initial_rates = rs_optimal_rates_vht; + nentries = ARRAY_SIZE(rs_optimal_rates_vht); + break; + case IEEE80211_STA_RX_BW_20: initial_rates = rs_optimal_rates_vht_20mhz; nentries = ARRAY_SIZE(rs_optimal_rates_vht_20mhz); - rate->bw = RATE_MCS_CHAN_WIDTH_20; - } else { + break; + default: IWL_ERR(mvm, "Invalid BW %d\n", sta->bandwidth); goto out; } + active_rate = lq_sta->active_siso_rate; rate->type = LQ_VHT_SISO; + rate->bw = rs_bw_from_sta_bw(sta); } else if (sta->ht_cap.ht_supported && best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) { initial_rates = rs_optimal_rates_ht; @@ -3057,6 +3090,9 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg) case RATE_MCS_CHAN_WIDTH_80: mvm->drv_rx_stats.bw_80_frames++; break; + case RATE_MCS_CHAN_WIDTH_160: + mvm->drv_rx_stats.bw_160_frames++; + break; default: WARN_ONCE(1, "bad BW. rate 0x%x", rate); } @@ -3705,7 +3741,8 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, desc += sprintf(buff + desc, " %s", (is_ht20(rate)) ? "20MHz" : (is_ht40(rate)) ? "40MHz" : - (is_ht80(rate)) ? "80Mhz" : "BAD BW"); + (is_ht80(rate)) ? "80MHz" : + (is_ht160(rate)) ? "160MHz" : "BAD BW"); desc += sprintf(buff + desc, " %s %s %s %s\n", (rate->sgi) ? "SGI" : "NGI", (rate->ldpc) ? "LDPC" : "BCC", @@ -3787,9 +3824,10 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, lq_sta->active_tbl == i ? "*" : "x", rate->type, rate->sgi, - is_ht20(rate) ? "20Mhz" : - is_ht40(rate) ? "40Mhz" : - is_ht80(rate) ? "80Mhz" : "ERR", + is_ht20(rate) ? "20MHz" : + is_ht40(rate) ? "40MHz" : + is_ht80(rate) ? "80MHz" : + is_ht160(rate) ? "160MHz" : "ERR", rate->index); for (j = 0; j < IWL_RATE_COUNT; j++) { desc += sprintf(buff+desc, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index 90d046fb24a0..ee207f2c0a90 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -205,6 +205,7 @@ struct rs_rate { #define is_ht20(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_20) #define is_ht40(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_40) #define is_ht80(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_80) +#define is_ht160(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_160) #define IWL_MAX_MCS_DISPLAY_SIZE 12 @@ -362,7 +363,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, /* Notify RS about Tx status */ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int tid, struct ieee80211_tx_info *info); + int tid, struct ieee80211_tx_info *info, bool ndp); /** * iwl_rate_control_register - Register the rate control algorithm callbacks diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index ab7f7eda9c13..0e60e38b2acf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -101,7 +101,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, struct napi_struct *napi, struct sk_buff *skb, struct ieee80211_hdr *hdr, u16 len, - u32 ampdu_status, u8 crypt_len, + u8 crypt_len, struct iwl_rx_cmd_buffer *rxb) { unsigned int hdrlen, fraglen; @@ -268,7 +268,6 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, struct ieee80211_sta *sta = NULL; struct sk_buff *skb; u32 len; - u32 ampdu_status; u32 rate_n_flags; u32 rx_pkt_status; u8 crypt_len = 0; @@ -354,13 +353,22 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, if (sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct ieee80211_vif *tx_blocked_vif = + rcu_dereference(mvm->csa_tx_blocked_vif); /* We have tx blocked stations (with CS bit). If we heard * frames from a blocked station on a new channel we can * TX to it again. */ - if (unlikely(mvm->csa_tx_block_bcn_timeout)) - iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false); + if (unlikely(tx_blocked_vif) && + mvmsta->vif == tx_blocked_vif) { + struct iwl_mvm_vif *mvmvif = + iwl_mvm_vif_from_mac80211(tx_blocked_vif); + + if (mvmvif->csa_target_freq == rx_status->freq) + iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, + false); + } rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status); @@ -471,7 +479,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, iwl_mvm_ref(mvm, IWL_MVM_REF_RX); iwl_mvm_pass_packet_to_mac80211(mvm, sta, napi, skb, hdr, len, - ampdu_status, crypt_len, rxb); + crypt_len, rxb); if (take_ref) iwl_mvm_unref(mvm, IWL_MVM_REF_RX); @@ -490,6 +498,7 @@ struct iwl_mvm_stat_data { __le32 mac_id; u8 beacon_filter_average_energy; struct mvm_statistics_general_v8 *general; + struct mvm_statistics_load *load; }; static void iwl_mvm_stat_iterator(void *_data, u8 *mac, @@ -606,13 +615,15 @@ iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) { - struct iwl_notif_statistics_v10 *stats = (void *)&pkt->data; + struct iwl_notif_statistics_v11 *stats = (void *)&pkt->data; struct iwl_mvm_stat_data data = { .mvm = mvm, }; + int expected_size = iwl_mvm_has_new_rx_api(mvm) ? sizeof(*stats) : + sizeof(struct iwl_notif_statistics_v10); u32 temperature; - if (iwl_rx_packet_payload_len(pkt) != sizeof(*stats)) + if (iwl_rx_packet_payload_len(pkt) != expected_size) goto invalid; temperature = le32_to_cpu(stats->general.radio_temperature); @@ -630,6 +641,25 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, le64_to_cpu(stats->general.on_time_scan); data.general = &stats->general; + if (iwl_mvm_has_new_rx_api(mvm)) { + int i; + + data.load = &stats->load_stats; + + rcu_read_lock(); + for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + struct iwl_mvm_sta *sta; + + if (!data.load->avg_energy[i]) + continue; + + sta = iwl_mvm_sta_from_staid_rcu(mvm, i); + if (!sta) + continue; + sta->avg_energy = data.load->avg_energy[i]; + } + rcu_read_unlock(); + } iwl_mvm_rx_stats_check_trigger(mvm, pkt); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 2c61516d06ff..df6c32caa5f0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -65,19 +65,6 @@ #include "fw-api.h" #include "fw-dbg.h" -void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) -{ - mvm->ampdu_ref++; - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (mvm->last_phy_info.phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) { - spin_lock(&mvm->drv_stats_lock); - mvm->drv_rx_stats.ampdu_count++; - spin_unlock(&mvm->drv_stats_lock); - } -#endif -} - static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, int queue, struct ieee80211_sta *sta) { @@ -489,6 +476,9 @@ void iwl_mvm_reorder_timer_expired(unsigned long data) rcu_read_lock(); sta = rcu_dereference(buf->mvm->fw_id_to_mac_id[buf->sta_id]); /* SN is set to the last expired frame + 1 */ + IWL_DEBUG_HT(buf->mvm, + "Releasing expired frames for sta %u, sn %d\n", + buf->sta_id, sn); iwl_mvm_release_frames(buf->mvm, sta, NULL, buf, sn); rcu_read_unlock(); } else if (buf->num_stored) { @@ -587,6 +577,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, struct sk_buff *tail; u32 reorder = le32_to_cpu(desc->reorder_data); bool amsdu = desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU; + bool last_subframe = + desc->amsdu_info & IWL_RX_MPDU_AMSDU_LAST_SUBFRAME; u8 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; u8 sub_frame_idx = desc->amsdu_info & IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; @@ -653,7 +645,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, /* release immediately if allowed by nssn and no stored frames */ if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) { if (iwl_mvm_is_sn_less(buffer->head_sn, nssn, - buffer->buf_size)) + buffer->buf_size) && + (!amsdu || last_subframe)) buffer->head_sn = nssn; /* No need to update AMSDU last SN - we are moving the head */ spin_unlock_bh(&buffer->lock); @@ -687,7 +680,20 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, buffer->last_sub_index = sub_frame_idx; } - iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn); + /* + * We cannot trust NSSN for AMSDU sub-frames that are not the last. + * The reason is that NSSN advances on the first sub-frame, and may + * cause the reorder buffer to advance before all the sub-frames arrive. + * Example: reorder buffer contains SN 0 & 2, and we receive AMSDU with + * SN 1. NSSN for first sub frame will be 3 with the result of driver + * releasing SN 0,1, 2. When sub-frame 1 arrives - reorder buffer is + * already ahead and it will be dropped. + * If the last sub-frame is not on this queue - we will get frame + * release notification with up to date NSSN. + */ + if (!amsdu || last_subframe) + iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn); + spin_unlock_bh(&buffer->lock); return true; @@ -736,6 +742,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct ieee80211_hdr *hdr = (void *)(pkt->data + sizeof(*desc)); u32 len = le16_to_cpu(desc->mpdu_len); u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags); + u16 phy_info = le16_to_cpu(desc->phy_info); struct ieee80211_sta *sta = NULL; struct sk_buff *skb; u8 crypt_len = 0; @@ -766,16 +773,34 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, le16_to_cpu(desc->status)); rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; } - - rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise); + /* set the preamble flag if appropriate */ + if (phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE) + rx_status->flag |= RX_FLAG_SHORTPRE; + + if (likely(!(phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD))) { + rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise); + /* TSF as indicated by the firmware is at INA time */ + rx_status->flag |= RX_FLAG_MACTIME_PLCP_START; + } rx_status->device_timestamp = le32_to_cpu(desc->gp2_on_air_rise); rx_status->band = desc->channel > 14 ? NL80211_BAND_5GHZ : NL80211_BAND_2GHZ; rx_status->freq = ieee80211_channel_to_frequency(desc->channel, rx_status->band); iwl_mvm_get_signal_strength(mvm, desc, rx_status); - /* TSF as indicated by the firmware is at INA time */ - rx_status->flag |= RX_FLAG_MACTIME_PLCP_START; + + /* update aggregation data for monitor sake on default queue */ + if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) { + bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE; + + rx_status->flag |= RX_FLAG_AMPDU_DETAILS; + rx_status->ampdu_reference = mvm->ampdu_ref; + /* toggle is switched whenever new aggregation starts */ + if (toggle_bit != mvm->ampdu_toggle) { + mvm->ampdu_ref++; + mvm->ampdu_toggle = toggle_bit; + } + } rcu_read_lock(); @@ -797,6 +822,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, if (sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct ieee80211_vif *tx_blocked_vif = + rcu_dereference(mvm->csa_tx_blocked_vif); u8 baid = (u8)((le32_to_cpu(desc->reorder_data) & IWL_RX_MPDU_REORDER_BAID_MASK) >> IWL_RX_MPDU_REORDER_BAID_SHIFT); @@ -806,8 +833,15 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, * frames from a blocked station on a new channel we can * TX to it again. */ - if (unlikely(mvm->csa_tx_block_bcn_timeout)) - iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false); + if (unlikely(tx_blocked_vif) && + tx_blocked_vif == mvmsta->vif) { + struct iwl_mvm_vif *mvmvif = + iwl_mvm_vif_from_mac80211(tx_blocked_vif); + + if (mvmvif->csa_target_freq == rx_status->freq) + iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, + false); + } rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status); @@ -830,8 +864,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL); } - /* TODO: multi queue TCM */ - if (ieee80211_is_data(hdr->frame_control)) iwl_mvm_rx_csum(sta, skb, desc); @@ -856,14 +888,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, iwl_mvm_agg_rx_received(mvm, baid); } - /* - * TODO: PHY info. - * Verify we don't have the information in the MPDU descriptor and - * that it is not needed. - * Make sure for monitor mode that we are on default queue, update - * ampdu_ref and the rest of phy info then - */ - /* Set up the HT phy flags */ switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { case RATE_MCS_CHAN_WIDTH_20: @@ -907,8 +931,18 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rx_status->band); } - /* TODO: PHY info - update ampdu queue statistics (for debugfs) */ - /* TODO: PHY info - gscan */ + /* management stuff on default queue */ + if (!queue) { + if (unlikely((ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control)) && + mvm->sched_scan_pass_all == + SCHED_SCAN_PASS_ALL_ENABLED)) + mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_FOUND; + + if (unlikely(ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control))) + rx_status->boottime_ns = ktime_get_boot_ns(); + } iwl_mvm_create_skb(skb, hdr, len, crypt_len, rxb); if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc)) @@ -927,6 +961,9 @@ void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, int baid = release->baid; + IWL_DEBUG_HT(mvm, "Frame release notification for BAID %u, NSSN %d\n", + release->baid, le16_to_cpu(release->nssn)); + if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID)) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index e78fc567ff7d..dac120f8861b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -391,15 +391,18 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, ieee80211_sched_scan_stopped(mvm->hw); mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; } else if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) { + struct cfg80211_scan_info info = { + .aborted = aborted, + }; + IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s (FW)\n", aborted ? "aborted" : "completed", iwl_mvm_ebs_status_str(scan_notif->ebs_status)); mvm->scan_status &= ~IWL_MVM_SCAN_REGULAR; - ieee80211_scan_completed(mvm->hw, - scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED); + ieee80211_scan_completed(mvm->hw, &info); iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); - del_timer(&mvm->scan_timer); + cancel_delayed_work(&mvm->scan_timeout_dwork); } else { IWL_ERR(mvm, "got scan complete notification but no scan is running\n"); @@ -1222,15 +1225,16 @@ static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type) return -EIO; } -#define SCAN_TIMEOUT (20 * HZ) +#define SCAN_TIMEOUT 20000 -void iwl_mvm_scan_timeout(unsigned long data) +void iwl_mvm_scan_timeout_wk(struct work_struct *work) { - struct iwl_mvm *mvm = (struct iwl_mvm *)data; + struct delayed_work *delayed_work = to_delayed_work(work); + struct iwl_mvm *mvm = container_of(delayed_work, struct iwl_mvm, + scan_timeout_dwork); IWL_ERR(mvm, "regular scan timed out\n"); - del_timer(&mvm->scan_timer); iwl_force_nmi(mvm->trans); } @@ -1313,7 +1317,8 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvm->scan_status |= IWL_MVM_SCAN_REGULAR; iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); - mod_timer(&mvm->scan_timer, jiffies + SCAN_TIMEOUT); + queue_delayed_work(system_wq, &mvm->scan_timeout_dwork, + msecs_to_jiffies(SCAN_TIMEOUT)); return 0; } @@ -1430,9 +1435,13 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, /* if the scan is already stopping, we don't need to notify mac80211 */ if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_REGULAR) { - ieee80211_scan_completed(mvm->hw, aborted); + struct cfg80211_scan_info info = { + .aborted = aborted, + }; + + ieee80211_scan_completed(mvm->hw, &info); iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); - del_timer(&mvm->scan_timer); + cancel_delayed_work(&mvm->scan_timeout_dwork); } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) { ieee80211_sched_scan_stopped(mvm->hw); mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; @@ -1564,7 +1573,11 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_REGULAR); if (uid >= 0) { - ieee80211_scan_completed(mvm->hw, true); + struct cfg80211_scan_info info = { + .aborted = true, + }; + + ieee80211_scan_completed(mvm->hw, &info); mvm->scan_uid_status[uid] = 0; } uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_SCHED); @@ -1585,8 +1598,13 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) mvm->scan_uid_status[i] = 0; } } else { - if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) - ieee80211_scan_completed(mvm->hw, true); + if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + + ieee80211_scan_completed(mvm->hw, &info); + } /* Sched scan will be restarted by mac80211 in * restart_hw, so do not report if FW is about to be @@ -1628,9 +1646,14 @@ out: * to release the scan reference here. */ iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); - del_timer(&mvm->scan_timer); - if (notify) - ieee80211_scan_completed(mvm->hw, true); + cancel_delayed_work(&mvm->scan_timeout_dwork); + if (notify) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + + ieee80211_scan_completed(mvm->hw, &info); + } } else if (notify) { ieee80211_sched_scan_stopped(mvm->hw); mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c index 443a42855c9e..101fb04a8573 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c @@ -215,7 +215,7 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, enum iwl_sf_state new_state) { struct iwl_sf_cfg_cmd sf_cmd = { - .state = cpu_to_le32(SF_FULL_ON), + .state = cpu_to_le32(new_state), }; struct ieee80211_sta *sta; int ret = 0; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index b23ab4a4504f..3130b9c68a74 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -310,6 +310,304 @@ static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm, iwl_mvm_disable_txq(mvm, i, i, IWL_MAX_TID_COUNT, 0); } +/* Disable aggregations for a bitmap of TIDs for a given station */ +static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue, + unsigned long disable_agg_tids, + bool remove_queue) +{ + struct iwl_mvm_add_sta_cmd cmd = {}; + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + u32 status; + u8 sta_id; + int ret; + + spin_lock_bh(&mvm->queue_info_lock); + sta_id = mvm->queue_info[queue].ra_sta_id; + spin_unlock_bh(&mvm->queue_info_lock); + + rcu_read_lock(); + + sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); + + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { + rcu_read_unlock(); + return -EINVAL; + } + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + + mvmsta->tid_disable_agg |= disable_agg_tids; + + cmd.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color); + cmd.sta_id = mvmsta->sta_id; + cmd.add_modify = STA_MODE_MODIFY; + cmd.modify_mask = STA_MODIFY_QUEUES; + if (disable_agg_tids) + cmd.modify_mask |= STA_MODIFY_TID_DISABLE_TX; + if (remove_queue) + cmd.modify_mask |= STA_MODIFY_QUEUE_REMOVAL; + cmd.tfd_queue_msk = cpu_to_le32(mvmsta->tfd_queue_msk); + cmd.tid_disable_tx = cpu_to_le16(mvmsta->tid_disable_agg); + + rcu_read_unlock(); + + /* Notify FW of queue removal from the STA queues */ + status = ADD_STA_SUCCESS; + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, + iwl_mvm_add_sta_cmd_size(mvm), + &cmd, &status); + + return ret; +} + +static int iwl_mvm_get_queue_agg_tids(struct iwl_mvm *mvm, int queue) +{ + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + unsigned long tid_bitmap; + unsigned long agg_tids = 0; + s8 sta_id; + int tid; + + lockdep_assert_held(&mvm->mutex); + + spin_lock_bh(&mvm->queue_info_lock); + sta_id = mvm->queue_info[queue].ra_sta_id; + tid_bitmap = mvm->queue_info[queue].tid_bitmap; + spin_unlock_bh(&mvm->queue_info_lock); + + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], + lockdep_is_held(&mvm->mutex)); + + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) + return -EINVAL; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + + spin_lock_bh(&mvmsta->lock); + for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { + if (mvmsta->tid_data[tid].state == IWL_AGG_ON) + agg_tids |= BIT(tid); + } + spin_unlock_bh(&mvmsta->lock); + + return agg_tids; +} + +/* + * Remove a queue from a station's resources. + * Note that this only marks as free. It DOESN'T delete a BA agreement, and + * doesn't disable the queue + */ +static int iwl_mvm_remove_sta_queue_marking(struct iwl_mvm *mvm, int queue) +{ + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + unsigned long tid_bitmap; + unsigned long disable_agg_tids = 0; + u8 sta_id; + int tid; + + lockdep_assert_held(&mvm->mutex); + + spin_lock_bh(&mvm->queue_info_lock); + sta_id = mvm->queue_info[queue].ra_sta_id; + tid_bitmap = mvm->queue_info[queue].tid_bitmap; + spin_unlock_bh(&mvm->queue_info_lock); + + rcu_read_lock(); + + sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); + + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { + rcu_read_unlock(); + return 0; + } + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + + spin_lock_bh(&mvmsta->lock); + /* Unmap MAC queues and TIDs from this queue */ + for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { + if (mvmsta->tid_data[tid].state == IWL_AGG_ON) + disable_agg_tids |= BIT(tid); + mvmsta->tid_data[tid].txq_id = IEEE80211_INVAL_HW_QUEUE; + } + + mvmsta->tfd_queue_msk &= ~BIT(queue); /* Don't use this queue anymore */ + spin_unlock_bh(&mvmsta->lock); + + rcu_read_unlock(); + + spin_lock_bh(&mvm->queue_info_lock); + /* Unmap MAC queues and TIDs from this queue */ + mvm->queue_info[queue].hw_queue_to_mac80211 = 0; + mvm->queue_info[queue].hw_queue_refcount = 0; + mvm->queue_info[queue].tid_bitmap = 0; + spin_unlock_bh(&mvm->queue_info_lock); + + return disable_agg_tids; +} + +static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm, + unsigned long tfd_queue_mask, u8 ac) +{ + int queue = 0; + u8 ac_to_queue[IEEE80211_NUM_ACS]; + int i; + + lockdep_assert_held(&mvm->queue_info_lock); + + memset(&ac_to_queue, IEEE80211_INVAL_HW_QUEUE, sizeof(ac_to_queue)); + + /* See what ACs the existing queues for this STA have */ + for_each_set_bit(i, &tfd_queue_mask, IWL_MVM_DQA_MAX_DATA_QUEUE) { + /* Only DATA queues can be shared */ + if (i < IWL_MVM_DQA_MIN_DATA_QUEUE && + i != IWL_MVM_DQA_BSS_CLIENT_QUEUE) + continue; + + ac_to_queue[mvm->queue_info[i].mac80211_ac] = i; + } + + /* + * The queue to share is chosen only from DATA queues as follows (in + * descending priority): + * 1. An AC_BE queue + * 2. Same AC queue + * 3. Highest AC queue that is lower than new AC + * 4. Any existing AC (there always is at least 1 DATA queue) + */ + + /* Priority 1: An AC_BE queue */ + if (ac_to_queue[IEEE80211_AC_BE] != IEEE80211_INVAL_HW_QUEUE) + queue = ac_to_queue[IEEE80211_AC_BE]; + /* Priority 2: Same AC queue */ + else if (ac_to_queue[ac] != IEEE80211_INVAL_HW_QUEUE) + queue = ac_to_queue[ac]; + /* Priority 3a: If new AC is VO and VI exists - use VI */ + else if (ac == IEEE80211_AC_VO && + ac_to_queue[IEEE80211_AC_VI] != IEEE80211_INVAL_HW_QUEUE) + queue = ac_to_queue[IEEE80211_AC_VI]; + /* Priority 3b: No BE so only AC less than the new one is BK */ + else if (ac_to_queue[IEEE80211_AC_BK] != IEEE80211_INVAL_HW_QUEUE) + queue = ac_to_queue[IEEE80211_AC_BK]; + /* Priority 4a: No BE nor BK - use VI if exists */ + else if (ac_to_queue[IEEE80211_AC_VI] != IEEE80211_INVAL_HW_QUEUE) + queue = ac_to_queue[IEEE80211_AC_VI]; + /* Priority 4b: No BE, BK nor VI - use VO if exists */ + else if (ac_to_queue[IEEE80211_AC_VO] != IEEE80211_INVAL_HW_QUEUE) + queue = ac_to_queue[IEEE80211_AC_VO]; + + /* Make sure queue found (or not) is legal */ + if (!((queue >= IWL_MVM_DQA_MIN_MGMT_QUEUE && + queue <= IWL_MVM_DQA_MAX_MGMT_QUEUE) || + (queue >= IWL_MVM_DQA_MIN_DATA_QUEUE && + queue <= IWL_MVM_DQA_MAX_DATA_QUEUE) || + (queue == IWL_MVM_DQA_BSS_CLIENT_QUEUE))) { + IWL_ERR(mvm, "No DATA queues available to share\n"); + queue = -ENOSPC; + } + + return queue; +} + +/* + * If a given queue has a higher AC than the TID stream that is being added to + * it, the queue needs to be redirected to the lower AC. This function does that + * in such a case, otherwise - if no redirection required - it does nothing, + * unless the %force param is true. + */ +static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, + int ac, int ssn, unsigned int wdg_timeout, + bool force) +{ + struct iwl_scd_txq_cfg_cmd cmd = { + .scd_queue = queue, + .enable = 0, + }; + bool shared_queue; + unsigned long mq; + int ret; + + /* + * If the AC is lower than current one - FIFO needs to be redirected to + * the lowest one of the streams in the queue. Check if this is needed + * here. + * Notice that the enum ieee80211_ac_numbers is "flipped", so BK is with + * value 3 and VO with value 0, so to check if ac X is lower than ac Y + * we need to check if the numerical value of X is LARGER than of Y. + */ + spin_lock_bh(&mvm->queue_info_lock); + if (ac <= mvm->queue_info[queue].mac80211_ac && !force) { + spin_unlock_bh(&mvm->queue_info_lock); + + IWL_DEBUG_TX_QUEUES(mvm, + "No redirection needed on TXQ #%d\n", + queue); + return 0; + } + + cmd.sta_id = mvm->queue_info[queue].ra_sta_id; + cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[mvm->queue_info[queue].mac80211_ac]; + mq = mvm->queue_info[queue].hw_queue_to_mac80211; + shared_queue = (mvm->queue_info[queue].hw_queue_refcount > 1); + spin_unlock_bh(&mvm->queue_info_lock); + + IWL_DEBUG_TX_QUEUES(mvm, "Redirecting shared TXQ #%d to FIFO #%d\n", + queue, iwl_mvm_ac_to_tx_fifo[ac]); + + /* Stop MAC queues and wait for this queue to empty */ + iwl_mvm_stop_mac_queues(mvm, mq); + ret = iwl_trans_wait_tx_queue_empty(mvm->trans, BIT(queue)); + if (ret) { + IWL_ERR(mvm, "Error draining queue %d before reconfig\n", + queue); + ret = -EIO; + goto out; + } + + /* Before redirecting the queue we need to de-activate it */ + iwl_trans_txq_disable(mvm->trans, queue, false); + ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd); + if (ret) + IWL_ERR(mvm, "Failed SCD disable TXQ %d (ret=%d)\n", queue, + ret); + + /* Make sure the SCD wrptr is correctly set before reconfiguring */ + iwl_trans_txq_enable(mvm->trans, queue, iwl_mvm_ac_to_tx_fifo[ac], + cmd.sta_id, tid, LINK_QUAL_AGG_FRAME_LIMIT_DEF, + ssn, wdg_timeout); + + /* TODO: Work-around SCD bug when moving back by multiples of 0x40 */ + + /* Redirect to lower AC */ + iwl_mvm_reconfig_scd(mvm, queue, iwl_mvm_ac_to_tx_fifo[ac], + cmd.sta_id, tid, LINK_QUAL_AGG_FRAME_LIMIT_DEF, + ssn); + + /* Update AC marking of the queue */ + spin_lock_bh(&mvm->queue_info_lock); + mvm->queue_info[queue].mac80211_ac = ac; + spin_unlock_bh(&mvm->queue_info_lock); + + /* + * Mark queue as shared in transport if shared + * Note this has to be done after queue enablement because enablement + * can also set this value, and there is no indication there to shared + * queues + */ + if (shared_queue) + iwl_trans_txq_set_shared_mode(mvm->trans, queue, true); + +out: + /* Continue using the MAC queues */ + iwl_mvm_start_mac_queues(mvm, mq); + + return ret; +} + static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, struct ieee80211_sta *sta, u8 ac, int tid, struct ieee80211_hdr *hdr) @@ -325,11 +623,20 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); u8 mac_queue = mvmsta->vif->hw_queue[ac]; int queue = -1; + bool using_inactive_queue = false; + unsigned long disable_agg_tids = 0; + enum iwl_mvm_agg_state queue_state; + bool shared_queue = false; int ssn; + unsigned long tfd_queue_mask; int ret; lockdep_assert_held(&mvm->mutex); + spin_lock_bh(&mvmsta->lock); + tfd_queue_mask = mvmsta->tfd_queue_msk; + spin_unlock_bh(&mvmsta->lock); + spin_lock_bh(&mvm->queue_info_lock); /* @@ -338,7 +645,8 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, */ if (!ieee80211_is_data_qos(hdr->frame_control) || ieee80211_is_qos_nullfunc(hdr->frame_control)) { - queue = iwl_mvm_find_free_queue(mvm, IWL_MVM_DQA_MIN_MGMT_QUEUE, + queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, + IWL_MVM_DQA_MIN_MGMT_QUEUE, IWL_MVM_DQA_MAX_MGMT_QUEUE); if (queue >= IWL_MVM_DQA_MIN_MGMT_QUEUE) IWL_DEBUG_TX_QUEUES(mvm, "Found free MGMT queue #%d\n", @@ -347,29 +655,62 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, /* If no such queue is found, we'll use a DATA queue instead */ } - if (queue < 0 && mvmsta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) { + if ((queue < 0 && mvmsta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) && + (mvm->queue_info[mvmsta->reserved_queue].status == + IWL_MVM_QUEUE_RESERVED || + mvm->queue_info[mvmsta->reserved_queue].status == + IWL_MVM_QUEUE_INACTIVE)) { queue = mvmsta->reserved_queue; + mvm->queue_info[queue].reserved = true; IWL_DEBUG_TX_QUEUES(mvm, "Using reserved queue #%d\n", queue); } if (queue < 0) - queue = iwl_mvm_find_free_queue(mvm, IWL_MVM_DQA_MIN_DATA_QUEUE, + queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, + IWL_MVM_DQA_MIN_DATA_QUEUE, IWL_MVM_DQA_MAX_DATA_QUEUE); /* + * Check if this queue is already allocated but inactive. + * In such a case, we'll need to first free this queue before enabling + * it again, so we'll mark it as reserved to make sure no new traffic + * arrives on it + */ + if (queue > 0 && + mvm->queue_info[queue].status == IWL_MVM_QUEUE_INACTIVE) { + mvm->queue_info[queue].status = IWL_MVM_QUEUE_RESERVED; + using_inactive_queue = true; + IWL_DEBUG_TX_QUEUES(mvm, + "Re-assigning TXQ %d: sta_id=%d, tid=%d\n", + queue, mvmsta->sta_id, tid); + } + + /* No free queue - we'll have to share */ + if (queue <= 0) { + queue = iwl_mvm_get_shared_queue(mvm, tfd_queue_mask, ac); + if (queue > 0) { + shared_queue = true; + mvm->queue_info[queue].status = IWL_MVM_QUEUE_SHARED; + } + } + + /* * Mark TXQ as ready, even though it hasn't been fully configured yet, * to make sure no one else takes it. * This will allow avoiding re-acquiring the lock at the end of the * configuration. On error we'll mark it back as free. */ - if (queue >= 0) + if ((queue > 0) && !shared_queue) mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY; spin_unlock_bh(&mvm->queue_info_lock); - /* TODO: support shared queues for same RA */ - if (queue < 0) + /* This shouldn't happen - out of queues */ + if (WARN_ON(queue <= 0)) { + IWL_ERR(mvm, "No available queues for tid %d on sta_id %d\n", + tid, cfg.sta_id); return -ENOSPC; + } /* * Actual en/disablement of aggregations is through the ADD_STA HCMD, @@ -380,24 +721,103 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, cfg.aggregate = (queue >= IWL_MVM_DQA_MIN_DATA_QUEUE || queue == IWL_MVM_DQA_BSS_CLIENT_QUEUE); - IWL_DEBUG_TX_QUEUES(mvm, "Allocating queue #%d to sta %d on tid %d\n", - queue, mvmsta->sta_id, tid); + /* + * If this queue was previously inactive (idle) - we need to free it + * first + */ + if (using_inactive_queue) { + struct iwl_scd_txq_cfg_cmd cmd = { + .scd_queue = queue, + .enable = 0, + }; + u8 ac; + + disable_agg_tids = iwl_mvm_remove_sta_queue_marking(mvm, queue); + + spin_lock_bh(&mvm->queue_info_lock); + ac = mvm->queue_info[queue].mac80211_ac; + cmd.sta_id = mvm->queue_info[queue].ra_sta_id; + cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[ac]; + spin_unlock_bh(&mvm->queue_info_lock); + + /* Disable the queue */ + iwl_mvm_invalidate_sta_queue(mvm, queue, disable_agg_tids, + true); + iwl_trans_txq_disable(mvm->trans, queue, false); + ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), + &cmd); + if (ret) { + IWL_ERR(mvm, + "Failed to free inactive queue %d (ret=%d)\n", + queue, ret); + + /* Re-mark the inactive queue as inactive */ + spin_lock_bh(&mvm->queue_info_lock); + mvm->queue_info[queue].status = IWL_MVM_QUEUE_INACTIVE; + spin_unlock_bh(&mvm->queue_info_lock); + + return ret; + } + } + + IWL_DEBUG_TX_QUEUES(mvm, + "Allocating %squeue #%d to sta %d on tid %d\n", + shared_queue ? "shared " : "", queue, + mvmsta->sta_id, tid); + + if (shared_queue) { + /* Disable any open aggs on this queue */ + disable_agg_tids = iwl_mvm_get_queue_agg_tids(mvm, queue); + + if (disable_agg_tids) { + IWL_DEBUG_TX_QUEUES(mvm, "Disabling aggs on queue %d\n", + queue); + iwl_mvm_invalidate_sta_queue(mvm, queue, + disable_agg_tids, false); + } + } ssn = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); iwl_mvm_enable_txq(mvm, queue, mac_queue, ssn, &cfg, wdg_timeout); + /* + * Mark queue as shared in transport if shared + * Note this has to be done after queue enablement because enablement + * can also set this value, and there is no indication there to shared + * queues + */ + if (shared_queue) + iwl_trans_txq_set_shared_mode(mvm->trans, queue, true); + spin_lock_bh(&mvmsta->lock); mvmsta->tid_data[tid].txq_id = queue; + mvmsta->tid_data[tid].is_tid_active = true; mvmsta->tfd_queue_msk |= BIT(queue); + queue_state = mvmsta->tid_data[tid].state; if (mvmsta->reserved_queue == queue) mvmsta->reserved_queue = IEEE80211_INVAL_HW_QUEUE; spin_unlock_bh(&mvmsta->lock); - ret = iwl_mvm_sta_send_to_fw(mvm, sta, true, STA_MODIFY_QUEUES); - if (ret) - goto out_err; + if (!shared_queue) { + ret = iwl_mvm_sta_send_to_fw(mvm, sta, true, STA_MODIFY_QUEUES); + if (ret) + goto out_err; + + /* If we need to re-enable aggregations... */ + if (queue_state == IWL_AGG_ON) { + ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); + if (ret) + goto out_err; + } + } else { + /* Redirect queue, if needed */ + ret = iwl_mvm_scd_queue_redirect(mvm, queue, tid, ac, ssn, + wdg_timeout, false); + if (ret) + goto out_err; + } return 0; @@ -476,6 +896,9 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk) unsigned long deferred_tid_traffic; int sta_id, tid; + /* Check inactivity of queues */ + iwl_mvm_inactivity_check(mvm); + mutex_lock(&mvm->mutex); /* Go over all stations with deferred traffic */ @@ -505,6 +928,12 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); int queue; + /* + * Check for inactive queues, so we don't reach a situation where we + * can't add a STA due to a shortage in queues that doesn't really exist + */ + iwl_mvm_inactivity_check(mvm); + spin_lock_bh(&mvm->queue_info_lock); /* Make sure we have free resources for this STA */ @@ -514,7 +943,8 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm, IWL_MVM_QUEUE_FREE)) queue = IWL_MVM_DQA_BSS_CLIENT_QUEUE; else - queue = iwl_mvm_find_free_queue(mvm, IWL_MVM_DQA_MIN_DATA_QUEUE, + queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, + IWL_MVM_DQA_MIN_DATA_QUEUE, IWL_MVM_DQA_MAX_DATA_QUEUE); if (queue < 0) { spin_unlock_bh(&mvm->queue_info_lock); @@ -568,8 +998,11 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, mvm_sta->tid_disable_agg = 0xffff; /* No aggs at first */ mvm_sta->tfd_queue_msk = 0; - /* allocate new queues for a TDLS station */ - if (sta->tdls) { + /* + * Allocate new queues for a TDLS station, unless we're in DQA mode, + * and then they'll be allocated dynamically + */ + if (!iwl_mvm_is_dqa_supported(mvm) && sta->tdls) { ret = iwl_mvm_tdls_sta_init(mvm, sta); if (ret) return ret; @@ -633,7 +1066,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, return 0; err: - iwl_mvm_tdls_sta_deinit(mvm, sta); + if (!iwl_mvm_is_dqa_supported(mvm) && sta->tdls) + iwl_mvm_tdls_sta_deinit(mvm, sta); return ret; } @@ -819,8 +1253,9 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, if (iwl_mvm_has_new_rx_api(mvm)) kfree(mvm_sta->dup_data); - if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->ap_sta_id == mvm_sta->sta_id) { + if ((vif->type == NL80211_IFTYPE_STATION && + mvmvif->ap_sta_id == mvm_sta->sta_id) || + iwl_mvm_is_dqa_supported(mvm)){ ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); if (ret) return ret; @@ -838,16 +1273,19 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, if (iwl_mvm_is_dqa_supported(mvm)) iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta); - /* if we are associated - we can't remove the AP STA now */ - if (vif->bss_conf.assoc) - return ret; + if (vif->type == NL80211_IFTYPE_STATION && + mvmvif->ap_sta_id == mvm_sta->sta_id) { + /* if associated - we can't remove the AP STA now */ + if (vif->bss_conf.assoc) + return ret; - /* unassoc - go ahead - remove the AP STA now */ - mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; + /* unassoc - go ahead - remove the AP STA now */ + mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; - /* clear d0i3_ap_sta_id if no longer relevant */ - if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id) - mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; + /* clear d0i3_ap_sta_id if no longer relevant */ + if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id) + mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; + } } /* @@ -885,7 +1323,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, } else { spin_unlock_bh(&mvm_sta->lock); - if (sta->tdls) + if (!iwl_mvm_is_dqa_supported(mvm) && sta->tdls) iwl_mvm_tdls_sta_deinit(mvm, sta); ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); @@ -983,8 +1421,9 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); /* Map Aux queue to fifo - needs to happen before adding Aux station */ - iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, mvm->aux_queue, - IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout); + if (!iwl_mvm_is_dqa_supported(mvm)) + iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, mvm->aux_queue, + IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout); /* Allocate aux station and assign to it the aux queue */ ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue), @@ -992,6 +1431,19 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) if (ret) return ret; + if (iwl_mvm_is_dqa_supported(mvm)) { + struct iwl_trans_txq_scd_cfg cfg = { + .fifo = IWL_MVM_TX_FIFO_MCAST, + .sta_id = mvm->aux_sta.sta_id, + .tid = IWL_MAX_TID_COUNT, + .aggregate = false, + .frame_limit = IWL_FRAME_LIMIT, + }; + + iwl_mvm_enable_txq(mvm, mvm->aux_queue, mvm->aux_queue, 0, &cfg, + wdg_timeout); + } + ret = iwl_mvm_add_int_sta_common(mvm, &mvm->aux_sta, NULL, MAC_INDEX_AUX, 0); @@ -1316,8 +1768,8 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, switch (status & IWL_ADD_STA_STATUS_MASK) { case ADD_STA_SUCCESS: - IWL_DEBUG_INFO(mvm, "RX BA Session %sed in fw\n", - start ? "start" : "stopp"); + IWL_DEBUG_HT(mvm, "RX BA Session %sed in fw\n", + start ? "start" : "stopp"); break; case ADD_STA_IMMEDIATE_BA_FAILURE: IWL_WARN(mvm, "RX BA Session refused by fw\n"); @@ -1372,13 +1824,16 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, * supposed to happen) and we will free the session data while * RX is being processed in parallel */ + IWL_DEBUG_HT(mvm, "Sta %d(%d) is assigned to BAID %d\n", + mvm_sta->sta_id, tid, baid); WARN_ON(rcu_access_pointer(mvm->baid_map[baid])); rcu_assign_pointer(mvm->baid_map[baid], baid_data); - } else if (mvm->rx_ba_sessions > 0) { + } else { u8 baid = mvm_sta->tid_to_baid[tid]; - /* check that restart flow didn't zero the counter */ - mvm->rx_ba_sessions--; + if (mvm->rx_ba_sessions > 0) + /* check that restart flow didn't zero the counter */ + mvm->rx_ba_sessions--; if (!iwl_mvm_has_new_rx_api(mvm)) return 0; @@ -1394,6 +1849,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, del_timer_sync(&baid_data->session_timer); RCU_INIT_POINTER(mvm->baid_map[baid], NULL); kfree_rcu(baid_data, rcu_head); + IWL_DEBUG_HT(mvm, "BAID %d is free\n", baid); } return 0; @@ -1402,8 +1858,8 @@ out_free: return ret; } -static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int tid, u8 queue, bool start) +int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, + int tid, u8 queue, bool start) { struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_add_sta_cmd cmd = {}; @@ -1458,6 +1914,7 @@ const u8 tid_to_mac80211_ac[] = { IEEE80211_AC_VI, IEEE80211_AC_VO, IEEE80211_AC_VO, + IEEE80211_AC_VO, /* We treat MGMT as TID 8, which is set as AC_VO */ }; static const u8 tid_to_ucode_ac[] = { @@ -1512,7 +1969,8 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, txq_id = mvmsta->tid_data[tid].txq_id; if (!iwl_mvm_is_dqa_supported(mvm) || mvm->queue_info[txq_id].status != IWL_MVM_QUEUE_READY) { - txq_id = iwl_mvm_find_free_queue(mvm, mvm->first_agg_queue, + txq_id = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, + mvm->first_agg_queue, mvm->last_agg_queue); if (txq_id < 0) { ret = txq_id; @@ -1907,6 +2365,13 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, key_flags |= cpu_to_le16(STA_KEY_FLG_WEP); memcpy(cmd.key + 3, keyconf->key, keyconf->keylen); break; + case WLAN_CIPHER_SUITE_GCMP_256: + key_flags |= cpu_to_le16(STA_KEY_FLG_KEY_32BYTES); + /* fall through */ + case WLAN_CIPHER_SUITE_GCMP: + key_flags |= cpu_to_le16(STA_KEY_FLG_GCMP); + memcpy(cmd.key, keyconf->key, keyconf->keylen); + break; default: key_flags |= cpu_to_le16(STA_KEY_FLG_EXT); memcpy(cmd.key, keyconf->key, keyconf->keylen); @@ -2035,6 +2500,8 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, 0, NULL, 0, key_offset); break; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index d2c58f134fcf..bbc1cab2c3bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -321,6 +321,9 @@ enum iwl_mvm_agg_state { * Basically when next_reclaimed reaches ssn, we can tell mac80211 that * we are ready to finish the Tx AGG stop / start flow. * @tx_time: medium time consumed by this A-MPDU + * @is_tid_active: has this TID sent traffic in the last + * %IWL_MVM_DQA_QUEUE_TIMEOUT time period. If %txq_id is invalid, this + * field should be ignored. */ struct iwl_mvm_tid_data { struct sk_buff_head deferred_tx_frames; @@ -333,6 +336,7 @@ struct iwl_mvm_tid_data { u16 txq_id; u16 ssn; u16 tx_time; + bool is_tid_active; }; static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) @@ -434,6 +438,7 @@ struct iwl_mvm_sta { bool tlc_amsdu; u8 agg_tids; u8 sleep_tx_count; + u8 avg_energy; }; static inline struct iwl_mvm_sta * @@ -509,6 +514,9 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid); +int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, + int tid, u8 queue, bool start); + int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm); void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 779bafcbc9a1..c6585ab48df3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -138,28 +138,19 @@ static void iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb, protocol = ipv6h->nexthdr; while (protocol != NEXTHDR_NONE && ipv6_ext_hdr(protocol)) { + struct ipv6_opt_hdr *hp; + /* only supported extension headers */ if (protocol != NEXTHDR_ROUTING && protocol != NEXTHDR_HOP && - protocol != NEXTHDR_DEST && - protocol != NEXTHDR_FRAGMENT) { + protocol != NEXTHDR_DEST) { skb_checksum_help(skb); return; } - if (protocol == NEXTHDR_FRAGMENT) { - struct frag_hdr *hp = - OPT_HDR(struct frag_hdr, skb, off); - - protocol = hp->nexthdr; - off += sizeof(struct frag_hdr); - } else { - struct ipv6_opt_hdr *hp = - OPT_HDR(struct ipv6_opt_hdr, skb, off); - - protocol = hp->nexthdr; - off += ipv6_optlen(hp); - } + hp = OPT_HDR(struct ipv6_opt_hdr, skb, off); + protocol = hp->nexthdr; + off += ipv6_optlen(hp); } /* if we get here - protocol now should be TCP/UDP */ #endif @@ -388,6 +379,23 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, tx_cmd->rate_n_flags = cpu_to_le32((u32)rate_plcp | rate_flags); } +static inline void iwl_mvm_set_tx_cmd_pn(struct ieee80211_tx_info *info, + u8 *crypto_hdr) +{ + struct ieee80211_key_conf *keyconf = info->control.hw_key; + u64 pn; + + pn = atomic64_inc_return(&keyconf->tx_pn); + crypto_hdr[0] = pn; + crypto_hdr[2] = 0; + crypto_hdr[3] = 0x20 | (keyconf->keyidx << 6); + crypto_hdr[1] = pn >> 8; + crypto_hdr[4] = pn >> 16; + crypto_hdr[5] = pn >> 24; + crypto_hdr[6] = pn >> 32; + crypto_hdr[7] = pn >> 40; +} + /* * Sets the fields in the Tx cmd that are crypto related */ @@ -405,15 +413,7 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP_256: iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd); - pn = atomic64_inc_return(&keyconf->tx_pn); - crypto_hdr[0] = pn; - crypto_hdr[2] = 0; - crypto_hdr[3] = 0x20 | (keyconf->keyidx << 6); - crypto_hdr[1] = pn >> 8; - crypto_hdr[4] = pn >> 16; - crypto_hdr[5] = pn >> 24; - crypto_hdr[6] = pn >> 32; - crypto_hdr[7] = pn >> 40; + iwl_mvm_set_tx_cmd_pn(info, crypto_hdr); break; case WLAN_CIPHER_SUITE_TKIP: @@ -433,6 +433,18 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); break; + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + /* TODO: Taking the key from the table might introduce a race + * when PTK rekeying is done, having an old packets with a PN + * based on the old key but the message encrypted with a new + * one. + * Need to handle this. + */ + tx_cmd->sec_ctl |= TX_CMD_SEC_GCMP | TC_CMD_SEC_KEY_FROM_TABLE; + tx_cmd->key[0] = keyconf->hw_key_idx; + iwl_mvm_set_tx_cmd_pn(info, crypto_hdr); + break; default: tx_cmd->sec_ctl |= TX_CMD_SEC_EXT; } @@ -534,6 +546,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) * (this is not possible for unicast packets as a TLDS discovery * response are sent without a station entry); otherwise use the * AUX station. + * In DQA mode, if vif is of type STATION and frames are not multicast, + * they should be sent from the BSS queue. For example, TDLS setup + * frames should be sent on this queue, as they go through the AP. */ sta_id = mvm->aux_sta.sta_id; if (info.control.vif) { @@ -551,6 +566,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) if (ap_sta_id != IWL_MVM_STATION_COUNT) sta_id = ap_sta_id; + } else if (iwl_mvm_is_dqa_supported(mvm) && + info.control.vif->type == NL80211_IFTYPE_STATION) { + queue = IWL_MVM_DQA_BSS_CLIENT_QUEUE; } } @@ -884,15 +902,17 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, * nullfunc frames should go to the MGMT queue regardless of QOS */ tid = IWL_MAX_TID_COUNT; - txq_id = mvmsta->tid_data[tid].txq_id; } + if (iwl_mvm_is_dqa_supported(mvm)) + txq_id = mvmsta->tid_data[tid].txq_id; + /* Copy MAC header from skb into command buffer */ memcpy(tx_cmd->hdr, hdr, hdrlen); WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); - if (sta->tdls) { + if (sta->tdls && !iwl_mvm_is_dqa_supported(mvm)) { /* default to TID 0 for non-QoS packets */ u8 tdls_tid = tid == IWL_MAX_TID_COUNT ? 0 : tid; @@ -905,9 +925,12 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, txq_id = mvmsta->tid_data[tid].txq_id; } - if (iwl_mvm_is_dqa_supported(mvm)) { - if (unlikely(mvmsta->tid_data[tid].txq_id == - IEEE80211_INVAL_HW_QUEUE)) { + /* Check if TXQ needs to be allocated or re-activated */ + if (unlikely(txq_id == IEEE80211_INVAL_HW_QUEUE || + !mvmsta->tid_data[tid].is_tid_active) && + iwl_mvm_is_dqa_supported(mvm)) { + /* If TXQ needs to be allocated... */ + if (txq_id == IEEE80211_INVAL_HW_QUEUE) { iwl_mvm_tx_add_stream(mvm, mvmsta, tid, skb); /* @@ -917,11 +940,22 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); spin_unlock(&mvmsta->lock); return 0; + } - txq_id = mvmsta->tid_data[tid].txq_id; + /* If we are here - TXQ exists and needs to be re-activated */ + spin_lock(&mvm->queue_info_lock); + mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_READY; + mvmsta->tid_data[tid].is_tid_active = true; + spin_unlock(&mvm->queue_info_lock); + + IWL_DEBUG_TX_QUEUES(mvm, "Re-activating queue %d for TX\n", + txq_id); } + /* Keep track of the time of the last frame for this RA/TID */ + mvm->queue_info[txq_id].last_frame_time[tid] = jiffies; + IWL_DEBUG_TX(mvm, "TX to [%d|%d] Q:%d - seq: 0x%x\n", mvmsta->sta_id, tid, txq_id, IEEE80211_SEQ_TO_SN(seq_number)); @@ -1313,7 +1347,15 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, bool send_eosp_ndp = false; spin_lock_bh(&mvmsta->lock); - txq_agg = (mvmsta->tid_data[tid].state == IWL_AGG_ON); + if (iwl_mvm_is_dqa_supported(mvm)) { + enum iwl_mvm_agg_state state; + + state = mvmsta->tid_data[tid].state; + txq_agg = (state == IWL_AGG_ON || + state == IWL_EMPTYING_HW_QUEUE_DELBA); + } else { + txq_agg = txq_id >= mvm->first_agg_queue; + } if (!is_ndp) { tid_data->next_reclaimed = next_reclaimed; @@ -1644,7 +1686,7 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) iwl_mvm_tx_info_from_ba_notif(&ba_info, ba_notif, tid_data); IWL_DEBUG_TX_REPLY(mvm, "No reclaim. Update rs directly\n"); - iwl_mvm_rs_tx_status(mvm, sta, tid, &ba_info); + iwl_mvm_rs_tx_status(mvm, sta, tid, &ba_info, false); } out: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 161b99efd63d..68f4e7fdfc11 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -579,17 +579,29 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) iwl_mvm_dump_umac_error_log(mvm); } -int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 minq, u8 maxq) +int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq) { int i; lockdep_assert_held(&mvm->queue_info_lock); + /* Start by looking for a free queue */ for (i = minq; i <= maxq; i++) if (mvm->queue_info[i].hw_queue_refcount == 0 && mvm->queue_info[i].status == IWL_MVM_QUEUE_FREE) return i; + /* + * If no free queue found - settle for an inactive one to reconfigure + * Make sure that the inactive queue either already belongs to this STA, + * or that if it belongs to another one - it isn't the reserved queue + */ + for (i = minq; i <= maxq; i++) + if (mvm->queue_info[i].status == IWL_MVM_QUEUE_INACTIVE && + (sta_id == mvm->queue_info[i].ra_sta_id || + !mvm->queue_info[i].reserved)) + return i; + return -ENOSPC; } @@ -643,13 +655,21 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, } /* Update mappings and refcounts */ + if (mvm->queue_info[queue].hw_queue_refcount > 0) + enable_queue = false; + mvm->queue_info[queue].hw_queue_to_mac80211 |= BIT(mac80211_queue); mvm->queue_info[queue].hw_queue_refcount++; - if (mvm->queue_info[queue].hw_queue_refcount > 1) - enable_queue = false; - else - mvm->queue_info[queue].ra_sta_id = cfg->sta_id; mvm->queue_info[queue].tid_bitmap |= BIT(cfg->tid); + mvm->queue_info[queue].ra_sta_id = cfg->sta_id; + + if (enable_queue) { + if (cfg->tid != IWL_MAX_TID_COUNT) + mvm->queue_info[queue].mac80211_ac = + tid_to_mac80211_ac[cfg->tid]; + else + mvm->queue_info[queue].mac80211_ac = IEEE80211_AC_VO; + } IWL_DEBUG_TX_QUEUES(mvm, "Enabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n", @@ -671,6 +691,10 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, .tid = cfg->tid, }; + /* Set sta_id in the command, if it exists */ + if (iwl_mvm_is_dqa_supported(mvm)) + cmd.sta_id = cfg->sta_id; + iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL, wdg_timeout); WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), @@ -752,6 +776,9 @@ void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, mvm->queue_info[queue].tid_bitmap = 0; mvm->queue_info[queue].hw_queue_to_mac80211 = 0; + /* Regardless if this is a reserved TXQ for a STA - mark it as false */ + mvm->queue_info[queue].reserved = false; + spin_unlock_bh(&mvm->queue_info_lock); iwl_trans_txq_disable(mvm->trans, queue, false); @@ -1039,6 +1066,155 @@ out: ieee80211_connection_loss(vif); } +/* + * Remove inactive TIDs of a given queue. + * If all queue TIDs are inactive - mark the queue as inactive + * If only some the queue TIDs are inactive - unmap them from the queue + */ +static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvmsta, int queue, + unsigned long tid_bitmap) +{ + int tid; + + lockdep_assert_held(&mvmsta->lock); + lockdep_assert_held(&mvm->queue_info_lock); + + /* Go over all non-active TIDs, incl. IWL_MAX_TID_COUNT (for mgmt) */ + for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { + /* If some TFDs are still queued - don't mark TID as inactive */ + if (iwl_mvm_tid_queued(&mvmsta->tid_data[tid])) + tid_bitmap &= ~BIT(tid); + } + + /* If all TIDs in the queue are inactive - mark queue as inactive. */ + if (tid_bitmap == mvm->queue_info[queue].tid_bitmap) { + mvm->queue_info[queue].status = IWL_MVM_QUEUE_INACTIVE; + + for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) + mvmsta->tid_data[tid].is_tid_active = false; + + IWL_DEBUG_TX_QUEUES(mvm, "Queue %d marked as inactive\n", + queue); + return; + } + + /* + * If we are here, this is a shared queue and not all TIDs timed-out. + * Remove the ones that did. + */ + for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { + int mac_queue = mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]; + + mvmsta->tid_data[tid].txq_id = IEEE80211_INVAL_HW_QUEUE; + mvm->queue_info[queue].hw_queue_to_mac80211 &= ~BIT(mac_queue); + mvm->queue_info[queue].hw_queue_refcount--; + mvm->queue_info[queue].tid_bitmap &= ~BIT(tid); + mvmsta->tid_data[tid].is_tid_active = false; + + IWL_DEBUG_TX_QUEUES(mvm, + "Removing inactive TID %d from shared Q:%d\n", + tid, queue); + } + + IWL_DEBUG_TX_QUEUES(mvm, + "TXQ #%d left with tid bitmap 0x%x\n", queue, + mvm->queue_info[queue].tid_bitmap); + + /* + * There may be different TIDs with the same mac queues, so make + * sure all TIDs have existing corresponding mac queues enabled + */ + tid_bitmap = mvm->queue_info[queue].tid_bitmap; + for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { + mvm->queue_info[queue].hw_queue_to_mac80211 |= + BIT(mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]); + } + + /* TODO: if queue was shared - need to re-enable AGGs */ +} + +void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) +{ + unsigned long timeout_queues_map = 0; + unsigned long now = jiffies; + int i; + + spin_lock_bh(&mvm->queue_info_lock); + for (i = 0; i < IWL_MAX_HW_QUEUES; i++) + if (mvm->queue_info[i].hw_queue_refcount > 0) + timeout_queues_map |= BIT(i); + spin_unlock_bh(&mvm->queue_info_lock); + + rcu_read_lock(); + + /* + * If a queue time outs - mark it as INACTIVE (don't remove right away + * if we don't have to.) This is an optimization in case traffic comes + * later, and we don't HAVE to use a currently-inactive queue + */ + for_each_set_bit(i, &timeout_queues_map, IWL_MAX_HW_QUEUES) { + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + u8 sta_id; + int tid; + unsigned long inactive_tid_bitmap = 0; + unsigned long queue_tid_bitmap; + + spin_lock_bh(&mvm->queue_info_lock); + queue_tid_bitmap = mvm->queue_info[i].tid_bitmap; + + /* If TXQ isn't in active use anyway - nothing to do here... */ + if (mvm->queue_info[i].status != IWL_MVM_QUEUE_READY && + mvm->queue_info[i].status != IWL_MVM_QUEUE_SHARED) { + spin_unlock_bh(&mvm->queue_info_lock); + continue; + } + + /* Check to see if there are inactive TIDs on this queue */ + for_each_set_bit(tid, &queue_tid_bitmap, + IWL_MAX_TID_COUNT + 1) { + if (time_after(mvm->queue_info[i].last_frame_time[tid] + + IWL_MVM_DQA_QUEUE_TIMEOUT, now)) + continue; + + inactive_tid_bitmap |= BIT(tid); + } + spin_unlock_bh(&mvm->queue_info_lock); + + /* If all TIDs are active - finish check on this queue */ + if (!inactive_tid_bitmap) + continue; + + /* + * If we are here - the queue hadn't been served recently and is + * in use + */ + + sta_id = mvm->queue_info[i].ra_sta_id; + sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); + + /* + * If the STA doesn't exist anymore, it isn't an error. It could + * be that it was removed since getting the queues, and in this + * case it should've inactivated its queues anyway. + */ + if (IS_ERR_OR_NULL(sta)) + continue; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + + spin_lock_bh(&mvmsta->lock); + spin_lock(&mvm->queue_info_lock); + iwl_mvm_remove_inactive_tids(mvm, mvmsta, i, + inactive_tid_bitmap); + spin_unlock(&mvm->queue_info_lock); + spin_unlock_bh(&mvmsta->lock); + } + + rcu_read_unlock(); +} + int iwl_mvm_send_lqm_cmd(struct ieee80211_vif *vif, enum iwl_lqm_cmd_operatrions operation, u32 duration, u32 timeout) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index a588b05e38eb..78cf9a7f3eac 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -433,6 +433,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* 8000 Series */ {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x1010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x10B0, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0130, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x1130, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0132, iwl8260_2ac_cfg)}, @@ -454,6 +455,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24F3, 0xD010, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0xC050, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0xD050, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0xD0B0, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0xB0B0, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x8010, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x8110, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x9010, iwl8260_2ac_cfg)}, @@ -481,6 +484,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24FD, 0x0010, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x0110, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x1110, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x1130, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x0130, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x1010, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x0050, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x0150, iwl8265_2ac_cfg)}, @@ -491,6 +496,10 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24FD, 0x0810, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x9110, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x8130, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x0910, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x0930, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x0950, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x0850, iwl8265_2ac_cfg)}, /* 9000 Series */ {IWL_PCI_DEVICE(0x2526, 0x0000, iwl9260_2ac_cfg)}, @@ -507,6 +516,9 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2526, 0x1420, iwl5165_2ac_cfg)}, {IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl5165_2ac_cfg)}, {IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl5165_2ac_cfg)}, + +/* a000 Series */ + {IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg)}, #endif /* CONFIG_IWLMVM */ {0} @@ -598,7 +610,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) const struct iwl_cfg *cfg_7265d __maybe_unused = NULL; const struct iwl_cfg *cfg_9260lc __maybe_unused = NULL; struct iwl_trans *iwl_trans; - struct iwl_trans_pcie *trans_pcie; int ret; iwl_trans = iwl_trans_pcie_alloc(pdev, ent, cfg); @@ -636,12 +647,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #endif pci_set_drvdata(pdev, iwl_trans); + iwl_trans->drv = iwl_drv_start(iwl_trans, cfg); - trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans); - trans_pcie->drv = iwl_drv_start(iwl_trans, cfg); - - if (IS_ERR(trans_pcie->drv)) { - ret = PTR_ERR(trans_pcie->drv); + if (IS_ERR(iwl_trans->drv)) { + ret = PTR_ERR(iwl_trans->drv); goto out_free_trans; } @@ -680,7 +689,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; out_free_drv: - iwl_drv_stop(trans_pcie->drv); + iwl_drv_stop(iwl_trans->drv); out_free_trans: iwl_trans_pcie_free(iwl_trans); return ret; @@ -689,7 +698,6 @@ out_free_trans: static void iwl_pci_remove(struct pci_dev *pdev) { struct iwl_trans *trans = pci_get_drvdata(pdev); - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); /* if RTPM was in use, restore it to the state before probe */ if (trans->runtime_pm_mode != IWL_PLAT_PM_MODE_DISABLED) { @@ -700,7 +708,7 @@ static void iwl_pci_remove(struct pci_dev *pdev) pm_runtime_forbid(trans->dev); } - iwl_drv_stop(trans_pcie->drv); + iwl_drv_stop(trans->drv); iwl_trans_pcie_free(trans); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index de6974f9c52f..11e347dd44c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -68,12 +68,14 @@ struct iwl_host_cmd; * struct iwl_rx_mem_buffer * @page_dma: bus address of rxb page * @page: driver's pointer to the rxb page + * @invalid: rxb is in driver ownership - not owned by HW * @vid: index of this rxb in the global table */ struct iwl_rx_mem_buffer { dma_addr_t page_dma; struct page *page; u16 vid; + bool invalid; struct list_head list; }; @@ -230,15 +232,16 @@ struct iwl_queue { #define TFD_CMD_SLOTS 32 /* - * The FH will write back to the first TB only, so we need - * to copy some data into the buffer regardless of whether - * it should be mapped or not. This indicates how big the - * first TB must be to include the scratch buffer. Since - * the scratch is 4 bytes at offset 12, it's 16 now. If we - * make it bigger then allocations will be bigger and copy - * slower, so that's probably not useful. + * The FH will write back to the first TB only, so we need to copy some data + * into the buffer regardless of whether it should be mapped or not. + * This indicates how big the first TB must be to include the scratch buffer + * and the assigned PN. + * Since PN location is 16 bytes at offset 24, it's 40 now. + * If we make it bigger then allocations will be bigger and copy slower, so + * that's probably not useful. */ -#define IWL_HCMD_SCRATCHBUF_SIZE 16 +#define IWL_FIRST_TB_SIZE 40 +#define IWL_FIRST_TB_SIZE_ALIGN ALIGN(IWL_FIRST_TB_SIZE, 64) struct iwl_pcie_txq_entry { struct iwl_device_cmd *cmd; @@ -248,20 +251,18 @@ struct iwl_pcie_txq_entry { struct iwl_cmd_meta meta; }; -struct iwl_pcie_txq_scratch_buf { - struct iwl_cmd_header hdr; - u8 buf[8]; - __le32 scratch; +struct iwl_pcie_first_tb_buf { + u8 buf[IWL_FIRST_TB_SIZE_ALIGN]; }; /** * struct iwl_txq - Tx Queue for DMA * @q: generic Rx/Tx queue descriptor * @tfds: transmit frame descriptors (DMA memory) - * @scratchbufs: start of command headers, including scratch buffers, for + * @first_tb_bufs: start of command headers, including scratch buffers, for * the writeback -- this is DMA memory and an array holding one buffer * for each command on the queue - * @scratchbufs_dma: DMA address for the scratchbufs start + * @first_tb_dma: DMA address for the first_tb_bufs start * @entries: transmit entries (driver state) * @lock: queue lock * @stuck_timer: timer that fires if queue gets stuck @@ -279,8 +280,8 @@ struct iwl_pcie_txq_scratch_buf { struct iwl_txq { struct iwl_queue q; struct iwl_tfd *tfds; - struct iwl_pcie_txq_scratch_buf *scratchbufs; - dma_addr_t scratchbufs_dma; + struct iwl_pcie_first_tb_buf *first_tb_bufs; + dma_addr_t first_tb_dma; struct iwl_pcie_txq_entry *entries; spinlock_t lock; unsigned long frozen_expiry_remainder; @@ -296,10 +297,10 @@ struct iwl_txq { }; static inline dma_addr_t -iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) +iwl_pcie_get_first_tb_dma(struct iwl_txq *txq, int idx) { - return txq->scratchbufs_dma + - sizeof(struct iwl_pcie_txq_scratch_buf) * idx; + return txq->first_tb_dma + + sizeof(struct iwl_pcie_first_tb_buf) * idx; } struct iwl_tso_hdr_page { @@ -313,7 +314,6 @@ struct iwl_tso_hdr_page { * @rx_pool: initial pool of iwl_rx_mem_buffer for all the queues * @global_table: table mapping received VID from hw to rxb * @rba: allocator for RX replenishing - * @drv - pointer to iwl_drv * @trans: pointer to the generic transport area * @scd_base_addr: scheduler sram base address in SRAM * @scd_bc_tbls: pointer to the byte count table of the scheduler @@ -351,7 +351,6 @@ struct iwl_trans_pcie { struct iwl_rx_mem_buffer *global_table[RX_POOL_SIZE]; struct iwl_rb_allocator rba; struct iwl_trans *trans; - struct iwl_drv *drv; struct net_device napi_dev; @@ -385,6 +384,8 @@ struct iwl_trans_pcie { wait_queue_head_t wait_command_queue; wait_queue_head_t d0i3_waitq; + u8 page_offs, dev_cmd_offs; + u8 cmd_queue; u8 cmd_fifo; unsigned int cmd_q_wdg_timeout; @@ -471,6 +472,10 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn, unsigned int wdg_timeout); void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue, bool configure_scd); +void iwl_trans_pcie_txq_set_shared_mode(struct iwl_trans *trans, u32 txq_id, + bool shared_mode); +void iwl_trans_pcie_log_scd_error(struct iwl_trans *trans, + struct iwl_txq *txq); int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id); void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans); @@ -496,7 +501,7 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans); /***************************************************** * Helpers ******************************************************/ -static inline void iwl_disable_interrupts(struct iwl_trans *trans) +static inline void _iwl_disable_interrupts(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -519,7 +524,16 @@ static inline void iwl_disable_interrupts(struct iwl_trans *trans) IWL_DEBUG_ISR(trans, "Disabled interrupts\n"); } -static inline void iwl_enable_interrupts(struct iwl_trans *trans) +static inline void iwl_disable_interrupts(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + spin_lock(&trans_pcie->irq_lock); + _iwl_disable_interrupts(trans); + spin_unlock(&trans_pcie->irq_lock); +} + +static inline void _iwl_enable_interrupts(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -542,6 +556,14 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans) } } +static inline void iwl_enable_interrupts(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + spin_lock(&trans_pcie->irq_lock); + _iwl_enable_interrupts(trans); + spin_unlock(&trans_pcie->irq_lock); +} static inline void iwl_enable_hw_int_msk_msix(struct iwl_trans *trans, u32 msk) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -673,4 +695,6 @@ static inline int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) int iwl_pci_fw_exit_d0i3(struct iwl_trans *trans); int iwl_pci_fw_enter_d0i3(struct iwl_trans *trans); +void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable); + #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 0a4a3c502c3c..5c36e6d00622 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -161,21 +161,21 @@ static inline __le32 iwl_pcie_dma_addr2rbd_ptr(dma_addr_t dma_addr) return cpu_to_le32((u32)(dma_addr >> 8)); } -static void iwl_pcie_write_prph_64_no_grab(struct iwl_trans *trans, u64 ofs, - u64 val) -{ - iwl_write_prph_no_grab(trans, ofs, val & 0xffffffff); - iwl_write_prph_no_grab(trans, ofs + 4, val >> 32); -} - /* * iwl_pcie_rx_stop - stops the Rx DMA */ int iwl_pcie_rx_stop(struct iwl_trans *trans) { - iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG, - FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); + if (trans->cfg->mq_rx_supported) { + iwl_write_prph(trans, RFH_RXF_DMA_CFG, 0); + return iwl_poll_prph_bit(trans, RFH_GEN_STATUS, + RXF_DMA_IDLE, RXF_DMA_IDLE, 1000); + } else { + iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG, + FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, + 1000); + } } /* @@ -211,12 +211,8 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, if (trans->cfg->mq_rx_supported) iwl_write32(trans, RFH_Q_FRBDCB_WIDX_TRG(rxq->id), rxq->write_actual); - /* - * write to FH_RSCSR_CHNL0_WPTR register even in MQ as a W/A to - * hardware shadow registers bug - writing to RFH_Q_FRBDCB_WIDX will - * not wake the NIC. - */ - iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual); + else + iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual); } static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans) @@ -237,10 +233,10 @@ static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans) } /* - * iwl_pcie_rxq_mq_restock - restock implementation for multi-queue rx + * iwl_pcie_rxmq_restock - restock implementation for multi-queue rx */ -static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans, - struct iwl_rxq *rxq) +static void iwl_pcie_rxmq_restock(struct iwl_trans *trans, + struct iwl_rxq *rxq) { struct iwl_rx_mem_buffer *rxb; @@ -263,7 +259,7 @@ static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans, rxb = list_first_entry(&rxq->rx_free, struct iwl_rx_mem_buffer, list); list_del(&rxb->list); - + rxb->invalid = false; /* 12 first bits are expected to be empty */ WARN_ON(rxb->page_dma & DMA_BIT_MASK(12)); /* Point to Rx buffer via next RBD in circular buffer */ @@ -285,10 +281,10 @@ static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans, } /* - * iwl_pcie_rxq_sq_restock - restock implementation for single queue rx + * iwl_pcie_rxsq_restock - restock implementation for single queue rx */ -static void iwl_pcie_rxq_sq_restock(struct iwl_trans *trans, - struct iwl_rxq *rxq) +static void iwl_pcie_rxsq_restock(struct iwl_trans *trans, + struct iwl_rxq *rxq) { struct iwl_rx_mem_buffer *rxb; @@ -314,6 +310,7 @@ static void iwl_pcie_rxq_sq_restock(struct iwl_trans *trans, rxb = list_first_entry(&rxq->rx_free, struct iwl_rx_mem_buffer, list); list_del(&rxb->list); + rxb->invalid = false; /* Point to Rx buffer via next RBD in circular buffer */ bd[rxq->write] = iwl_pcie_dma_addr2rbd_ptr(rxb->page_dma); @@ -347,9 +344,9 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq) { if (trans->cfg->mq_rx_supported) - iwl_pcie_rxq_mq_restock(trans, rxq); + iwl_pcie_rxmq_restock(trans, rxq); else - iwl_pcie_rxq_sq_restock(trans, rxq); + iwl_pcie_rxsq_restock(trans, rxq); } /* @@ -764,6 +761,23 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) iwl_set_bit(trans, CSR_INT_COALESCING, IWL_HOST_INT_OPER_MODE); } +void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable) +{ + /* + * Turn on the chicken-bits that cause MAC wakeup for RX-related + * values. + * This costs some power, but needed for W/A 9000 integrated A-step + * bug where shadow registers are not in the retention list and their + * value is lost when NIC powers down + */ + if (trans->cfg->integrated) { + iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, + CSR_MAC_SHADOW_REG_CTRL_RX_WAKE); + iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTL2, + CSR_MAC_SHADOW_REG_CTL2_RX_WAKE); + } +} + static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -796,17 +810,17 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) for (i = 0; i < trans->num_rx_queues; i++) { /* Tell device where to find RBD free table in DRAM */ - iwl_pcie_write_prph_64_no_grab(trans, - RFH_Q_FRBDCB_BA_LSB(i), - trans_pcie->rxq[i].bd_dma); + iwl_write_prph64_no_grab(trans, + RFH_Q_FRBDCB_BA_LSB(i), + trans_pcie->rxq[i].bd_dma); /* Tell device where to find RBD used table in DRAM */ - iwl_pcie_write_prph_64_no_grab(trans, - RFH_Q_URBDCB_BA_LSB(i), - trans_pcie->rxq[i].used_bd_dma); + iwl_write_prph64_no_grab(trans, + RFH_Q_URBDCB_BA_LSB(i), + trans_pcie->rxq[i].used_bd_dma); /* Tell device where in DRAM to update its Rx status */ - iwl_pcie_write_prph_64_no_grab(trans, - RFH_Q_URBD_STTS_WPTR_LSB(i), - trans_pcie->rxq[i].rb_stts_dma); + iwl_write_prph64_no_grab(trans, + RFH_Q_URBD_STTS_WPTR_LSB(i), + trans_pcie->rxq[i].rb_stts_dma); /* Reset device indice tables */ iwl_write_prph_no_grab(trans, RFH_Q_FRBDCB_WIDX(i), 0); iwl_write_prph_no_grab(trans, RFH_Q_FRBDCB_RIDX(i), 0); @@ -815,33 +829,32 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) enabled |= BIT(i) | BIT(i + 16); } - /* restock default queue */ - iwl_pcie_rxq_mq_restock(trans, &trans_pcie->rxq[0]); - /* * Enable Rx DMA - * Single frame mode * Rx buffer size 4 or 8k or 12k * Min RB size 4 or 8 * Drop frames that exceed RB size * 512 RBDs */ iwl_write_prph_no_grab(trans, RFH_RXF_DMA_CFG, - RFH_DMA_EN_ENABLE_VAL | - rb_size | RFH_RXF_DMA_SINGLE_FRAME_MASK | + RFH_DMA_EN_ENABLE_VAL | rb_size | RFH_RXF_DMA_MIN_RB_4_8 | RFH_RXF_DMA_DROP_TOO_LARGE_MASK | RFH_RXF_DMA_RBDCB_SIZE_512); /* * Activate DMA snooping. - * Set RX DMA chunk size to 64B + * Set RX DMA chunk size to 64B for IOSF and 128B for PCIe * Default queue is 0 */ iwl_write_prph_no_grab(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP | (DEFAULT_RXQ_NUM << RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS) | - RFH_GEN_CFG_SERVICE_DMA_SNOOP); + RFH_GEN_CFG_SERVICE_DMA_SNOOP | + (trans->cfg->integrated ? + RFH_GEN_CFG_RB_CHUNK_SIZE_64 : + RFH_GEN_CFG_RB_CHUNK_SIZE_128) << + RFH_GEN_CFG_RB_CHUNK_SIZE_POS); /* Enable the relevant rx queues */ iwl_write_prph_no_grab(trans, RFH_RXF_RXQ_ACTIVE, enabled); @@ -849,6 +862,8 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) /* Set interrupt coalescing timer to default (2048 usecs) */ iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); + + iwl_pcie_enable_rx_wake(trans, true); } static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq) @@ -939,16 +954,18 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) else list_add(&rxb->list, &def_rxq->rx_used); trans_pcie->global_table[i] = rxb; - rxb->vid = (u16)i; + rxb->vid = (u16)(i + 1); + rxb->invalid = true; } iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL, def_rxq); - if (trans->cfg->mq_rx_supported) { + + if (trans->cfg->mq_rx_supported) iwl_pcie_rx_mq_hw_init(trans); - } else { - iwl_pcie_rxq_sq_restock(trans, def_rxq); + else iwl_pcie_rx_hw_init(trans, def_rxq); - } + + iwl_pcie_rxq_restock(trans, def_rxq); spin_lock(&def_rxq->lock); iwl_pcie_rxq_inc_wr_ptr(trans, def_rxq); @@ -1087,6 +1104,9 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID)) break; + WARN_ON((le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_RXQ_MASK) >> + FH_RSCSR_RXQ_POS != rxq->id); + IWL_DEBUG_RX(trans, "cmd at offset %d: %s (0x%.2x, seq 0x%x)\n", rxcb._offset, @@ -1224,10 +1244,19 @@ restart: */ u16 vid = le32_to_cpu(rxq->used_bd[i]) & 0x0FFF; - if (WARN(vid >= ARRAY_SIZE(trans_pcie->global_table), - "Invalid rxb index from HW %u\n", (u32)vid)) + if (WARN(!vid || + vid > ARRAY_SIZE(trans_pcie->global_table), + "Invalid rxb index from HW %u\n", (u32)vid)) { + iwl_force_nmi(trans); + goto out; + } + rxb = trans_pcie->global_table[vid - 1]; + if (WARN(rxb->invalid, + "Invalid rxb from HW %u\n", (u32)vid)) { + iwl_force_nmi(trans); goto out; - rxb = trans_pcie->global_table[vid]; + } + rxb->invalid = true; } else { rxb = rxq->queue[i]; rxq->queue[i] = NULL; @@ -1507,7 +1536,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) * have anything to service */ if (test_bit(STATUS_INT_ENABLED, &trans->status)) - iwl_enable_interrupts(trans); + _iwl_enable_interrupts(trans); spin_unlock(&trans_pcie->irq_lock); lock_map_release(&trans->sync_cmd_lockdep_map); return IRQ_NONE; @@ -1699,15 +1728,17 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) inta & ~trans_pcie->inta_mask); } + spin_lock(&trans_pcie->irq_lock); + /* only Re-enable all interrupt if disabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &trans->status)) + _iwl_enable_interrupts(trans); /* we are loading the firmware, enable FH_TX interrupt only */ - if (handled & CSR_INT_BIT_FH_TX) + else if (handled & CSR_INT_BIT_FH_TX) iwl_enable_fw_load_int(trans); - /* only Re-enable all interrupt if disabled by irq */ - else if (test_bit(STATUS_INT_ENABLED, &trans->status)) - iwl_enable_interrupts(trans); /* Re-enable RF_KILL if it occurred */ else if (handled & CSR_INT_BIT_RF_KILL) iwl_enable_rfkill_int(trans); + spin_unlock(&trans_pcie->irq_lock); out: lock_map_release(&trans->sync_cmd_lockdep_map); @@ -1771,7 +1802,7 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans) return; spin_lock(&trans_pcie->irq_lock); - iwl_disable_interrupts(trans); + _iwl_disable_interrupts(trans); memset(trans_pcie->ict_tbl, 0, ICT_SIZE); @@ -1787,7 +1818,7 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans) trans_pcie->use_ict = true; trans_pcie->ict_index = 0; iwl_write32(trans, CSR_INT, trans_pcie->inta_mask); - iwl_enable_interrupts(trans); + _iwl_enable_interrupts(trans); spin_unlock(&trans_pcie->irq_lock); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index f603d7830a6b..74f2f035bd28 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -608,18 +608,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) /* * ucode */ -static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr, - dma_addr_t phy_addr, u32 byte_cnt) +static void iwl_pcie_load_firmware_chunk_fh(struct iwl_trans *trans, + u32 dst_addr, dma_addr_t phy_addr, + u32 byte_cnt) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - unsigned long flags; - int ret; - - trans_pcie->ucode_write_complete = false; - - if (!iwl_trans_grab_nic_access(trans, &flags)) - return -EIO; - iwl_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); @@ -642,7 +634,50 @@ static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr, FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); +} + +static void iwl_pcie_load_firmware_chunk_tfh(struct iwl_trans *trans, + u32 dst_addr, dma_addr_t phy_addr, + u32 byte_cnt) +{ + /* Stop DMA channel */ + iwl_write32(trans, TFH_SRV_DMA_CHNL0_CTRL, 0); + + /* Configure SRAM address */ + iwl_write32(trans, TFH_SRV_DMA_CHNL0_SRAM_ADDR, + dst_addr); + + /* Configure DRAM address - 64 bit */ + iwl_write64(trans, TFH_SRV_DMA_CHNL0_DRAM_ADDR, phy_addr); + + /* Configure byte count to transfer */ + iwl_write32(trans, TFH_SRV_DMA_CHNL0_BC, byte_cnt); + /* Enable the DRAM2SRAM to start */ + iwl_write32(trans, TFH_SRV_DMA_CHNL0_CTRL, TFH_SRV_DMA_SNOOP | + TFH_SRV_DMA_TO_DRIVER | + TFH_SRV_DMA_START); +} + +static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans, + u32 dst_addr, dma_addr_t phy_addr, + u32 byte_cnt) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + unsigned long flags; + int ret; + + trans_pcie->ucode_write_complete = false; + + if (!iwl_trans_grab_nic_access(trans, &flags)) + return -EIO; + + if (trans->cfg->use_tfh) + iwl_pcie_load_firmware_chunk_tfh(trans, dst_addr, phy_addr, + byte_cnt); + else + iwl_pcie_load_firmware_chunk_fh(trans, dst_addr, phy_addr, + byte_cnt); iwl_trans_release_nic_access(trans, &flags); ret = wait_event_timeout(trans_pcie->ucode_write_waitq, @@ -801,6 +836,8 @@ static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans, *first_ucode_section = last_read_idx; + iwl_enable_interrupts(trans); + if (cpu == 1) iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFF); else @@ -980,6 +1017,8 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, iwl_pcie_apply_destination(trans); } + iwl_enable_interrupts(trans); + /* release CPU reset */ iwl_write32(trans, CSR_RESET, 0); @@ -1033,9 +1072,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) was_hw_rfkill = iwl_is_rfkill_set(trans); /* tell the device to stop sending interrupts */ - spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); - spin_unlock(&trans_pcie->irq_lock); /* device going down, Stop using ICT table */ iwl_pcie_disable_ict(trans); @@ -1079,9 +1116,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) * the time, unless the interrupt is ACKed even if the interrupt * should be masked. Re-ACK all the interrupts here. */ - spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); - spin_unlock(&trans_pcie->irq_lock); /* clear all status bits */ clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); @@ -1215,7 +1250,6 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, ret = iwl_pcie_load_given_ucode_8000(trans, fw); else ret = iwl_pcie_load_given_ucode(trans, fw); - iwl_enable_interrupts(trans); /* re-check RF-Kill state since we may have missed the interrupt */ hw_rfkill = iwl_is_rfkill_set(trans); @@ -1286,6 +1320,8 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_pcie_enable_rx_wake(trans, false); + if (reset) { /* * reset TX queues -- some of their registers reset during S3 @@ -1311,6 +1347,8 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, return 0; } + iwl_pcie_enable_rx_wake(trans, true); + /* * Also enables interrupts - none will happen as the device doesn't * know we're waking it up, only when the opmode actually tells it @@ -1389,8 +1427,12 @@ static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie) max_rx_vector = trans_pcie->allocated_vector - 1; - if (!trans_pcie->msix_enabled) + if (!trans_pcie->msix_enabled) { + if (trans->cfg->mq_rx_supported) + iwl_write_prph(trans, UREG_CHICK, + UREG_CHICK_MSI_ENABLE); return; + } iwl_write_prph(trans, UREG_CHICK, UREG_CHICK_MSIX_ENABLE); @@ -1567,15 +1609,11 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) mutex_lock(&trans_pcie->mutex); /* disable interrupts - don't enable HW RF kill interrupt */ - spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); - spin_unlock(&trans_pcie->irq_lock); iwl_pcie_apm_stop(trans, true); - spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); - spin_unlock(&trans_pcie->irq_lock); iwl_pcie_disable_ict(trans); @@ -1639,6 +1677,9 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, trans_pcie->scd_set_active = trans_cfg->scd_set_active; trans_pcie->sw_csum_tx = trans_cfg->sw_csum_tx; + trans_pcie->page_offs = trans_cfg->cb_data_offs; + trans_pcie->dev_cmd_offs = trans_cfg->cb_data_offs + sizeof(void *); + trans->command_groups = trans_cfg->command_groups; trans->command_groups_size = trans_cfg->command_groups_size; @@ -1909,6 +1950,48 @@ static void iwl_trans_pcie_block_txq_ptrs(struct iwl_trans *trans, bool block) #define IWL_FLUSH_WAIT_MS 2000 +void iwl_trans_pcie_log_scd_error(struct iwl_trans *trans, struct iwl_txq *txq) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 scd_sram_addr; + u8 buf[16]; + int cnt; + + IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", + txq->q.read_ptr, txq->q.write_ptr); + + scd_sram_addr = trans_pcie->scd_base_addr + + SCD_TX_STTS_QUEUE_OFFSET(txq->q.id); + iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf)); + + iwl_print_hex_error(trans, buf, sizeof(buf)); + + for (cnt = 0; cnt < FH_TCSR_CHNL_NUM; cnt++) + IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", cnt, + iwl_read_direct32(trans, FH_TX_TRB_REG(cnt))); + + for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) { + u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(cnt)); + u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7; + bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE)); + u32 tbl_dw = + iwl_trans_read_mem32(trans, trans_pcie->scd_base_addr + + SCD_TRANS_TBL_OFFSET_QUEUE(cnt)); + + if (cnt & 0x1) + tbl_dw = (tbl_dw & 0xFFFF0000) >> 16; + else + tbl_dw = tbl_dw & 0x0000FFFF; + + IWL_ERR(trans, + "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n", + cnt, active ? "" : "in", fifo, tbl_dw, + iwl_read_prph(trans, SCD_QUEUE_RDPTR(cnt)) & + (TFD_QUEUE_SIZE_MAX - 1), + iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt))); + } +} + static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -1916,8 +1999,6 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) struct iwl_queue *q; int cnt; unsigned long now = jiffies; - u32 scd_sram_addr; - u8 buf[16]; int ret = 0; /* waiting for all the tx frames complete might take a while */ @@ -1957,42 +2038,8 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) IWL_DEBUG_TX_QUEUES(trans, "Queue %d is now empty.\n", cnt); } - if (!ret) - return 0; - - IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", - txq->q.read_ptr, txq->q.write_ptr); - - scd_sram_addr = trans_pcie->scd_base_addr + - SCD_TX_STTS_QUEUE_OFFSET(txq->q.id); - iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf)); - - iwl_print_hex_error(trans, buf, sizeof(buf)); - - for (cnt = 0; cnt < FH_TCSR_CHNL_NUM; cnt++) - IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", cnt, - iwl_read_direct32(trans, FH_TX_TRB_REG(cnt))); - - for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) { - u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(cnt)); - u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7; - bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE)); - u32 tbl_dw = - iwl_trans_read_mem32(trans, trans_pcie->scd_base_addr + - SCD_TRANS_TBL_OFFSET_QUEUE(cnt)); - - if (cnt & 0x1) - tbl_dw = (tbl_dw & 0xFFFF0000) >> 16; - else - tbl_dw = tbl_dw & 0x0000FFFF; - - IWL_ERR(trans, - "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n", - cnt, active ? "" : "in", fifo, tbl_dw, - iwl_read_prph(trans, SCD_QUEUE_RDPTR(cnt)) & - (TFD_QUEUE_SIZE_MAX - 1), - iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt))); - } + if (ret) + iwl_trans_pcie_log_scd_error(trans, txq); return ret; } @@ -2741,6 +2788,8 @@ static const struct iwl_trans_ops trans_ops_pcie = { .txq_disable = iwl_trans_pcie_txq_disable, .txq_enable = iwl_trans_pcie_txq_enable, + .txq_set_shared_mode = iwl_trans_pcie_txq_set_shared_mode, + .wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty, .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer, .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index d6beac9af029..18650dccdb58 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -70,6 +70,7 @@ * Tx queue resumed. * ***************************************************/ + static int iwl_queue_space(const struct iwl_queue *q) { unsigned int max; @@ -154,10 +155,6 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) struct iwl_txq *txq = (void *)data; struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie); - u32 scd_sram_addr = trans_pcie->scd_base_addr + - SCD_TX_STTS_QUEUE_OFFSET(txq->q.id); - u8 buf[16]; - int i; spin_lock(&txq->lock); /* check if triggered erroneously */ @@ -169,38 +166,8 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id, jiffies_to_msecs(txq->wd_timeout)); - IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", - txq->q.read_ptr, txq->q.write_ptr); - - iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf)); - - iwl_print_hex_error(trans, buf, sizeof(buf)); - - for (i = 0; i < FH_TCSR_CHNL_NUM; i++) - IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", i, - iwl_read_direct32(trans, FH_TX_TRB_REG(i))); - - for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) { - u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(i)); - u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7; - bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE)); - u32 tbl_dw = - iwl_trans_read_mem32(trans, - trans_pcie->scd_base_addr + - SCD_TRANS_TBL_OFFSET_QUEUE(i)); - - if (i & 0x1) - tbl_dw = (tbl_dw & 0xFFFF0000) >> 16; - else - tbl_dw = tbl_dw & 0x0000FFFF; - IWL_ERR(trans, - "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n", - i, active ? "" : "in", fifo, tbl_dw, - iwl_read_prph(trans, SCD_QUEUE_RDPTR(i)) & - (TFD_QUEUE_SIZE_MAX - 1), - iwl_read_prph(trans, SCD_QUEUE_WRPTR(i))); - } + iwl_trans_pcie_log_scd_error(trans, txq); iwl_force_nmi(trans); } @@ -393,7 +360,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, return; } - /* first TB is never freed - it's the scratchbuf data */ + /* first TB is never freed - it's the bidirectional DMA data */ for (i = 1; i < num_tbs; i++) { if (meta->flags & BIT(i + CMD_TB_BITMAP_POS)) @@ -491,7 +458,7 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans, { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX; - size_t scratchbuf_sz; + size_t tb0_buf_sz; int i; if (WARN_ON(txq->entries || txq->tfds)) @@ -526,17 +493,14 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans, if (!txq->tfds) goto error; - BUILD_BUG_ON(IWL_HCMD_SCRATCHBUF_SIZE != sizeof(*txq->scratchbufs)); - BUILD_BUG_ON(offsetof(struct iwl_pcie_txq_scratch_buf, scratch) != - sizeof(struct iwl_cmd_header) + - offsetof(struct iwl_tx_cmd, scratch)); + BUILD_BUG_ON(IWL_FIRST_TB_SIZE_ALIGN != sizeof(*txq->first_tb_bufs)); - scratchbuf_sz = sizeof(*txq->scratchbufs) * slots_num; + tb0_buf_sz = sizeof(*txq->first_tb_bufs) * slots_num; - txq->scratchbufs = dma_alloc_coherent(trans->dev, scratchbuf_sz, - &txq->scratchbufs_dma, + txq->first_tb_bufs = dma_alloc_coherent(trans->dev, tb0_buf_sz, + &txq->first_tb_dma, GFP_KERNEL); - if (!txq->scratchbufs) + if (!txq->first_tb_bufs) goto err_free_tfds; txq->q.id = txq_id; @@ -578,22 +542,27 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, * Tell nic where to find circular buffer of Tx Frame Descriptors for * given Tx queue, and enable the DMA channel used for that queue. * Circular buffer (TFD queue in DRAM) physical base address */ - iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id), - txq->q.dma_addr >> 8); + if (trans->cfg->use_tfh) + iwl_write_direct64(trans, + FH_MEM_CBBC_QUEUE(trans, txq_id), + txq->q.dma_addr); + else + iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(trans, txq_id), + txq->q.dma_addr >> 8); return 0; } -static void iwl_pcie_free_tso_page(struct sk_buff *skb) +static void iwl_pcie_free_tso_page(struct iwl_trans_pcie *trans_pcie, + struct sk_buff *skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct page **page_ptr; - if (info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA]) { - struct page *page = - info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA]; + page_ptr = (void *)((u8 *)skb->cb + trans_pcie->page_offs); - __free_page(page); - info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA] = NULL; + if (*page_ptr) { + __free_page(*page_ptr); + *page_ptr = NULL; } } @@ -639,7 +608,7 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) if (WARN_ON_ONCE(!skb)) continue; - iwl_pcie_free_tso_page(skb); + iwl_pcie_free_tso_page(trans_pcie, skb); } iwl_pcie_txq_free_tfd(trans, txq); q->read_ptr = iwl_queue_inc_wrap(q->read_ptr); @@ -708,8 +677,8 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) txq->tfds = NULL; dma_free_coherent(dev, - sizeof(*txq->scratchbufs) * txq->q.n_window, - txq->scratchbufs, txq->scratchbufs_dma); + sizeof(*txq->first_tb_bufs) * txq->q.n_window, + txq->first_tb_bufs, txq->first_tb_dma); } kfree(txq->entries); @@ -786,9 +755,14 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; txq_id++) { struct iwl_txq *txq = &trans_pcie->txq[txq_id]; - - iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id), - txq->q.dma_addr >> 8); + if (trans->cfg->use_tfh) + iwl_write_direct64(trans, + FH_MEM_CBBC_QUEUE(trans, txq_id), + txq->q.dma_addr); + else + iwl_write_direct32(trans, + FH_MEM_CBBC_QUEUE(trans, txq_id), + txq->q.dma_addr >> 8); iwl_pcie_txq_unmap(trans, txq_id); txq->q.read_ptr = 0; txq->q.write_ptr = 0; @@ -996,6 +970,12 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) } } + if (trans->cfg->use_tfh) + iwl_write_direct32(trans, TFH_TRANSFER_MODE, + TFH_TRANSFER_MAX_PENDING_REQ | + TFH_CHUNK_SIZE_128 | + TFH_CHUNK_SPLIT_MODE); + iwl_set_bits_prph(trans, SCD_GP_CTRL, SCD_GP_CTRL_AUTO_ACTIVE_MODE); if (trans->cfg->base_params->num_of_queues > 20) iwl_set_bits_prph(trans, SCD_GP_CTRL, @@ -1084,7 +1064,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, if (WARN_ON_ONCE(!skb)) continue; - iwl_pcie_free_tso_page(skb); + iwl_pcie_free_tso_page(trans_pcie, skb); __skb_queue_tail(skbs, skb); @@ -1115,17 +1095,17 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, while (!skb_queue_empty(&overflow_skbs)) { struct sk_buff *skb = __skb_dequeue(&overflow_skbs); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - u8 dev_cmd_idx = IWL_TRANS_FIRST_DRIVER_DATA + 1; - struct iwl_device_cmd *dev_cmd = - info->driver_data[dev_cmd_idx]; + struct iwl_device_cmd *dev_cmd_ptr; + + dev_cmd_ptr = *(void **)((u8 *)skb->cb + + trans_pcie->dev_cmd_offs); /* * Note that we can very well be overflowing again. * In that case, iwl_queue_space will be small again * and we won't wake mac80211's queue. */ - iwl_trans_pcie_tx(trans, skb, dev_cmd, txq_id); + iwl_trans_pcie_tx(trans, skb, dev_cmd_ptr, txq_id); } spin_lock_bh(&txq->lock); @@ -1354,6 +1334,15 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, txq->active = true; } +void iwl_trans_pcie_txq_set_shared_mode(struct iwl_trans *trans, u32 txq_id, + bool shared_mode) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + + txq->ampdu = !shared_mode; +} + void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, bool configure_scd) { @@ -1413,7 +1402,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, void *dup_buf = NULL; dma_addr_t phys_addr; int idx; - u16 copy_size, cmd_size, scratch_size; + u16 copy_size, cmd_size, tb0_size; bool had_nocopy = false; u8 group_id = iwl_cmd_groupid(cmd->id); int i, ret; @@ -1444,9 +1433,9 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, if (!cmd->len[i]) continue; - /* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */ - if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) { - int copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size; + /* need at least IWL_FIRST_TB_SIZE copied */ + if (copy_size < IWL_FIRST_TB_SIZE) { + int copy = IWL_FIRST_TB_SIZE - copy_size; if (copy > cmdlen[i]) copy = cmdlen[i]; @@ -1567,8 +1556,8 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, } /* - * Otherwise we need at least IWL_HCMD_SCRATCHBUF_SIZE copied - * in total (for the scratchbuf handling), but copy up to what + * Otherwise we need at least IWL_FIRST_TB_SIZE copied + * in total (for bi-directional DMA), but copy up to what * we can fit into the payload for debug dump purposes. */ copy = min_t(int, TFD_MAX_PAYLOAD_SIZE - cmd_pos, cmd->len[i]); @@ -1577,8 +1566,8 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, cmd_pos += copy; /* However, treat copy_size the proper way, we need it below */ - if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) { - copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size; + if (copy_size < IWL_FIRST_TB_SIZE) { + copy = IWL_FIRST_TB_SIZE - copy_size; if (copy > cmd->len[i]) copy = cmd->len[i]; @@ -1593,18 +1582,18 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, le16_to_cpu(out_cmd->hdr.sequence), cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue); - /* start the TFD with the scratchbuf */ - scratch_size = min_t(int, copy_size, IWL_HCMD_SCRATCHBUF_SIZE); - memcpy(&txq->scratchbufs[q->write_ptr], &out_cmd->hdr, scratch_size); + /* start the TFD with the minimum copy bytes */ + tb0_size = min_t(int, copy_size, IWL_FIRST_TB_SIZE); + memcpy(&txq->first_tb_bufs[idx], &out_cmd->hdr, tb0_size); iwl_pcie_txq_build_tfd(trans, txq, - iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr), - scratch_size, true); + iwl_pcie_get_first_tb_dma(txq, idx), + tb0_size, true); /* map first command fragment, if any remains */ - if (copy_size > scratch_size) { + if (copy_size > tb0_size) { phys_addr = dma_map_single(trans->dev, - ((u8 *)&out_cmd->hdr) + scratch_size, - copy_size - scratch_size, + ((u8 *)&out_cmd->hdr) + tb0_size, + copy_size - tb0_size, DMA_TO_DEVICE); if (dma_mapping_error(trans->dev, phys_addr)) { iwl_pcie_tfd_unmap(trans, out_meta, @@ -1614,7 +1603,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, } iwl_pcie_txq_build_tfd(trans, txq, phys_addr, - copy_size - scratch_size, false); + copy_size - tb0_size, false); } /* map the remaining (adjusted) nocopy/dup fragments */ @@ -1959,7 +1948,7 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, trace_iwlwifi_dev_tx(trans->dev, skb, &txq->tfds[txq->q.write_ptr], sizeof(struct iwl_tfd), - &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len, + &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, skb->data + hdr_len, tb2_len); trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len, skb->len - hdr_len); @@ -2015,7 +2004,6 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_cmd_meta *out_meta, struct iwl_device_cmd *dev_cmd, u16 tb1_len) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; struct ieee80211_hdr *hdr = (void *)skb->data; unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; @@ -2024,6 +2012,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, u16 length, iv_len, amsdu_pad; u8 *start_hdr; struct iwl_tso_hdr_page *hdr_page; + struct page **page_ptr; int ret; struct tso_t tso; @@ -2035,7 +2024,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, trace_iwlwifi_dev_tx(trans->dev, skb, &txq->tfds[txq->q.write_ptr], sizeof(struct iwl_tfd), - &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len, + &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, NULL, 0); ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb); @@ -2054,7 +2043,8 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, get_page(hdr_page->page); start_hdr = hdr_page->pos; - info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA] = hdr_page->page; + page_ptr = (void *)((u8 *)skb->cb + trans_pcie->page_offs); + *page_ptr = hdr_page->page; memcpy(hdr_page->pos, skb->data + hdr_len, iv_len); hdr_page->pos += iv_len; @@ -2264,10 +2254,12 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* don't put the packet on the ring, if there is no room */ if (unlikely(iwl_queue_space(q) < 3)) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct iwl_device_cmd **dev_cmd_ptr; + + dev_cmd_ptr = (void *)((u8 *)skb->cb + + trans_pcie->dev_cmd_offs); - info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA + 1] = - dev_cmd; + *dev_cmd_ptr = dev_cmd; __skb_queue_tail(&txq->overflow_q, skb); spin_unlock(&txq->lock); @@ -2294,7 +2286,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | INDEX_TO_SEQ(q->write_ptr))); - tb0_phys = iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr); + tb0_phys = iwl_pcie_get_first_tb_dma(txq, q->write_ptr); scratch_phys = tb0_phys + sizeof(struct iwl_cmd_header) + offsetof(struct iwl_tx_cmd, scratch); @@ -2312,7 +2304,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, * setup of the first TB) */ len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + - hdr_len - IWL_HCMD_SCRATCHBUF_SIZE; + hdr_len - IWL_FIRST_TB_SIZE; /* do not align A-MSDU to dword as the subframe header aligns it */ amsdu = ieee80211_is_data_qos(fc) && (*ieee80211_get_qos_ctl(hdr) & @@ -2326,17 +2318,17 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, tb1_len = len; } - /* The first TB points to the scratchbuf data - min_copy bytes */ - memcpy(&txq->scratchbufs[q->write_ptr], &dev_cmd->hdr, - IWL_HCMD_SCRATCHBUF_SIZE); + /* The first TB points to bi-directional DMA data */ + memcpy(&txq->first_tb_bufs[q->write_ptr], &dev_cmd->hdr, + IWL_FIRST_TB_SIZE); iwl_pcie_txq_build_tfd(trans, txq, tb0_phys, - IWL_HCMD_SCRATCHBUF_SIZE, true); + IWL_FIRST_TB_SIZE, true); /* there must be data left over for TB1 or this code must be changed */ - BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_HCMD_SCRATCHBUF_SIZE); + BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_FIRST_TB_SIZE); /* map the data for TB1 */ - tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_HCMD_SCRATCHBUF_SIZE; + tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_FIRST_TB_SIZE; tb1_phys = dma_map_single(trans->dev, tb1_addr, tb1_len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(trans->dev, tb1_phys))) goto out_err; diff --git a/drivers/net/wireless/intersil/orinoco/scan.c b/drivers/net/wireless/intersil/orinoco/scan.c index d0ceb06c72d0..6d1d084854fb 100644 --- a/drivers/net/wireless/intersil/orinoco/scan.c +++ b/drivers/net/wireless/intersil/orinoco/scan.c @@ -237,7 +237,11 @@ void orinoco_add_hostscan_results(struct orinoco_private *priv, scan_abort: if (priv->scan_request) { - cfg80211_scan_done(priv->scan_request, abort); + struct cfg80211_scan_info info = { + .aborted = abort, + }; + + cfg80211_scan_done(priv->scan_request, &info); priv->scan_request = NULL; } } @@ -245,7 +249,11 @@ void orinoco_add_hostscan_results(struct orinoco_private *priv, void orinoco_scan_done(struct orinoco_private *priv, bool abort) { if (priv->scan_request) { - cfg80211_scan_done(priv->scan_request, abort); + struct cfg80211_scan_info info = { + .aborted = abort, + }; + + cfg80211_scan_done(priv->scan_request, &info); priv->scan_request = NULL; } } diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 4dd5adcdd29b..8c35ac838fce 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -30,6 +30,8 @@ #include <linux/module.h> #include <linux/ktime.h> #include <net/genetlink.h> +#include <net/net_namespace.h> +#include <net/netns/generic.h> #include "mac80211_hwsim.h" #define WARN_QUEUE 100 @@ -39,8 +41,6 @@ MODULE_AUTHOR("Jouni Malinen"); MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); MODULE_LICENSE("GPL"); -static u32 wmediumd_portid; - static int radios = 2; module_param(radios, int, 0444); MODULE_PARM_DESC(radios, "Number of simulated radios"); @@ -250,6 +250,43 @@ static inline void hwsim_clear_chanctx_magic(struct ieee80211_chanctx_conf *c) cp->magic = 0; } +static int hwsim_net_id; + +static int hwsim_netgroup; + +struct hwsim_net { + int netgroup; + u32 wmediumd; +}; + +static inline int hwsim_net_get_netgroup(struct net *net) +{ + struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); + + return hwsim_net->netgroup; +} + +static inline void hwsim_net_set_netgroup(struct net *net) +{ + struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); + + hwsim_net->netgroup = hwsim_netgroup++; +} + +static inline u32 hwsim_net_get_wmediumd(struct net *net) +{ + struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); + + return hwsim_net->wmediumd; +} + +static inline void hwsim_net_set_wmediumd(struct net *net, u32 portid) +{ + struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); + + hwsim_net->wmediumd = portid; +} + static struct class *hwsim_class; static struct net_device *hwsim_mon; /* global monitor netdev */ @@ -420,10 +457,6 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = { { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) } }; -static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = { - { .max = 8, .types = BIT(NL80211_IFTYPE_AP) }, -}; - static const struct ieee80211_iface_combination hwsim_if_comb[] = { { .limits = hwsim_if_limits, @@ -431,18 +464,12 @@ static const struct ieee80211_iface_combination hwsim_if_comb[] = { .n_limits = ARRAY_SIZE(hwsim_if_limits) - 1, .max_interfaces = 2048, .num_different_channels = 1, - }, - { - .limits = hwsim_if_dfs_limits, - .n_limits = ARRAY_SIZE(hwsim_if_dfs_limits), - .max_interfaces = 8, - .num_different_channels = 1, .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | BIT(NL80211_CHAN_WIDTH_40) | BIT(NL80211_CHAN_WIDTH_80) | BIT(NL80211_CHAN_WIDTH_160), - } + }, }; static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = { @@ -451,18 +478,12 @@ static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = { .n_limits = ARRAY_SIZE(hwsim_if_limits), .max_interfaces = 2048, .num_different_channels = 1, - }, - { - .limits = hwsim_if_dfs_limits, - .n_limits = ARRAY_SIZE(hwsim_if_dfs_limits), - .max_interfaces = 8, - .num_different_channels = 1, .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | BIT(NL80211_CHAN_WIDTH_40) | BIT(NL80211_CHAN_WIDTH_80) | BIT(NL80211_CHAN_WIDTH_160), - } + }, }; static spinlock_t hwsim_radio_lock; @@ -526,6 +547,11 @@ struct mac80211_hwsim_data { */ u64 group; + /* group shared by radios created in the same netns */ + int netgroup; + /* wmediumd portid responsible for netgroup of this radio */ + u32 wmediumd; + int power_level; /* difference between this hw's clock and the real clock, in usecs */ @@ -568,6 +594,7 @@ static struct genl_family hwsim_genl_family = { .name = "MAC80211_HWSIM", .version = 1, .maxattr = HWSIM_ATTR_MAX, + .netnsok = true, }; enum hwsim_multicast_groups { @@ -955,6 +982,29 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, return true; } +static int hwsim_unicast_netgroup(struct mac80211_hwsim_data *data, + struct sk_buff *skb, int portid) +{ + struct net *net; + bool found = false; + int res = -ENOENT; + + rcu_read_lock(); + for_each_net_rcu(net) { + if (data->netgroup == hwsim_net_get_netgroup(net)) { + res = genlmsg_unicast(net, skb, portid); + found = true; + break; + } + } + rcu_read_unlock(); + + if (!found) + nlmsg_free(skb); + + return res; +} + static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, struct sk_buff *my_skb, int dst_portid) @@ -1034,7 +1084,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, goto nla_put_failure; genlmsg_end(skb, msg_head); - if (genlmsg_unicast(&init_net, skb, dst_portid)) + if (hwsim_unicast_netgroup(data, skb, dst_portid)) goto err_free_txskb; /* Enqueue the packet */ @@ -1202,6 +1252,9 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, if (!(data->group & data2->group)) continue; + if (data->netgroup != data2->netgroup) + continue; + if (!hwsim_chans_compat(chan, data2->tmp_chan) && !hwsim_chans_compat(chan, data2->channel)) { ieee80211_iterate_active_interfaces_atomic( @@ -1324,7 +1377,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, mac80211_hwsim_monitor_rx(hw, skb, channel); /* wmediumd mode check */ - _portid = ACCESS_ONCE(wmediumd_portid); + _portid = ACCESS_ONCE(data->wmediumd); if (_portid) return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); @@ -1420,7 +1473,8 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_channel *chan) { - u32 _pid = ACCESS_ONCE(wmediumd_portid); + struct mac80211_hwsim_data *data = hw->priv; + u32 _pid = ACCESS_ONCE(data->wmediumd); if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) { struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); @@ -1887,8 +1941,12 @@ static void hw_scan_work(struct work_struct *work) mutex_lock(&hwsim->mutex); if (hwsim->scan_chan_idx >= req->n_channels) { + struct cfg80211_scan_info info = { + .aborted = false, + }; + wiphy_debug(hwsim->hw->wiphy, "hw scan complete\n"); - ieee80211_scan_completed(hwsim->hw, false); + ieee80211_scan_completed(hwsim->hw, &info); hwsim->hw_scan_request = NULL; hwsim->hw_scan_vif = NULL; hwsim->tmp_chan = NULL; @@ -1973,13 +2031,16 @@ static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mac80211_hwsim_data *hwsim = hw->priv; + struct cfg80211_scan_info info = { + .aborted = true, + }; wiphy_debug(hw->wiphy, "hwsim cancel_hw_scan\n"); cancel_delayed_work_sync(&hwsim->hw_scan); mutex_lock(&hwsim->mutex); - ieee80211_scan_completed(hwsim->hw, true); + ieee80211_scan_completed(hwsim->hw, &info); hwsim->tmp_chan = NULL; hwsim->hw_scan_request = NULL; hwsim->hw_scan_vif = NULL; @@ -2349,6 +2410,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, struct ieee80211_hw *hw; enum nl80211_band band; const struct ieee80211_ops *ops = &mac80211_hwsim_ops; + struct net *net; int idx; if (WARN_ON(param->channels > 1 && !param->use_chanctx)) @@ -2366,6 +2428,13 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, err = -ENOMEM; goto failed; } + + if (info) + net = genl_info_net(info); + else + net = &init_net; + wiphy_net_set(hw->wiphy, net); + data = hw->priv; data->hw = hw; @@ -2409,13 +2478,14 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, hw->wiphy->max_scan_ssids = 255; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; hw->wiphy->max_remain_on_channel_duration = 1000; - /* For channels > 1 DFS is not allowed */ - hw->wiphy->n_iface_combinations = 1; hw->wiphy->iface_combinations = &data->if_combination; if (param->p2p_device) data->if_combination = hwsim_if_comb_p2p_dev[0]; else data->if_combination = hwsim_if_comb[0]; + hw->wiphy->n_iface_combinations = 1; + /* For channels > 1 DFS is not allowed */ + data->if_combination.radar_detect_widths = 0; data->if_combination.num_different_channels = data->channels; } else if (param->p2p_device) { hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev; @@ -2541,6 +2611,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, data->group = 1; mutex_init(&data->mutex); + data->netgroup = hwsim_net_get_netgroup(net); + /* Enable frame retransmissions for lossy channels */ hw->max_rates = 4; hw->max_rate_tries = 11; @@ -2755,6 +2827,20 @@ static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr) return data; } +static void hwsim_register_wmediumd(struct net *net, u32 portid) +{ + struct mac80211_hwsim_data *data; + + hwsim_net_set_wmediumd(net, portid); + + spin_lock_bh(&hwsim_radio_lock); + list_for_each_entry(data, &hwsim_radios, list) { + if (data->netgroup == hwsim_net_get_netgroup(net)) + data->wmediumd = portid; + } + spin_unlock_bh(&hwsim_radio_lock); +} + static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, struct genl_info *info) { @@ -2770,9 +2856,6 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, int i; bool found = false; - if (info->snd_portid != wmediumd_portid) - return -EINVAL; - if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] || !info->attrs[HWSIM_ATTR_FLAGS] || !info->attrs[HWSIM_ATTR_COOKIE] || @@ -2788,6 +2871,12 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, if (!data2) goto out; + if (hwsim_net_get_netgroup(genl_info_net(info)) != data2->netgroup) + goto out; + + if (info->snd_portid != data2->wmediumd) + goto out; + /* look for the skb matching the cookie passed back from user */ skb_queue_walk_safe(&data2->pending, skb, tmp) { u64 skb_cookie; @@ -2851,9 +2940,6 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, void *frame_data; struct sk_buff *skb = NULL; - if (info->snd_portid != wmediumd_portid) - return -EINVAL; - if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || !info->attrs[HWSIM_ATTR_FRAME] || !info->attrs[HWSIM_ATTR_RX_RATE] || @@ -2879,6 +2965,12 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, if (!data2) goto out; + if (hwsim_net_get_netgroup(genl_info_net(info)) != data2->netgroup) + goto out; + + if (info->snd_portid != data2->wmediumd) + goto out; + /* check if radio is configured properly */ if (data2->idle || !data2->started) @@ -2925,6 +3017,7 @@ out: static int hwsim_register_received_nl(struct sk_buff *skb_2, struct genl_info *info) { + struct net *net = genl_info_net(info); struct mac80211_hwsim_data *data; int chans = 1; @@ -2941,10 +3034,10 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2, if (chans > 1) return -EOPNOTSUPP; - if (wmediumd_portid) + if (hwsim_net_get_wmediumd(net)) return -EBUSY; - wmediumd_portid = info->snd_portid; + hwsim_register_wmediumd(net, info->snd_portid); printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, " "switching to wmediumd mode with pid %d\n", info->snd_portid); @@ -3014,6 +3107,9 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) continue; } + if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info))) + continue; + list_del(&data->list); spin_unlock_bh(&hwsim_radio_lock); mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), @@ -3040,6 +3136,9 @@ static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info) if (data->idx != idx) continue; + if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info))) + continue; + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!skb) { res = -ENOMEM; @@ -3079,6 +3178,9 @@ static int hwsim_dump_radio_nl(struct sk_buff *skb, if (data->idx < idx) continue; + if (!net_eq(wiphy_net(data->hw->wiphy), sock_net(skb->sk))) + continue; + res = mac80211_hwsim_get_radio(skb, data, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, cb, @@ -3102,7 +3204,7 @@ static const struct genl_ops hwsim_ops[] = { .cmd = HWSIM_CMD_REGISTER, .policy = hwsim_genl_policy, .doit = hwsim_register_received_nl, - .flags = GENL_ADMIN_PERM, + .flags = GENL_UNS_ADMIN_PERM, }, { .cmd = HWSIM_CMD_FRAME, @@ -3118,13 +3220,13 @@ static const struct genl_ops hwsim_ops[] = { .cmd = HWSIM_CMD_NEW_RADIO, .policy = hwsim_genl_policy, .doit = hwsim_new_radio_nl, - .flags = GENL_ADMIN_PERM, + .flags = GENL_UNS_ADMIN_PERM, }, { .cmd = HWSIM_CMD_DEL_RADIO, .policy = hwsim_genl_policy, .doit = hwsim_del_radio_nl, - .flags = GENL_ADMIN_PERM, + .flags = GENL_UNS_ADMIN_PERM, }, { .cmd = HWSIM_CMD_GET_RADIO, @@ -3168,10 +3270,10 @@ static int mac80211_hwsim_netlink_notify(struct notifier_block *nb, remove_user_radios(notify->portid); - if (notify->portid == wmediumd_portid) { + if (notify->portid == hwsim_net_get_wmediumd(notify->net)) { printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink" " socket, switching to perfect channel medium\n"); - wmediumd_portid = 0; + hwsim_register_wmediumd(notify->net, 0); } return NOTIFY_DONE; @@ -3206,6 +3308,40 @@ failure: return -EINVAL; } +static __net_init int hwsim_init_net(struct net *net) +{ + hwsim_net_set_netgroup(net); + + return 0; +} + +static void __net_exit hwsim_exit_net(struct net *net) +{ + struct mac80211_hwsim_data *data, *tmp; + + spin_lock_bh(&hwsim_radio_lock); + list_for_each_entry_safe(data, tmp, &hwsim_radios, list) { + if (!net_eq(wiphy_net(data->hw->wiphy), net)) + continue; + + /* Radios created in init_net are returned to init_net. */ + if (data->netgroup == hwsim_net_get_netgroup(&init_net)) + continue; + + list_del(&data->list); + INIT_WORK(&data->destroy_work, destroy_radio); + schedule_work(&data->destroy_work); + } + spin_unlock_bh(&hwsim_radio_lock); +} + +static struct pernet_operations hwsim_net_ops = { + .init = hwsim_init_net, + .exit = hwsim_exit_net, + .id = &hwsim_net_id, + .size = sizeof(struct hwsim_net), +}; + static void hwsim_exit_netlink(void) { /* unregister the notifier */ @@ -3242,10 +3378,14 @@ static int __init init_mac80211_hwsim(void) spin_lock_init(&hwsim_radio_lock); INIT_LIST_HEAD(&hwsim_radios); - err = platform_driver_register(&mac80211_hwsim_driver); + err = register_pernet_device(&hwsim_net_ops); if (err) return err; + err = platform_driver_register(&mac80211_hwsim_driver); + if (err) + goto out_unregister_pernet; + hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); if (IS_ERR(hwsim_class)) { err = PTR_ERR(hwsim_class); @@ -3363,6 +3503,8 @@ out_free_radios: mac80211_hwsim_free(); out_unregister_driver: platform_driver_unregister(&mac80211_hwsim_driver); +out_unregister_pernet: + unregister_pernet_device(&hwsim_net_ops); return err; } module_init(init_mac80211_hwsim); @@ -3376,5 +3518,6 @@ static void __exit exit_mac80211_hwsim(void) mac80211_hwsim_free(); unregister_netdev(hwsim_mon); platform_driver_unregister(&mac80211_hwsim_driver); + unregister_pernet_device(&hwsim_net_ops); } module_exit(exit_mac80211_hwsim); diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index 776b44bfd93a..7ff2efadceca 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -796,10 +796,15 @@ void lbs_scan_done(struct lbs_private *priv) { WARN_ON(!priv->scan_req); - if (priv->internal_scan) + if (priv->internal_scan) { kfree(priv->scan_req); - else - cfg80211_scan_done(priv->scan_req, false); + } else { + struct cfg80211_scan_info info = { + .aborted = false, + }; + + cfg80211_scan_done(priv->scan_req, &info); + } priv->scan_req = NULL; } @@ -2039,8 +2044,8 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) -int lbs_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, - bool enabled, int timeout) +static int lbs_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, + bool enabled, int timeout) { struct lbs_private *priv = wiphy_priv(wiphy); diff --git a/drivers/net/wireless/marvell/libertas/cmdresp.c b/drivers/net/wireless/marvell/libertas/cmdresp.c index c95bf6dc9522..c753e36c2c0e 100644 --- a/drivers/net/wireless/marvell/libertas/cmdresp.c +++ b/drivers/net/wireless/marvell/libertas/cmdresp.c @@ -27,6 +27,8 @@ void lbs_mac_event_disconnected(struct lbs_private *priv, bool locally_generated) { + unsigned long flags; + if (priv->connect_status != LBS_CONNECTED) return; @@ -46,9 +48,11 @@ void lbs_mac_event_disconnected(struct lbs_private *priv, netif_carrier_off(priv->dev); /* Free Tx and Rx packets */ + spin_lock_irqsave(&priv->driver_lock, flags); kfree_skb(priv->currenttxskb); priv->currenttxskb = NULL; priv->tx_pending_len = 0; + spin_unlock_irqrestore(&priv->driver_lock, flags); priv->connect_status = LBS_DISCONNECTED; diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index 13eae9ff8c35..47f4a14c84fe 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -1228,7 +1228,7 @@ static int if_sdio_probe(struct sdio_func *func, } spin_lock_init(&card->lock); - card->workqueue = create_workqueue("libertas_sdio"); + card->workqueue = alloc_workqueue("libertas_sdio", WQ_MEM_RECLAIM, 0); INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker); init_waitqueue_head(&card->pwron_waitq); @@ -1326,7 +1326,6 @@ static void if_sdio_remove(struct sdio_func *func) lbs_stop_card(card->priv); lbs_remove_card(card->priv); - flush_workqueue(card->workqueue); destroy_workqueue(card->workqueue); while (card->packets) { diff --git a/drivers/net/wireless/marvell/libertas/if_spi.c b/drivers/net/wireless/marvell/libertas/if_spi.c index 82c0796377aa..c3a53cd6988e 100644 --- a/drivers/net/wireless/marvell/libertas/if_spi.c +++ b/drivers/net/wireless/marvell/libertas/if_spi.c @@ -1180,7 +1180,7 @@ static int if_spi_probe(struct spi_device *spi) priv->fw_ready = 1; /* Initialize interrupt handling stuff. */ - card->workqueue = create_workqueue("libertas_spi"); + card->workqueue = alloc_workqueue("libertas_spi", WQ_MEM_RECLAIM, 0); INIT_WORK(&card->packet_work, if_spi_host_to_card_worker); INIT_WORK(&card->resume_work, if_spi_resume_worker); @@ -1208,7 +1208,6 @@ static int if_spi_probe(struct spi_device *spi) release_irq: free_irq(spi->irq, card); terminate_workqueue: - flush_workqueue(card->workqueue); destroy_workqueue(card->workqueue); lbs_remove_card(priv); /* will call free_netdev */ free_card: @@ -1235,7 +1234,6 @@ static int libertas_spi_remove(struct spi_device *spi) lbs_remove_card(priv); /* will call free_netdev */ free_irq(spi->irq, card); - flush_workqueue(card->workqueue); destroy_workqueue(card->workqueue); if (card->pdata->teardown) card->pdata->teardown(spi); diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 0bf8916a02cf..54e426c1e405 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -16,7 +16,6 @@ #include <linux/module.h> #include "libertas_tf.h" -#define DRIVER_RELEASE_VERSION "004.p0" /* thinfirm version: 5.132.X.pX */ #define LBTF_FW_VER_MIN 0x05840300 #define LBTF_FW_VER_MAX 0x0584ffff @@ -27,12 +26,6 @@ unsigned int lbtf_debug; EXPORT_SYMBOL_GPL(lbtf_debug); module_param_named(libertas_tf_debug, lbtf_debug, int, 0644); -static const char lbtf_driver_version[] = "THINFIRM-USB8388-" DRIVER_RELEASE_VERSION -#ifdef DEBUG - "-dbg" -#endif - ""; - struct workqueue_struct *lbtf_wq; static const struct ieee80211_channel lbtf_channels[] = { @@ -742,7 +735,7 @@ EXPORT_SYMBOL_GPL(lbtf_bcn_sent); static int __init lbtf_init_module(void) { lbtf_deb_enter(LBTF_DEB_MAIN); - lbtf_wq = create_workqueue("libertastf"); + lbtf_wq = alloc_workqueue("libertastf", WQ_MEM_RECLAIM, 0); if (lbtf_wq == NULL) { printk(KERN_ERR "libertastf: couldn't create workqueue\n"); return -ENOMEM; diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c index 1efef3b8273d..dc49c3de1f25 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c @@ -184,7 +184,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, tx_info_src = MWIFIEX_SKB_TXCB(skb_src); skb_aggr = mwifiex_alloc_dma_align_buf(adapter->tx_buf_size, - GFP_ATOMIC | GFP_DMA); + GFP_ATOMIC); if (!skb_aggr) { spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index ff948a922222..a8ff969c95c2 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -377,6 +377,29 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, } /* + * CFG802.11 operation handler to get Tx power. + */ +static int +mwifiex_cfg80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm) +{ + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_private *priv = mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY); + int ret = mwifiex_send_cmd(priv, HostCmd_CMD_RF_TX_PWR, + HostCmd_ACT_GEN_GET, 0, NULL, true); + + if (ret < 0) + return ret; + + /* tx_power_level is set in HostCmd_CMD_RF_TX_PWR command handler */ + *dbm = priv->tx_power_level; + + return 0; +} + +/* * CFG802.11 operation handler to set Power Save option. * * The timeout value, if provided, is currently ignored. @@ -1672,6 +1695,9 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy, struct cfg80211_beacon_data *data) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_adapter *adapter = priv->adapter; + + mwifiex_cancel_scan(adapter); if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) { mwifiex_dbg(priv->adapter, ERROR, @@ -1804,6 +1830,21 @@ mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) HostCmd_ACT_GEN_SET, 0, &ant_cfg, true); } +static int +mwifiex_cfg80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) +{ + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_private *priv = mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY); + mwifiex_send_cmd(priv, HostCmd_CMD_RF_ANTENNA, + HostCmd_ACT_GEN_GET, 0, NULL, true); + + *tx_ant = priv->tx_ant; + *rx_ant = priv->rx_ant; + + return 0; +} + /* cfg80211 operation handler for stop ap. * Function stops BSS running at uAP interface. */ @@ -1895,10 +1936,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, mwifiex_set_uap_rates(bss_cfg, params); if (mwifiex_set_secure_params(priv, bss_cfg, params)) { - kfree(bss_cfg); mwifiex_dbg(priv->adapter, ERROR, "Failed to parse secuirty parameters!\n"); - return -1; + goto out; } mwifiex_set_ht_params(priv, bss_cfg, params); @@ -1927,7 +1967,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, if (mwifiex_11h_activate(priv, false)) { mwifiex_dbg(priv->adapter, ERROR, "Failed to disable 11h extensions!!"); - return -1; + goto out; } priv->state_11h.is_11h_active = false; } @@ -1935,12 +1975,11 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, if (mwifiex_config_start_uap(priv, bss_cfg)) { mwifiex_dbg(priv->adapter, ERROR, "Failed to start AP\n"); - kfree(bss_cfg); - return -1; + goto out; } if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon)) - return -1; + goto out; if (!netif_carrier_ok(priv->netdev)) netif_carrier_on(priv->netdev); @@ -1949,6 +1988,10 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg)); kfree(bss_cfg); return 0; + +out: + kfree(bss_cfg); + return -1; } /* @@ -2209,6 +2252,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return -EALREADY; } + if (priv->scan_block) + priv->scan_block = false; + if (adapter->surprise_removed || adapter->is_cmd_timedout) { mwifiex_dbg(adapter, ERROR, "%s: Ignore connection.\t" @@ -2427,6 +2473,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, return -EBUSY; } + if (!priv->wdev.current_bss && priv->scan_block) + priv->scan_block = false; + if (!mwifiex_stop_bg_scan(priv)) cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy); @@ -2734,6 +2783,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, struct mwifiex_private *priv; struct net_device *dev; void *mdev_priv; + int ret; if (!adapter) return ERR_PTR(-EFAULT); @@ -2859,6 +2909,15 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, mwifiex_init_priv_params(priv, dev); priv->netdev = dev; + ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL, true); + if (ret) + return ERR_PTR(ret); + + ret = mwifiex_sta_init_cmd(priv, false, false); + if (ret) + return ERR_PTR(ret); + mwifiex_setup_ht_caps(&wiphy->bands[NL80211_BAND_2GHZ]->ht_cap, priv); if (adapter->is_hw_11ac_capable) mwifiex_setup_vht_caps( @@ -3262,7 +3321,10 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, struct mwifiex_ds_hs_cfg hs_cfg; int i, ret = 0, retry_num = 10; struct mwifiex_private *priv; + struct mwifiex_private *sta_priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + sta_priv->scan_aborting = true; for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; mwifiex_abort_cac(priv); @@ -3291,21 +3353,21 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, if (!wowlan) { mwifiex_dbg(adapter, ERROR, "None of the WOWLAN triggers enabled\n"); - return 0; + ret = 0; + goto done; } - priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); - - if (!priv->media_connected && !wowlan->nd_config) { + if (!sta_priv->media_connected && !wowlan->nd_config) { mwifiex_dbg(adapter, ERROR, "Can not configure WOWLAN in disconnected state\n"); - return 0; + ret = 0; + goto done; } - ret = mwifiex_set_mef_filter(priv, wowlan); + ret = mwifiex_set_mef_filter(sta_priv, wowlan); if (ret) { mwifiex_dbg(adapter, ERROR, "Failed to set MEF filter\n"); - return ret; + goto done; } memset(&hs_cfg, 0, sizeof(hs_cfg)); @@ -3314,26 +3376,25 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, if (wowlan->nd_config) { mwifiex_dbg(adapter, INFO, "Wake on net detect\n"); hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT; - mwifiex_cfg80211_sched_scan_start(wiphy, priv->netdev, + mwifiex_cfg80211_sched_scan_start(wiphy, sta_priv->netdev, wowlan->nd_config); } if (wowlan->disconnect) { hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT; - mwifiex_dbg(priv->adapter, INFO, "Wake on device disconnect\n"); + mwifiex_dbg(sta_priv->adapter, INFO, "Wake on device disconnect\n"); } hs_cfg.is_invoke_hostcmd = false; hs_cfg.gpio = adapter->hs_cfg.gpio; hs_cfg.gap = adapter->hs_cfg.gap; - ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, + ret = mwifiex_set_hs_params(sta_priv, HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD, &hs_cfg); - if (ret) { - mwifiex_dbg(adapter, ERROR, - "Failed to set HS params\n"); - return ret; - } + if (ret) + mwifiex_dbg(adapter, ERROR, "Failed to set HS params\n"); +done: + sta_priv->scan_aborting = false; return ret; } @@ -3940,12 +4001,14 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .set_default_key = mwifiex_cfg80211_set_default_key, .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt, .set_tx_power = mwifiex_cfg80211_set_tx_power, + .get_tx_power = mwifiex_cfg80211_get_tx_power, .set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask, .start_ap = mwifiex_cfg80211_start_ap, .stop_ap = mwifiex_cfg80211_stop_ap, .change_beacon = mwifiex_cfg80211_change_beacon, .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config, .set_antenna = mwifiex_cfg80211_set_antenna, + .get_antenna = mwifiex_cfg80211_get_antenna, .del_station = mwifiex_cfg80211_del_station, .sched_scan_start = mwifiex_cfg80211_sched_scan_start, .sched_scan_stop = mwifiex_cfg80211_sched_scan_stop, diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 6bc2011d8609..c29f26d8baf2 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -1020,8 +1020,6 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) { struct cmd_ctrl_node *cmd_node = NULL, *tmp_node; unsigned long flags, cmd_flags; - struct mwifiex_private *priv; - int i; spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); /* Cancel current cmd */ @@ -1046,23 +1044,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); - mwifiex_cancel_pending_scan_cmd(adapter); - - if (adapter->scan_processing) { - spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); - adapter->scan_processing = false; - spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); - for (i = 0; i < adapter->priv_num; i++) { - priv = adapter->priv[i]; - if (!priv) - continue; - if (priv->scan_request) { - mwifiex_dbg(adapter, WARN, "info: aborting scan\n"); - cfg80211_scan_done(priv->scan_request, 1); - priv->scan_request = NULL; - } - } - } + mwifiex_cancel_scan(adapter); } /* @@ -1080,8 +1062,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) { struct cmd_ctrl_node *cmd_node = NULL; unsigned long cmd_flags; - struct mwifiex_private *priv; - int i; if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) { @@ -1101,23 +1081,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) mwifiex_recycle_cmd_node(adapter, cmd_node); } - mwifiex_cancel_pending_scan_cmd(adapter); - - if (adapter->scan_processing) { - spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); - adapter->scan_processing = false; - spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); - for (i = 0; i < adapter->priv_num; i++) { - priv = adapter->priv[i]; - if (!priv) - continue; - if (priv->scan_request) { - mwifiex_dbg(adapter, WARN, "info: aborting scan\n"); - cfg80211_scan_done(priv->scan_request, 1); - priv->scan_request = NULL; - } - } - } + mwifiex_cancel_scan(adapter); } /* diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 8e4145abdbfa..5596b6be1898 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -462,6 +462,9 @@ enum P2P_MODES { #define HostCmd_ACT_SET_RX 0x0001 #define HostCmd_ACT_SET_TX 0x0002 #define HostCmd_ACT_SET_BOTH 0x0003 +#define HostCmd_ACT_GET_RX 0x0004 +#define HostCmd_ACT_GET_TX 0x0008 +#define HostCmd_ACT_GET_BOTH 0x000c #define RF_ANTENNA_AUTO 0xFFFF @@ -1958,8 +1961,8 @@ struct mwifiex_ie_types_btcoex_scan_time { struct mwifiex_ie_types_header header; u8 coex_scan; u8 reserved; - u16 min_scan_time; - u16 max_scan_time; + __le16 min_scan_time; + __le16 max_scan_time; } __packed; struct mwifiex_ie_types_btcoex_aggr_win_size { diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index 78c532f0d286..1489c90192bd 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -60,7 +60,7 @@ static void wakeup_timer_fn(unsigned long data) adapter->hw_status = MWIFIEX_HW_STATUS_RESET; mwifiex_cancel_all_pending_cmd(adapter); - if (adapter->if_ops.card_reset) + if (adapter->if_ops.card_reset && !adapter->hs_activated) adapter->if_ops.card_reset(adapter); } @@ -110,6 +110,8 @@ int mwifiex_init_priv(struct mwifiex_private *priv) priv->tx_power_level = 0; priv->max_tx_power_level = 0; priv->min_tx_power_level = 0; + priv->tx_ant = 0; + priv->rx_ant = 0; priv->tx_rate = 0; priv->rxpd_htinfo = 0; priv->rxpd_rate = 0; @@ -788,3 +790,4 @@ poll_fw: return ret; } +EXPORT_SYMBOL_GPL(mwifiex_dnld_fw); diff --git a/drivers/net/wireless/marvell/mwifiex/ioctl.h b/drivers/net/wireless/marvell/mwifiex/ioctl.h index a5a48c183d37..70429815ff53 100644 --- a/drivers/net/wireless/marvell/mwifiex/ioctl.h +++ b/drivers/net/wireless/marvell/mwifiex/ioctl.h @@ -83,6 +83,8 @@ struct wep_key { #define MWIFIEX_AUTH_MODE_AUTO 0xFF #define BAND_CONFIG_BG 0x00 #define BAND_CONFIG_A 0x01 +#define MWIFIEX_SEC_CHAN_BELOW 0x30 +#define MWIFIEX_SEC_CHAN_ABOVE 0x10 #define MWIFIEX_SUPPORTED_RATES 14 #define MWIFIEX_SUPPORTED_RATES_EXT 32 #define MWIFIEX_TDLS_SUPPORTED_RATES 8 @@ -341,16 +343,16 @@ enum { }; struct mwifiex_ds_reg_rw { - __le32 type; - __le32 offset; - __le32 value; + u32 type; + u32 offset; + u32 value; }; #define MAX_EEPROM_DATA 256 struct mwifiex_ds_read_eeprom { - __le16 offset; - __le16 byte_count; + u16 offset; + u16 byte_count; u8 value[MAX_EEPROM_DATA]; }; diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c index 62211fca91b7..1c7b00630b90 100644 --- a/drivers/net/wireless/marvell/mwifiex/join.c +++ b/drivers/net/wireless/marvell/mwifiex/join.c @@ -647,6 +647,12 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, const u8 *ie_ptr; struct ieee80211_ht_operation *assoc_resp_ht_oper; + if (!priv->attempted_bss_desc) { + mwifiex_dbg(priv->adapter, ERROR, + "ASSOC_RESP: failed, association terminated by host\n"); + goto done; + } + assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap); @@ -1270,6 +1276,12 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, u16 cmd = le16_to_cpu(resp->command); u8 result; + if (!priv->attempted_bss_desc) { + mwifiex_dbg(priv->adapter, ERROR, + "ADHOC_RESP: failed, association terminated by host\n"); + goto done; + } + if (cmd == HostCmd_CMD_802_11_AD_HOC_START) result = start_result->result; else @@ -1281,7 +1293,7 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, if (result) { mwifiex_dbg(priv->adapter, ERROR, "ADHOC_RESP: failed\n"); if (priv->media_connected) - mwifiex_reset_connect_state(priv, result); + mwifiex_reset_connect_state(priv, result, true); memset(&priv->curr_bss_params.bss_descriptor, 0x00, sizeof(struct mwifiex_bssdescriptor)); diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 8b67a552a690..db4925db39aa 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -526,10 +526,12 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) fw.fw_buf = (u8 *) adapter->firmware->data; fw.fw_len = adapter->firmware->size; - if (adapter->if_ops.dnld_fw) + if (adapter->if_ops.dnld_fw) { ret = adapter->if_ops.dnld_fw(adapter, &fw); - else + } else { ret = mwifiex_dnld_fw(adapter, &fw); + } + if (ret == -1) goto err_dnld_fw; @@ -695,9 +697,13 @@ mwifiex_close(struct net_device *dev) struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); if (priv->scan_request) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + mwifiex_dbg(priv->adapter, INFO, "aborting scan on ndo_stop\n"); - cfg80211_scan_done(priv->scan_request, 1); + cfg80211_scan_done(priv->scan_request, &info); priv->scan_request = NULL; priv->scan_aborting = true; } diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 0207af00be42..9f6bb400bdae 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -533,6 +533,8 @@ struct mwifiex_private { u16 tx_power_level; u8 max_tx_power_level; u8 min_tx_power_level; + u32 tx_ant; + u32 rx_ant; u8 tx_rate; u8 tx_htinfo; u8 rxpd_htinfo; @@ -1054,6 +1056,7 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter); void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter); void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter); void mwifiex_cancel_pending_scan_cmd(struct mwifiex_adapter *adapter); +void mwifiex_cancel_scan(struct mwifiex_adapter *adapter); void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter, struct cmd_ctrl_node *cmd_node); @@ -1128,7 +1131,8 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); -void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason); +void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason, + bool from_ap); u8 mwifiex_band_to_radio_type(u8 band); int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac); void mwifiex_deauthenticate_all(struct mwifiex_adapter *adapter); diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 0c7937eb6b77..453ab6ad4784 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -202,7 +202,6 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops, MWIFIEX_PCIE)) { pr_err("%s failed\n", __func__); - kfree(card); return -1; } @@ -440,6 +439,11 @@ static int mwifiex_pcie_disable_host_int(struct mwifiex_adapter *adapter) return 0; } +static void mwifiex_pcie_disable_host_int_noerr(struct mwifiex_adapter *adapter) +{ + WARN_ON(mwifiex_pcie_disable_host_int(adapter)); +} + /* * This function enables the host interrupt. * @@ -507,7 +511,7 @@ static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter) for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { /* Allocate skb here so that firmware can DMA data from it */ skb = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE, - GFP_KERNEL | GFP_DMA); + GFP_KERNEL); if (!skb) { mwifiex_dbg(adapter, ERROR, "Unable to allocate skb for RX ring.\n"); @@ -1319,7 +1323,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) } skb_tmp = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE, - GFP_KERNEL | GFP_DMA); + GFP_KERNEL); if (!skb_tmp) { mwifiex_dbg(adapter, ERROR, "Unable to allocate skb.\n"); @@ -1612,6 +1616,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) pkt_len = *((__le16 *)skb->data); rx_len = le16_to_cpu(pkt_len); + skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len); skb_trim(skb, rx_len); skb_pull(skb, INTF_HEADER_LEN); @@ -2086,6 +2091,13 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter, unsigned long flags; struct pcie_service_card *card = adapter->card; + if (card->msi_enable) { + spin_lock_irqsave(&adapter->int_lock, flags); + adapter->int_status = 1; + spin_unlock_irqrestore(&adapter->int_lock, flags); + return; + } + if (!mwifiex_pcie_ok_to_access_hw(adapter)) return; @@ -2187,15 +2199,44 @@ exit: static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter) { int ret; - u32 pcie_ireg; + u32 pcie_ireg = 0; unsigned long flags; + struct pcie_service_card *card = adapter->card; spin_lock_irqsave(&adapter->int_lock, flags); - /* Clear out unused interrupts */ - pcie_ireg = adapter->int_status; + if (!card->msi_enable) { + /* Clear out unused interrupts */ + pcie_ireg = adapter->int_status; + } adapter->int_status = 0; spin_unlock_irqrestore(&adapter->int_lock, flags); + if (card->msi_enable) { + if (mwifiex_pcie_ok_to_access_hw(adapter)) { + if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, + &pcie_ireg)) { + mwifiex_dbg(adapter, ERROR, + "Read register failed\n"); + return -1; + } + + if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) { + if (mwifiex_write_reg(adapter, + PCIE_HOST_INT_STATUS, + ~pcie_ireg)) { + mwifiex_dbg(adapter, ERROR, + "Write register failed\n"); + return -1; + } + if (!adapter->pps_uapsd_mode && + adapter->ps_state == PS_STATE_SLEEP) { + adapter->ps_state = PS_STATE_AWAKE; + adapter->pm_wakeup_fw_try = false; + del_timer(&adapter->wakeup_timer); + } + } + } + } while (pcie_ireg & HOST_INTR_MASK) { if (pcie_ireg & HOST_INTR_DNLD_DONE) { pcie_ireg &= ~HOST_INTR_DNLD_DONE; @@ -2235,6 +2276,12 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter) return ret; } + if (card->msi_enable) { + spin_lock_irqsave(&adapter->int_lock, flags); + adapter->int_status = 0; + spin_unlock_irqrestore(&adapter->int_lock, flags); + } + if (mwifiex_pcie_ok_to_access_hw(adapter)) { if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, &pcie_ireg)) { @@ -2254,11 +2301,17 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter) } } + if (!card->msi_enable) { + spin_lock_irqsave(&adapter->int_lock, flags); + pcie_ireg |= adapter->int_status; + adapter->int_status = 0; + spin_unlock_irqrestore(&adapter->int_lock, flags); + } } mwifiex_dbg(adapter, INTR, "info: cmd_sent=%d data_sent=%d\n", adapter->cmd_sent, adapter->data_sent); - if (adapter->ps_state != PS_STATE_SLEEP) + if (!card->msi_enable && adapter->ps_state != PS_STATE_SLEEP) mwifiex_pcie_enable_host_int(adapter); return 0; @@ -2796,7 +2849,6 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter) "MRVL_PCIE", &card->share_irq_ctx); if (ret) { pr_err("request_irq failed: ret=%d\n", ret); - adapter->card = NULL; return -1; } @@ -2804,7 +2856,7 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter) } /* - * This function get firmare name for downloading by revision id + * This function gets the firmware name for downloading by revision id * * Read revision id register to get revision id */ @@ -2841,20 +2893,20 @@ static void mwifiex_pcie_get_fw_name(struct mwifiex_adapter *adapter) version &= 0x7; switch (revision_id) { case PCIE8997_V2: - if (version == CHIP_VER_PCIEUSB) + if (version == CHIP_VER_PCIEUART) strcpy(adapter->fw_name, - PCIEUSB8997_FW_NAME_V2); + PCIEUART8997_FW_NAME_V2); else strcpy(adapter->fw_name, - PCIEUART8997_FW_NAME_V2); + PCIEUSB8997_FW_NAME_V2); break; case PCIE8997_Z: - if (version == CHIP_VER_PCIEUSB) + if (version == CHIP_VER_PCIEUART) strcpy(adapter->fw_name, - PCIEUSB8997_FW_NAME_Z); + PCIEUART8997_FW_NAME_Z); else strcpy(adapter->fw_name, - PCIEUART8997_FW_NAME_Z); + PCIEUSB8997_FW_NAME_Z); break; default: strcpy(adapter->fw_name, PCIE8997_DEFAULT_FW_NAME); @@ -2901,10 +2953,11 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *reg; - struct pci_dev *pdev = card->dev; + struct pci_dev *pdev; int i; if (card) { + pdev = card->dev; if (card->msix_enable) { for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++) synchronize_irq(card->msix_entries[i].vector); @@ -2945,6 +2998,7 @@ static struct mwifiex_if_ops pcie_ops = { .register_dev = mwifiex_register_dev, .unregister_dev = mwifiex_unregister_dev, .enable_int = mwifiex_pcie_enable_host_int, + .disable_int = mwifiex_pcie_disable_host_int_noerr, .process_int_status = mwifiex_process_int_status, .host_to_card = mwifiex_pcie_host_to_card, .wakeup = mwifiex_pm_wakeup_card, diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h index 2592e63c32cf..f05061cea5cd 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie.h @@ -32,7 +32,7 @@ #define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin" #define PCIE8897_A0_FW_NAME "mrvl/pcie8897_uapsta_a0.bin" #define PCIE8897_B0_FW_NAME "mrvl/pcie8897_uapsta.bin" -#define PCIE8997_DEFAULT_FW_NAME "mrvl/pcieuart8997_combo_v2.bin" +#define PCIE8997_DEFAULT_FW_NAME "mrvl/pcieusb8997_combo_v2.bin" #define PCIEUART8997_FW_NAME_Z "mrvl/pcieuart8997_combo.bin" #define PCIEUART8997_FW_NAME_V2 "mrvl/pcieuart8997_combo_v2.bin" #define PCIEUSB8997_FW_NAME_Z "mrvl/pcieusb8997_combo.bin" @@ -48,7 +48,7 @@ #define PCIE8897_B0 0x1200 #define PCIE8997_Z 0x0 #define PCIE8997_V2 0x471 -#define CHIP_VER_PCIEUSB 0x2 +#define CHIP_VER_PCIEUART 0x3 /* Constants for Buffer Descriptor (BD) rings */ #define MWIFIEX_MAX_TXRX_BD 0x20 @@ -258,7 +258,7 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = { .fw_dump_end = 0xcff, .fw_dump_host_ready = 0xcc, .fw_dump_read_done = 0xdd, - .msix_support = 1, + .msix_support = 0, }; static struct memory_type_mapping mem_type_mapping_tbl_w8897[] = { diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index bc5e52cebce1..21ec84794d0c 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -1896,7 +1896,8 @@ mwifiex_active_scan_req_for_passive_chan(struct mwifiex_private *priv) u8 id = 0; struct mwifiex_user_scan_cfg *user_scan_cfg; - if (adapter->active_scan_triggered || !priv->scan_request) { + if (adapter->active_scan_triggered || !priv->scan_request || + priv->scan_aborting) { adapter->active_scan_triggered = false; return 0; } @@ -1956,10 +1957,15 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) mwifiex_complete_scan(priv); if (priv->scan_request) { + struct cfg80211_scan_info info = { + .aborted = false, + }; + mwifiex_dbg(adapter, INFO, "info: notifying scan done\n"); - cfg80211_scan_done(priv->scan_request, 0); + cfg80211_scan_done(priv->scan_request, &info); priv->scan_request = NULL; + priv->scan_aborting = false; } else { priv->scan_aborting = false; mwifiex_dbg(adapter, INFO, @@ -1977,10 +1983,15 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) if (!adapter->active_scan_triggered) { if (priv->scan_request) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + mwifiex_dbg(adapter, INFO, "info: aborting scan\n"); - cfg80211_scan_done(priv->scan_request, 1); + cfg80211_scan_done(priv->scan_request, &info); priv->scan_request = NULL; + priv->scan_aborting = false; } else { priv->scan_aborting = false; mwifiex_dbg(adapter, INFO, @@ -2001,6 +2012,37 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) return; } +void mwifiex_cancel_scan(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv; + unsigned long cmd_flags; + int i; + + mwifiex_cancel_pending_scan_cmd(adapter); + + if (adapter->scan_processing) { + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (!priv) + continue; + if (priv->scan_request) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + + mwifiex_dbg(adapter, INFO, + "info: aborting scan\n"); + cfg80211_scan_done(priv->scan_request, &info); + priv->scan_request = NULL; + priv->scan_aborting = false; + } + } + } +} + /* * This function handles the command response of scan. * diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index bdc51ffd43ec..d3e1561ca075 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -102,10 +102,9 @@ static int mwifiex_sdio_probe_of(struct device *dev, struct sdio_mmc_card *card) struct mwifiex_plt_wake_cfg *cfg; int ret; - if (!dev->of_node || - !of_match_node(mwifiex_sdio_of_match_table, dev->of_node)) { - dev_err(dev, "sdio platform data not available\n"); - return -1; + if (!of_match_node(mwifiex_sdio_of_match_table, dev->of_node)) { + dev_err(dev, "required compatible string missing\n"); + return -EINVAL; } card->plt_of_node = dev->of_node; @@ -115,7 +114,7 @@ static int mwifiex_sdio_probe_of(struct device *dev, struct sdio_mmc_card *card) if (cfg && card->plt_of_node) { cfg->irq_wifi = irq_of_parse_and_map(card->plt_of_node, 0); if (!cfg->irq_wifi) { - dev_err(dev, + dev_dbg(dev, "fail to parse irq_wifi from device tree\n"); } else { ret = devm_request_irq(dev, cfg->irq_wifi, @@ -183,24 +182,35 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) sdio_release_host(func); if (ret) { - pr_err("%s: failed to enable function\n", __func__); - kfree(card); - return -EIO; + dev_err(&func->dev, "failed to enable function\n"); + goto err_free; } /* device tree node parsing and platform specific configuration*/ - mwifiex_sdio_probe_of(&func->dev, card); - - if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops, - MWIFIEX_SDIO)) { - pr_err("%s: add card failed\n", __func__); - kfree(card); - sdio_claim_host(func); - ret = sdio_disable_func(func); - sdio_release_host(func); - ret = -1; + if (func->dev.of_node) { + ret = mwifiex_sdio_probe_of(&func->dev, card); + if (ret) { + dev_err(&func->dev, "SDIO dt node parse failed\n"); + goto err_disable; + } + } + + ret = mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops, + MWIFIEX_SDIO); + if (ret) { + dev_err(&func->dev, "add card failed\n"); + goto err_disable; } + return 0; + +err_disable: + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); +err_free: + kfree(card); + return ret; } @@ -544,6 +554,19 @@ static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) return mwifiex_write_reg(adapter, CONFIGURATION_REG, 0); } +static int mwifiex_sdio_dnld_fw(struct mwifiex_adapter *adapter, + struct mwifiex_fw_image *fw) +{ + struct sdio_mmc_card *card = adapter->card; + int ret; + + sdio_claim_host(card->func); + ret = mwifiex_dnld_fw(adapter, fw); + sdio_release_host(card->func); + + return ret; +} + /* * This function is used to initialize IO ports for the * chipsets supporting SDIO new mode eg SD8897. @@ -1492,7 +1515,7 @@ rx_curr_single: mwifiex_dbg(adapter, INFO, "info: RX: port: %d, rx_len: %d\n", port, rx_len); - skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA); + skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL); if (!skb) { mwifiex_dbg(adapter, ERROR, "single skb allocated fail,\t" @@ -1597,7 +1620,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); mwifiex_dbg(adapter, INFO, "info: rx_len = %d\n", rx_len); - skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA); + skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL); if (!skb) return -1; @@ -2732,6 +2755,7 @@ static struct mwifiex_if_ops sdio_ops = { .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf, .cmdrsp_complete = mwifiex_sdio_cmdrsp_complete, .event_complete = mwifiex_sdio_event_complete, + .dnld_fw = mwifiex_sdio_dnld_fw, .card_reset = mwifiex_sdio_card_reset, .reg_dump = mwifiex_sdio_reg_dump, .device_dump = mwifiex_sdio_device_dump, diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index e436574b1698..7897037b0992 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -313,23 +313,41 @@ static int mwifiex_cmd_rf_antenna(struct mwifiex_private *priv, cmd->command = cpu_to_le16(HostCmd_CMD_RF_ANTENNA); - if (cmd_action != HostCmd_ACT_GEN_SET) - return 0; - - if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) { - cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_ant_mimo) + - S_DS_GEN); - ant_mimo->action_tx = cpu_to_le16(HostCmd_ACT_SET_TX); - ant_mimo->tx_ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant); - ant_mimo->action_rx = cpu_to_le16(HostCmd_ACT_SET_RX); - ant_mimo->rx_ant_mode = cpu_to_le16((u16)ant_cfg->rx_ant); - } else { - cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_ant_siso) + - S_DS_GEN); - ant_siso->action = cpu_to_le16(HostCmd_ACT_SET_BOTH); - ant_siso->ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant); + switch (cmd_action) { + case HostCmd_ACT_GEN_SET: + if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) { + cmd->size = cpu_to_le16(sizeof(struct + host_cmd_ds_rf_ant_mimo) + + S_DS_GEN); + ant_mimo->action_tx = cpu_to_le16(HostCmd_ACT_SET_TX); + ant_mimo->tx_ant_mode = cpu_to_le16((u16)ant_cfg-> + tx_ant); + ant_mimo->action_rx = cpu_to_le16(HostCmd_ACT_SET_RX); + ant_mimo->rx_ant_mode = cpu_to_le16((u16)ant_cfg-> + rx_ant); + } else { + cmd->size = cpu_to_le16(sizeof(struct + host_cmd_ds_rf_ant_siso) + + S_DS_GEN); + ant_siso->action = cpu_to_le16(HostCmd_ACT_SET_BOTH); + ant_siso->ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant); + } + break; + case HostCmd_ACT_GEN_GET: + if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) { + cmd->size = cpu_to_le16(sizeof(struct + host_cmd_ds_rf_ant_mimo) + + S_DS_GEN); + ant_mimo->action_tx = cpu_to_le16(HostCmd_ACT_GET_TX); + ant_mimo->action_rx = cpu_to_le16(HostCmd_ACT_GET_RX); + } else { + cmd->size = cpu_to_le16(sizeof(struct + host_cmd_ds_rf_ant_siso) + + S_DS_GEN); + ant_siso->action = cpu_to_le16(HostCmd_ACT_GET_BOTH); + } + break; } - return 0; } @@ -1130,9 +1148,8 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN); mac_reg = &cmd->params.mac_reg; mac_reg->action = cpu_to_le16(cmd_action); - mac_reg->offset = - cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); - mac_reg->value = reg_rw->value; + mac_reg->offset = cpu_to_le16((u16) reg_rw->offset); + mac_reg->value = cpu_to_le32(reg_rw->value); break; } case HostCmd_CMD_BBP_REG_ACCESS: @@ -1142,9 +1159,8 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN); bbp_reg = &cmd->params.bbp_reg; bbp_reg->action = cpu_to_le16(cmd_action); - bbp_reg->offset = - cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); - bbp_reg->value = (u8) le32_to_cpu(reg_rw->value); + bbp_reg->offset = cpu_to_le16((u16) reg_rw->offset); + bbp_reg->value = (u8) reg_rw->value; break; } case HostCmd_CMD_RF_REG_ACCESS: @@ -1154,8 +1170,8 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN); rf_reg = &cmd->params.rf_reg; rf_reg->action = cpu_to_le16(cmd_action); - rf_reg->offset = cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); - rf_reg->value = (u8) le32_to_cpu(reg_rw->value); + rf_reg->offset = cpu_to_le16((u16) reg_rw->offset); + rf_reg->value = (u8) reg_rw->value; break; } case HostCmd_CMD_PMIC_REG_ACCESS: @@ -1165,9 +1181,8 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN); pmic_reg = &cmd->params.pmic_reg; pmic_reg->action = cpu_to_le16(cmd_action); - pmic_reg->offset = - cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); - pmic_reg->value = (u8) le32_to_cpu(reg_rw->value); + pmic_reg->offset = cpu_to_le16((u16) reg_rw->offset); + pmic_reg->value = (u8) reg_rw->value; break; } case HostCmd_CMD_CAU_REG_ACCESS: @@ -1177,9 +1192,8 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN); cau_reg = &cmd->params.rf_reg; cau_reg->action = cpu_to_le16(cmd_action); - cau_reg->offset = - cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); - cau_reg->value = (u8) le32_to_cpu(reg_rw->value); + cau_reg->offset = cpu_to_le16((u16) reg_rw->offset); + cau_reg->value = (u8) reg_rw->value; break; } case HostCmd_CMD_802_11_EEPROM_ACCESS: @@ -1190,8 +1204,8 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN); cmd_eeprom->action = cpu_to_le16(cmd_action); - cmd_eeprom->offset = rd_eeprom->offset; - cmd_eeprom->byte_count = rd_eeprom->byte_count; + cmd_eeprom->offset = cpu_to_le16(rd_eeprom->offset); + cmd_eeprom->byte_count = cpu_to_le16(rd_eeprom->byte_count); cmd_eeprom->value = 0; break; } diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c index d18c7979d723..ccf54932e321 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c @@ -469,7 +469,9 @@ static int mwifiex_ret_rf_antenna(struct mwifiex_private *priv, struct host_cmd_ds_rf_ant_siso *ant_siso = &resp->params.ant_siso; struct mwifiex_adapter *adapter = priv->adapter; - if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) + if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) { + priv->tx_ant = le16_to_cpu(ant_mimo->tx_ant_mode); + priv->rx_ant = le16_to_cpu(ant_mimo->rx_ant_mode); mwifiex_dbg(adapter, INFO, "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x\t" "Rx action = 0x%x, Rx Mode = 0x%04x\n", @@ -477,12 +479,14 @@ static int mwifiex_ret_rf_antenna(struct mwifiex_private *priv, le16_to_cpu(ant_mimo->tx_ant_mode), le16_to_cpu(ant_mimo->action_rx), le16_to_cpu(ant_mimo->rx_ant_mode)); - else + } else { + priv->tx_ant = le16_to_cpu(ant_siso->ant_mode); + priv->rx_ant = le16_to_cpu(ant_siso->ant_mode); mwifiex_dbg(adapter, INFO, "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x\n", le16_to_cpu(ant_siso->action), le16_to_cpu(ant_siso->ant_mode)); - + } return 0; } @@ -553,7 +557,8 @@ static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv, if (!memcmp(resp->params.deauth.mac_addr, &priv->curr_bss_params.bss_descriptor.mac_address, sizeof(resp->params.deauth.mac_addr))) - mwifiex_reset_connect_state(priv, WLAN_REASON_DEAUTH_LEAVING); + mwifiex_reset_connect_state(priv, WLAN_REASON_DEAUTH_LEAVING, + false); return 0; } @@ -566,7 +571,7 @@ static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv, static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv, struct host_cmd_ds_command *resp) { - mwifiex_reset_connect_state(priv, WLAN_REASON_DEAUTH_LEAVING); + mwifiex_reset_connect_state(priv, WLAN_REASON_DEAUTH_LEAVING, false); return 0; } @@ -781,45 +786,44 @@ static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp, switch (type) { case HostCmd_CMD_MAC_REG_ACCESS: r.mac = &resp->params.mac_reg; - reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.mac->offset)); - reg_rw->value = r.mac->value; + reg_rw->offset = (u32) le16_to_cpu(r.mac->offset); + reg_rw->value = le32_to_cpu(r.mac->value); break; case HostCmd_CMD_BBP_REG_ACCESS: r.bbp = &resp->params.bbp_reg; - reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.bbp->offset)); - reg_rw->value = cpu_to_le32((u32) r.bbp->value); + reg_rw->offset = (u32) le16_to_cpu(r.bbp->offset); + reg_rw->value = (u32) r.bbp->value; break; case HostCmd_CMD_RF_REG_ACCESS: r.rf = &resp->params.rf_reg; - reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.rf->offset)); - reg_rw->value = cpu_to_le32((u32) r.bbp->value); + reg_rw->offset = (u32) le16_to_cpu(r.rf->offset); + reg_rw->value = (u32) r.bbp->value; break; case HostCmd_CMD_PMIC_REG_ACCESS: r.pmic = &resp->params.pmic_reg; - reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.pmic->offset)); - reg_rw->value = cpu_to_le32((u32) r.pmic->value); + reg_rw->offset = (u32) le16_to_cpu(r.pmic->offset); + reg_rw->value = (u32) r.pmic->value; break; case HostCmd_CMD_CAU_REG_ACCESS: r.rf = &resp->params.rf_reg; - reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.rf->offset)); - reg_rw->value = cpu_to_le32((u32) r.rf->value); + reg_rw->offset = (u32) le16_to_cpu(r.rf->offset); + reg_rw->value = (u32) r.rf->value; break; case HostCmd_CMD_802_11_EEPROM_ACCESS: r.eeprom = &resp->params.eeprom; - pr_debug("info: EEPROM read len=%x\n", r.eeprom->byte_count); - if (le16_to_cpu(eeprom->byte_count) < - le16_to_cpu(r.eeprom->byte_count)) { - eeprom->byte_count = cpu_to_le16(0); + pr_debug("info: EEPROM read len=%x\n", + le16_to_cpu(r.eeprom->byte_count)); + if (eeprom->byte_count < le16_to_cpu(r.eeprom->byte_count)) { + eeprom->byte_count = 0; pr_debug("info: EEPROM read length is too big\n"); return -1; } - eeprom->offset = r.eeprom->offset; - eeprom->byte_count = r.eeprom->byte_count; - if (le16_to_cpu(eeprom->byte_count) > 0) + eeprom->offset = le16_to_cpu(r.eeprom->offset); + eeprom->byte_count = le16_to_cpu(r.eeprom->byte_count); + if (eeprom->byte_count > 0) memcpy(&eeprom->value, &r.eeprom->value, - le16_to_cpu(r.eeprom->byte_count)); - + min((u16)MAX_EEPROM_DATA, eeprom->byte_count)); break; default: return -1; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c index 0104108b4ea2..a422f3306d4d 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c @@ -40,8 +40,8 @@ * - Erases current SSID and BSSID information * - Sends a disconnect event to upper layers/applications. */ -void -mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) +void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code, + bool from_ap) { struct mwifiex_adapter *adapter = priv->adapter; @@ -140,7 +140,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) if (priv->bss_mode == NL80211_IFTYPE_STATION || priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) { cfg80211_disconnected(priv->netdev, reason_code, NULL, 0, - false, GFP_KERNEL); + !from_ap, GFP_KERNEL); } eth_zero_addr(priv->cfg_bssid); @@ -474,8 +474,8 @@ void mwifiex_bt_coex_wlan_param_update_event(struct mwifiex_private *priv, scantlv = (struct mwifiex_ie_types_btcoex_scan_time *)tlv; adapter->coex_scan = scantlv->coex_scan; - adapter->coex_min_scan_time = scantlv->min_scan_time; - adapter->coex_max_scan_time = scantlv->max_scan_time; + adapter->coex_min_scan_time = le16_to_cpu(scantlv->min_scan_time); + adapter->coex_max_scan_time = le16_to_cpu(scantlv->max_scan_time); break; default: @@ -574,7 +574,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) if (priv->media_connected) { reason_code = le16_to_cpu(*(__le16 *)adapter->event_body); - mwifiex_reset_connect_state(priv, reason_code); + mwifiex_reset_connect_state(priv, reason_code, true); } break; @@ -589,7 +589,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) if (priv->media_connected) { reason_code = le16_to_cpu(*(__le16 *)adapter->event_body); - mwifiex_reset_connect_state(priv, reason_code); + mwifiex_reset_connect_state(priv, reason_code, true); } break; @@ -599,7 +599,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) if (priv->media_connected) { reason_code = le16_to_cpu(*(__le16 *)adapter->event_body); - mwifiex_reset_connect_state(priv, reason_code); + mwifiex_reset_connect_state(priv, reason_code, true); } break; @@ -708,7 +708,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_EXT_SCAN_REPORT: mwifiex_dbg(adapter, EVENT, "event: EXT_SCAN Report\n"); - if (adapter->ext_scan) + if (adapter->ext_scan && !priv->scan_aborting) ret = mwifiex_handle_event_ext_scan_report(priv, adapter->event_skb->data); diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index 8e0862657122..e06647a327b6 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -426,6 +426,10 @@ done: if (bss_desc) kfree(bss_desc->beacon_buf); kfree(bss_desc); + + if (ret < 0) + priv->attempted_bss_desc = NULL; + return ret; } @@ -1247,7 +1251,7 @@ static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv, { u16 cmd_no; - switch (le32_to_cpu(reg_rw->type)) { + switch (reg_rw->type) { case MWIFIEX_REG_MAC: cmd_no = HostCmd_CMD_MAC_REG_ACCESS; break; @@ -1282,9 +1286,9 @@ mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, { struct mwifiex_ds_reg_rw reg_rw; - reg_rw.type = cpu_to_le32(reg_type); - reg_rw.offset = cpu_to_le32(reg_offset); - reg_rw.value = cpu_to_le32(reg_value); + reg_rw.type = reg_type; + reg_rw.offset = reg_offset; + reg_rw.value = reg_value; return mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_SET); } @@ -1302,14 +1306,14 @@ mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, int ret; struct mwifiex_ds_reg_rw reg_rw; - reg_rw.type = cpu_to_le32(reg_type); - reg_rw.offset = cpu_to_le32(reg_offset); + reg_rw.type = reg_type; + reg_rw.offset = reg_offset; ret = mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_GET); if (ret) goto done; - *value = le32_to_cpu(reg_rw.value); + *value = reg_rw.value; done: return ret; @@ -1328,15 +1332,16 @@ mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, int ret; struct mwifiex_ds_read_eeprom rd_eeprom; - rd_eeprom.offset = cpu_to_le16((u16) offset); - rd_eeprom.byte_count = cpu_to_le16((u16) bytes); + rd_eeprom.offset = offset; + rd_eeprom.byte_count = bytes; /* Send request to firmware */ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS, HostCmd_ACT_GEN_GET, 0, &rd_eeprom, true); if (!ret) - memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA); + memcpy(value, rd_eeprom.value, min((u16)MAX_EEPROM_DATA, + rd_eeprom.byte_count)); return ret; } diff --git a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c index f79d00d1e294..a7e9f544f219 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c @@ -19,6 +19,7 @@ #include "main.h" #include "11ac.h" +#include "11n.h" /* This function parses security related parameters from cfg80211_ap_settings * and sets into FW understandable bss_config structure. @@ -521,9 +522,9 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) tlv += sizeof(struct host_cmd_tlv_rates) + i; } if (bss_cfg->channel && - ((bss_cfg->band_cfg == BAND_CONFIG_BG && + (((bss_cfg->band_cfg & BIT(0)) == BAND_CONFIG_BG && bss_cfg->channel <= MAX_CHANNEL_BAND_BG) || - (bss_cfg->band_cfg == BAND_CONFIG_A && + ((bss_cfg->band_cfg & BIT(0)) == BAND_CONFIG_A && bss_cfg->channel <= MAX_CHANNEL_BAND_A))) { chan_band = (struct host_cmd_tlv_channel_band *)tlv; chan_band->header.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST); @@ -833,6 +834,31 @@ void mwifiex_uap_set_channel(struct mwifiex_private *priv, config_bands |= BAND_AAC; } + switch (chandef.width) { + case NL80211_CHAN_WIDTH_5: + case NL80211_CHAN_WIDTH_10: + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + break; + case NL80211_CHAN_WIDTH_40: + if (chandef.center_freq1 < chandef.chan->center_freq) + bss_cfg->band_cfg |= MWIFIEX_SEC_CHAN_BELOW; + else + bss_cfg->band_cfg |= MWIFIEX_SEC_CHAN_ABOVE; + break; + case NL80211_CHAN_WIDTH_80: + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_160: + bss_cfg->band_cfg |= + mwifiex_get_sec_chan_offset(bss_cfg->channel) << 4; + break; + default: + mwifiex_dbg(priv->adapter, + WARN, "Unknown channel width: %d\n", + chandef.width); + break; + } + priv->adapter->config_bands = config_bands; if (old_bands != config_bands) { diff --git a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c index 666e91af59d7..bf5660eb27d3 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c @@ -272,7 +272,7 @@ int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv, int mwifiex_uap_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb) { - struct mwifiex_adapter *adapter = adapter; + struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_sta_node *src_node; struct ethhdr *p_ethhdr; struct sk_buff *skb_uap; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 870c9cd5cdf3..4341d56805f8 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -135,7 +135,8 @@ struct rtl8xxxu_rxdesc16 { u32 seq:12; u32 frag:4; - u32 nextpktlen:14; + u32 pkt_cnt:8; + u32 reserved:6; u32 nextind:1; u32 reserved0:1; @@ -198,7 +199,8 @@ struct rtl8xxxu_rxdesc16 { u32 reserved0:1; u32 nextind:1; - u32 nextpktlen:14; + u32 reserved:6; + u32 pkt_cnt:8; u32 frag:4; u32 seq:12; @@ -1245,6 +1247,7 @@ struct rtl8xxxu_priv { u32 ep_tx_normal_queue:1; u32 ep_tx_low_queue:1; u32 has_xtalk:1; + u32 rx_buf_aggregation:1; u8 xtalk; unsigned int pipe_interrupt; unsigned int pipe_in; @@ -1315,8 +1318,7 @@ struct rtl8xxxu_fileops { void (*phy_init_antenna_selection) (struct rtl8xxxu_priv *priv); void (*phy_iq_calibrate) (struct rtl8xxxu_priv *priv); void (*config_channel) (struct ieee80211_hw *hw); - int (*parse_rx_desc) (struct rtl8xxxu_priv *priv, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); + int (*parse_rx_desc) (struct rtl8xxxu_priv *priv, struct sk_buff *skb); void (*init_aggregation) (struct rtl8xxxu_priv *priv); void (*init_statistics) (struct rtl8xxxu_priv *priv); void (*enable_rf) (struct rtl8xxxu_priv *priv); @@ -1329,6 +1331,7 @@ struct rtl8xxxu_fileops { void (*report_connect) (struct rtl8xxxu_priv *priv, u8 macid, bool connect); int writeN_block_size; + int rx_agg_buf_size; char tx_desc_size; char rx_desc_size; char has_s0s1; @@ -1409,13 +1412,12 @@ void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv, u8 macid, bool connect); void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, u8 macid, bool connect); +void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_enable_rf(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_disable_rf(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen2_disable_rf(struct rtl8xxxu_priv *priv); -int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); -int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); +int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb); +int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb); int rtl8xxxu_gen2_channel_to_group(int channel); bool rtl8xxxu_gen2_simularity_compare(struct rtl8xxxu_priv *priv, int result[][8], int c1, int c2); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c index 2c86b5599a30..69d1a1453ede 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c @@ -413,13 +413,8 @@ static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv) dev_info(&priv->udev->dev, "%s: dumping efuse (0x%02zx bytes):\n", __func__, sizeof(struct rtl8192cu_efuse)); - for (i = 0; i < sizeof(struct rtl8192cu_efuse); i += 8) { - dev_info(&priv->udev->dev, "%02x: " - "%02x %02x %02x %02x %02x %02x %02x %02x\n", i, - raw[i], raw[i + 1], raw[i + 2], - raw[i + 3], raw[i + 4], raw[i + 5], - raw[i + 6], raw[i + 7]); - } + for (i = 0; i < sizeof(struct rtl8192cu_efuse); i += 8) + dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]); } return 0; } @@ -565,6 +560,7 @@ struct rtl8xxxu_fileops rtl8192cu_fops = { .phy_iq_calibrate = rtl8xxxu_gen1_phy_iq_calibrate, .config_channel = rtl8xxxu_gen1_config_channel, .parse_rx_desc = rtl8xxxu_parse_rxdesc16, + .init_aggregation = rtl8xxxu_gen1_init_aggregation, .enable_rf = rtl8xxxu_gen1_enable_rf, .disable_rf = rtl8xxxu_gen1_disable_rf, .usb_quirks = rtl8xxxu_gen1_usb_quirks, @@ -572,6 +568,7 @@ struct rtl8xxxu_fileops rtl8192cu_fops = { .update_rate_mask = rtl8xxxu_update_rate_mask, .report_connect = rtl8xxxu_gen1_report_connect, .writeN_block_size = 128, + .rx_agg_buf_size = 16000, .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32), .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16), .adda_1t_init = 0x0b1b25a0, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c index b04cf30f3959..9a1994f49b7b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c @@ -622,13 +622,8 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) dev_info(&priv->udev->dev, "%s: dumping efuse (0x%02zx bytes):\n", __func__, sizeof(struct rtl8192eu_efuse)); - for (i = 0; i < sizeof(struct rtl8192eu_efuse); i += 8) { - dev_info(&priv->udev->dev, "%02x: " - "%02x %02x %02x %02x %02x %02x %02x %02x\n", i, - raw[i], raw[i + 1], raw[i + 2], - raw[i + 3], raw[i + 4], raw[i + 5], - raw[i + 6], raw[i + 7]); - } + for (i = 0; i < sizeof(struct rtl8192eu_efuse); i += 8) + dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]); } return 0; } @@ -1249,11 +1244,9 @@ static void rtl8192eu_phy_iq_calibrate(struct rtl8xxxu_priv *priv) reg_e94 = result[i][0]; reg_e9c = result[i][1]; reg_ea4 = result[i][2]; - reg_eac = result[i][3]; reg_eb4 = result[i][4]; reg_ebc = result[i][5]; reg_ec4 = result[i][6]; - reg_ecc = result[i][7]; } if (candidate >= 0) { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c index a8e172ceab89..686c551581b1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c @@ -377,6 +377,7 @@ struct rtl8xxxu_fileops rtl8723au_fops = { .phy_iq_calibrate = rtl8xxxu_gen1_phy_iq_calibrate, .config_channel = rtl8xxxu_gen1_config_channel, .parse_rx_desc = rtl8xxxu_parse_rxdesc16, + .init_aggregation = rtl8xxxu_gen1_init_aggregation, .enable_rf = rtl8xxxu_gen1_enable_rf, .disable_rf = rtl8xxxu_gen1_disable_rf, .usb_quirks = rtl8xxxu_gen1_usb_quirks, @@ -384,6 +385,7 @@ struct rtl8xxxu_fileops rtl8723au_fops = { .update_rate_mask = rtl8xxxu_update_rate_mask, .report_connect = rtl8xxxu_gen1_report_connect, .writeN_block_size = 1024, + .rx_agg_buf_size = 16000, .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32), .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16), .adda_1t_init = 0x0b1b25a0, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index 4186e7cf0ddf..9d45afb0e3fd 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -466,13 +466,8 @@ static int rtl8723bu_parse_efuse(struct rtl8xxxu_priv *priv) dev_info(&priv->udev->dev, "%s: dumping efuse (0x%02zx bytes):\n", __func__, sizeof(struct rtl8723bu_efuse)); - for (i = 0; i < sizeof(struct rtl8723bu_efuse); i += 8) { - dev_info(&priv->udev->dev, "%02x: " - "%02x %02x %02x %02x %02x %02x %02x %02x\n", i, - raw[i], raw[i + 1], raw[i + 2], - raw[i + 3], raw[i + 4], raw[i + 5], - raw[i + 6], raw[i + 7]); - } + for (i = 0; i < sizeof(struct rtl8723bu_efuse); i += 8) + dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]); } return 0; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 9f6dbb4490a9..77048db3b32a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -44,6 +44,9 @@ int rtl8xxxu_debug = RTL8XXXU_DEBUG_EFUSE; static bool rtl8xxxu_ht40_2g; +static bool rtl8xxxu_dma_aggregation; +static int rtl8xxxu_dma_agg_timeout = -1; +static int rtl8xxxu_dma_agg_pages = -1; MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@redhat.com>"); MODULE_DESCRIPTION("RTL8XXXu USB mac80211 Wireless LAN Driver"); @@ -62,10 +65,14 @@ module_param_named(debug, rtl8xxxu_debug, int, 0600); MODULE_PARM_DESC(debug, "Set debug mask"); module_param_named(ht40_2g, rtl8xxxu_ht40_2g, bool, 0600); MODULE_PARM_DESC(ht40_2g, "Enable HT40 support on the 2.4GHz band"); +module_param_named(dma_aggregation, rtl8xxxu_dma_aggregation, bool, 0600); +MODULE_PARM_DESC(dma_aggregation, "Enable DMA packet aggregation"); +module_param_named(dma_agg_timeout, rtl8xxxu_dma_agg_timeout, int, 0600); +MODULE_PARM_DESC(dma_agg_timeout, "Set DMA aggregation timeout (range 1-127)"); +module_param_named(dma_agg_pages, rtl8xxxu_dma_agg_pages, int, 0600); +MODULE_PARM_DESC(dma_agg_pages, "Set DMA aggregation pages (range 1-127, 0 to disable)"); #define USB_VENDOR_ID_REALTEK 0x0bda -/* Minimum IEEE80211_MAX_FRAME_LEN */ -#define RTL_RX_BUFFER_SIZE IEEE80211_MAX_FRAME_LEN #define RTL8XXXU_RX_URBS 32 #define RTL8XXXU_RX_URB_PENDING_WATER 8 #define RTL8XXXU_TX_URBS 64 @@ -4407,6 +4414,73 @@ void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.media_status_rpt)); } +void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv) +{ + u8 agg_ctrl, usb_spec, page_thresh, timeout; + + usb_spec = rtl8xxxu_read8(priv, REG_USB_SPECIAL_OPTION); + usb_spec &= ~USB_SPEC_USB_AGG_ENABLE; + rtl8xxxu_write8(priv, REG_USB_SPECIAL_OPTION, usb_spec); + + agg_ctrl = rtl8xxxu_read8(priv, REG_TRXDMA_CTRL); + agg_ctrl &= ~TRXDMA_CTRL_RXDMA_AGG_EN; + + if (!rtl8xxxu_dma_aggregation) { + rtl8xxxu_write8(priv, REG_TRXDMA_CTRL, agg_ctrl); + return; + } + + agg_ctrl |= TRXDMA_CTRL_RXDMA_AGG_EN; + rtl8xxxu_write8(priv, REG_TRXDMA_CTRL, agg_ctrl); + + /* + * The number of packets we can take looks to be buffer size / 512 + * which matches the 512 byte rounding we have to do when de-muxing + * the packets. + * + * Sample numbers from the vendor driver: + * USB High-Speed mode values: + * RxAggBlockCount = 8 : 512 byte unit + * RxAggBlockTimeout = 6 + * RxAggPageCount = 48 : 128 byte unit + * RxAggPageTimeout = 4 or 6 (absolute time 34ms/(2^6)) + */ + + page_thresh = (priv->fops->rx_agg_buf_size / 512); + if (rtl8xxxu_dma_agg_pages >= 0) { + if (rtl8xxxu_dma_agg_pages <= page_thresh) + timeout = page_thresh; + else if (rtl8xxxu_dma_agg_pages <= 6) + dev_err(&priv->udev->dev, + "%s: dma_agg_pages=%i too small, minium is 6\n", + __func__, rtl8xxxu_dma_agg_pages); + else + dev_err(&priv->udev->dev, + "%s: dma_agg_pages=%i larger than limit %i\n", + __func__, rtl8xxxu_dma_agg_pages, page_thresh); + } + rtl8xxxu_write8(priv, REG_RXDMA_AGG_PG_TH, page_thresh); + /* + * REG_RXDMA_AGG_PG_TH + 1 seems to be the timeout register on + * gen2 chips and rtl8188eu. The rtl8723au seems unhappy if we + * don't set it, so better set both. + */ + timeout = 4; + + if (rtl8xxxu_dma_agg_timeout >= 0) { + if (rtl8xxxu_dma_agg_timeout <= 127) + timeout = rtl8xxxu_dma_agg_timeout; + else + dev_err(&priv->udev->dev, + "%s: Invalid dma_agg_timeout: %i\n", + __func__, rtl8xxxu_dma_agg_timeout); + } + + rtl8xxxu_write8(priv, REG_RXDMA_AGG_PG_TH + 1, timeout); + rtl8xxxu_write8(priv, REG_USB_DMA_AGG_TO, timeout); + priv->rx_buf_aggregation = 1; +} + static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg) { u32 val32; @@ -5045,55 +5119,143 @@ static void rtl8xxxu_rx_urb_work(struct work_struct *work) } } -int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) +static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, + struct sk_buff *skb) +{ + struct rtl8723bu_c2h *c2h = (struct rtl8723bu_c2h *)skb->data; + struct device *dev = &priv->udev->dev; + int len; + + len = skb->len - 2; + + dev_dbg(dev, "C2H ID %02x seq %02x, len %02x source %02x\n", + c2h->id, c2h->seq, len, c2h->bt_info.response_source); + + switch(c2h->id) { + case C2H_8723B_BT_INFO: + if (c2h->bt_info.response_source > + BT_INFO_SRC_8723B_BT_ACTIVE_SEND) + dev_dbg(dev, "C2H_BT_INFO WiFi only firmware\n"); + else + dev_dbg(dev, "C2H_BT_INFO BT/WiFi coexist firmware\n"); + + if (c2h->bt_info.bt_has_reset) + dev_dbg(dev, "BT has been reset\n"); + if (c2h->bt_info.tx_rx_mask) + dev_dbg(dev, "BT TRx mask\n"); + + break; + case C2H_8723B_BT_MP_INFO: + dev_dbg(dev, "C2H_MP_INFO ext ID %02x, status %02x\n", + c2h->bt_mp_info.ext_id, c2h->bt_mp_info.status); + break; + case C2H_8723B_RA_REPORT: + dev_dbg(dev, + "C2H RA RPT: rate %02x, unk %i, macid %02x, noise %i\n", + c2h->ra_report.rate, c2h->ra_report.dummy0_0, + c2h->ra_report.macid, c2h->ra_report.noisy_state); + break; + default: + dev_info(dev, "Unhandled C2H event %02x seq %02x\n", + c2h->id, c2h->seq); + print_hex_dump(KERN_INFO, "C2H content: ", DUMP_PREFIX_NONE, + 16, 1, c2h->raw.payload, len, false); + break; + } +} + +int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) { - struct rtl8xxxu_rxdesc16 *rx_desc = - (struct rtl8xxxu_rxdesc16 *)skb->data; + struct ieee80211_hw *hw = priv->hw; + struct ieee80211_rx_status *rx_status; + struct rtl8xxxu_rxdesc16 *rx_desc; struct rtl8723au_phy_stats *phy_stats; - __le32 *_rx_desc_le = (__le32 *)skb->data; - u32 *_rx_desc = (u32 *)skb->data; + struct sk_buff *next_skb = NULL; + __le32 *_rx_desc_le; + u32 *_rx_desc; int drvinfo_sz, desc_shift; - int i; + int i, pkt_cnt, pkt_len, urb_len, pkt_offset; - for (i = 0; i < (sizeof(struct rtl8xxxu_rxdesc16) / sizeof(u32)); i++) - _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]); + urb_len = skb->len; + pkt_cnt = 0; - skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc16)); + do { + rx_desc = (struct rtl8xxxu_rxdesc16 *)skb->data; + _rx_desc_le = (__le32 *)skb->data; + _rx_desc = (u32 *)skb->data; - phy_stats = (struct rtl8723au_phy_stats *)skb->data; + for (i = 0; + i < (sizeof(struct rtl8xxxu_rxdesc16) / sizeof(u32)); i++) + _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]); - drvinfo_sz = rx_desc->drvinfo_sz * 8; - desc_shift = rx_desc->shift; - skb_pull(skb, drvinfo_sz + desc_shift); + /* + * Only read pkt_cnt from the header if we're parsing the + * first packet + */ + if (!pkt_cnt) + pkt_cnt = rx_desc->pkt_cnt; + pkt_len = rx_desc->pktlen; - if (rx_desc->phy_stats) - rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats, - rx_desc->rxmcs); + drvinfo_sz = rx_desc->drvinfo_sz * 8; + desc_shift = rx_desc->shift; + pkt_offset = roundup(pkt_len + drvinfo_sz + desc_shift + + sizeof(struct rtl8xxxu_rxdesc16), 128); - rx_status->mactime = le32_to_cpu(rx_desc->tsfl); - rx_status->flag |= RX_FLAG_MACTIME_START; + if (pkt_cnt > 1) + next_skb = skb_clone(skb, GFP_ATOMIC); - if (!rx_desc->swdec) - rx_status->flag |= RX_FLAG_DECRYPTED; - if (rx_desc->crc32) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - if (rx_desc->bw) - rx_status->flag |= RX_FLAG_40MHZ; + rx_status = IEEE80211_SKB_RXCB(skb); + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - if (rx_desc->rxht) { - rx_status->flag |= RX_FLAG_HT; - rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; - } else { - rx_status->rate_idx = rx_desc->rxmcs; - } + skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc16)); + + phy_stats = (struct rtl8723au_phy_stats *)skb->data; + + skb_pull(skb, drvinfo_sz + desc_shift); + + skb_trim(skb, pkt_len); + + if (rx_desc->phy_stats) + rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats, + rx_desc->rxmcs); + + rx_status->mactime = le32_to_cpu(rx_desc->tsfl); + rx_status->flag |= RX_FLAG_MACTIME_START; + + if (!rx_desc->swdec) + rx_status->flag |= RX_FLAG_DECRYPTED; + if (rx_desc->crc32) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (rx_desc->bw) + rx_status->flag |= RX_FLAG_40MHZ; + + if (rx_desc->rxht) { + rx_status->flag |= RX_FLAG_HT; + rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; + } else { + rx_status->rate_idx = rx_desc->rxmcs; + } + + rx_status->freq = hw->conf.chandef.chan->center_freq; + rx_status->band = hw->conf.chandef.chan->band; + + ieee80211_rx_irqsafe(hw, skb); + + skb = next_skb; + if (skb) + skb_pull(next_skb, pkt_offset); + + pkt_cnt--; + urb_len -= pkt_offset; + } while (skb && urb_len > 0 && pkt_cnt > 0); return RX_TYPE_DATA_PKT; } -int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) +int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb) { + struct ieee80211_hw *hw = priv->hw; + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); struct rtl8xxxu_rxdesc24 *rx_desc = (struct rtl8xxxu_rxdesc24 *)skb->data; struct rtl8723au_phy_stats *phy_stats; @@ -5105,6 +5267,8 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb, for (i = 0; i < (sizeof(struct rtl8xxxu_rxdesc24) / sizeof(u32)); i++) _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]); + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc24)); phy_stats = (struct rtl8723au_phy_stats *)skb->data; @@ -5116,6 +5280,8 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb, if (rx_desc->rpt_sel) { struct device *dev = &priv->udev->dev; dev_dbg(dev, "%s: C2H packet\n", __func__); + rtl8723bu_handle_c2h(priv, skb); + dev_kfree_skb(skb); return RX_TYPE_C2H; } @@ -5140,52 +5306,11 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb, rx_status->rate_idx = rx_desc->rxmcs; } - return RX_TYPE_DATA_PKT; -} - -static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, - struct sk_buff *skb) -{ - struct rtl8723bu_c2h *c2h = (struct rtl8723bu_c2h *)skb->data; - struct device *dev = &priv->udev->dev; - int len; - - len = skb->len - 2; - - dev_dbg(dev, "C2H ID %02x seq %02x, len %02x source %02x\n", - c2h->id, c2h->seq, len, c2h->bt_info.response_source); - - switch(c2h->id) { - case C2H_8723B_BT_INFO: - if (c2h->bt_info.response_source > - BT_INFO_SRC_8723B_BT_ACTIVE_SEND) - dev_dbg(dev, "C2H_BT_INFO WiFi only firmware\n"); - else - dev_dbg(dev, "C2H_BT_INFO BT/WiFi coexist firmware\n"); - - if (c2h->bt_info.bt_has_reset) - dev_dbg(dev, "BT has been reset\n"); - if (c2h->bt_info.tx_rx_mask) - dev_dbg(dev, "BT TRx mask\n"); + rx_status->freq = hw->conf.chandef.chan->center_freq; + rx_status->band = hw->conf.chandef.chan->band; - break; - case C2H_8723B_BT_MP_INFO: - dev_dbg(dev, "C2H_MP_INFO ext ID %02x, status %02x\n", - c2h->bt_mp_info.ext_id, c2h->bt_mp_info.status); - break; - case C2H_8723B_RA_REPORT: - dev_dbg(dev, - "C2H RA RPT: rate %02x, unk %i, macid %02x, noise %i\n", - c2h->ra_report.rate, c2h->ra_report.dummy0_0, - c2h->ra_report.macid, c2h->ra_report.noisy_state); - break; - default: - dev_info(dev, "Unhandled C2H event %02x seq %02x\n", - c2h->id, c2h->seq); - print_hex_dump(KERN_INFO, "C2H content: ", DUMP_PREFIX_NONE, - 16, 1, c2h->raw.payload, len, false); - break; - } + ieee80211_rx_irqsafe(hw, skb); + return RX_TYPE_DATA_PKT; } static void rtl8xxxu_rx_complete(struct urb *urb) @@ -5195,26 +5320,12 @@ static void rtl8xxxu_rx_complete(struct urb *urb) struct ieee80211_hw *hw = rx_urb->hw; struct rtl8xxxu_priv *priv = hw->priv; struct sk_buff *skb = (struct sk_buff *)urb->context; - struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); struct device *dev = &priv->udev->dev; - int rx_type; skb_put(skb, urb->actual_length); if (urb->status == 0) { - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - - rx_type = priv->fops->parse_rx_desc(priv, skb, rx_status); - - rx_status->freq = hw->conf.chandef.chan->center_freq; - rx_status->band = hw->conf.chandef.chan->band; - - if (rx_type == RX_TYPE_DATA_PKT) - ieee80211_rx_irqsafe(hw, skb); - else { - rtl8723bu_handle_c2h(priv, skb); - dev_kfree_skb(skb); - } + priv->fops->parse_rx_desc(priv, skb); skb = NULL; rx_urb->urb.context = NULL; @@ -5234,12 +5345,20 @@ cleanup: static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv, struct rtl8xxxu_rx_urb *rx_urb) { + struct rtl8xxxu_fileops *fops = priv->fops; struct sk_buff *skb; int skb_size; int ret, rx_desc_sz; - rx_desc_sz = priv->fops->rx_desc_size; - skb_size = rx_desc_sz + RTL_RX_BUFFER_SIZE; + rx_desc_sz = fops->rx_desc_size; + + if (priv->rx_buf_aggregation && fops->rx_agg_buf_size) { + skb_size = fops->rx_agg_buf_size; + skb_size += (rx_desc_sz + sizeof(struct rtl8723au_phy_stats)); + } else { + skb_size = IEEE80211_MAX_FRAME_LEN; + } + skb = __netdev_alloc_skb(NULL, skb_size, GFP_KERNEL); if (!skb) return -ENOMEM; @@ -5267,7 +5386,7 @@ static void rtl8xxxu_int_complete(struct urb *urb) if (ret) usb_unanchor_urb(urb); } else { - dev_info(dev, "%s: Error %i\n", __func__, urb->status); + dev_dbg(dev, "%s: Error %i\n", __func__, urb->status); } } diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index b0e0c642302c..921c5653fff2 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -405,7 +405,11 @@ #define REG_DWBCN1_CTRL_8723B 0x0228 /* 0x0280 ~ 0x02FF RXDMA Configuration */ -#define REG_RXDMA_AGG_PG_TH 0x0280 +#define REG_RXDMA_AGG_PG_TH 0x0280 /* 0-7 : USB DMA size bits + 8-14: USB DMA timeout + 15 : Aggregation enable + Only seems to be used + on 8723bu/8192eu */ #define RXDMA_USB_AGG_ENABLE BIT(31) #define REG_RXPKT_NUM 0x0284 #define RXPKT_NUM_RXDMA_IDLE BIT(17) @@ -1052,10 +1056,14 @@ #define USB_HIMR_ROK BIT(0) /* Receive DMA OK Interrupt */ #define REG_USB_SPECIAL_OPTION 0xfe55 +#define USB_SPEC_USB_AGG_ENABLE BIT(3) /* Enable USB aggregation */ +#define USB_SPEC_INT_BULK_SELECT BIT(4) /* Use interrupt endpoint to + deliver interrupt packet. + 0: Use int, 1: use bulk */ #define REG_USB_HRPWM 0xfe58 #define REG_USB_DMA_AGG_TO 0xfe5b -#define REG_USB_AGG_TO 0xfe5c -#define REG_USB_AGG_TH 0xfe5d +#define REG_USB_AGG_TIMEOUT 0xfe5c +#define REG_USB_AGG_THRESH 0xfe5d #define REG_NORMAL_SIE_VID 0xfe60 /* 0xfe60 - 0xfe61 */ #define REG_NORMAL_SIE_PID 0xfe62 /* 0xfe62 - 0xfe63 */ diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index b660c214dc71..91cc1397b150 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -901,7 +901,7 @@ void exhalbtc_stack_update_profile_info(void) { } -void exhalbtc_update_min_bt_rssi(char bt_rssi) +void exhalbtc_update_min_bt_rssi(s8 bt_rssi) { struct btc_coexist *btcoexist = &gl_bt_coexist; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index 3cbe34c535ec..3d308ebbe048 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -433,7 +433,7 @@ struct btc_stack_info { u8 num_of_hid; bool pan_exist; bool unknown_acl_exist; - char min_bt_rssi; + s8 min_bt_rssi; }; struct btc_statistics { @@ -537,7 +537,7 @@ void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len, void exhalbtc_stack_update_profile_info(void); void exhalbtc_set_hci_version(u16 hci_version); void exhalbtc_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version); -void exhalbtc_update_min_bt_rssi(char bt_rssi); +void exhalbtc_update_min_bt_rssi(s8 bt_rssi); void exhalbtc_set_bt_exist(bool bt_exist); void exhalbtc_set_chip_type(u8 chip_type); void exhalbtc_set_ant_num(struct rtl_priv *rtlpriv, u8 type, u8 ant_num); diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 3a0faa8fe9d4..41f77f8a309e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -526,7 +526,7 @@ static void _rtl_add_wowlan_patterns(struct ieee80211_hw *hw, /* 3. calculate crc */ rtl_pattern.crc = _calculate_wol_pattern_crc(content, len); RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, - "CRC_Remainder = 0x%x", rtl_pattern.crc); + "CRC_Remainder = 0x%x\n", rtl_pattern.crc); /* 4. write crc & mask_for_hw to hw */ rtlpriv->cfg->ops->add_wowlan_pattern(hw, &rtl_pattern, i); diff --git a/drivers/net/wireless/realtek/rtlwifi/debug.c b/drivers/net/wireless/realtek/rtlwifi/debug.c index fd25abad2b9e..33905bbacad2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/debug.c +++ b/drivers/net/wireless/realtek/rtlwifi/debug.c @@ -48,3 +48,28 @@ void rtl_dbgp_flag_init(struct ieee80211_hw *hw) /*Init Debug flag enable condition */ } EXPORT_SYMBOL_GPL(rtl_dbgp_flag_init); + +#ifdef CONFIG_RTLWIFI_DEBUG +void _rtl_dbg_trace(struct rtl_priv *rtlpriv, int comp, int level, + const char *modname, const char *fmt, ...) +{ + if (unlikely((comp & rtlpriv->dbg.global_debugcomponents) && + (level <= rtlpriv->dbg.global_debuglevel))) { + struct va_format vaf; + va_list args; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + printk(KERN_DEBUG "%s:%ps:<%lx-%x> %pV", + modname, __builtin_return_address(0), + in_interrupt(), in_atomic(), + &vaf); + + va_end(args); + } +} +EXPORT_SYMBOL_GPL(_rtl_dbg_trace); +#endif diff --git a/drivers/net/wireless/realtek/rtlwifi/debug.h b/drivers/net/wireless/realtek/rtlwifi/debug.h index fc794b3e9f4a..6156a79328c1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/debug.h +++ b/drivers/net/wireless/realtek/rtlwifi/debug.h @@ -174,15 +174,16 @@ do { \ } \ } while (0) + +struct rtl_priv; + +__printf(5, 6) +void _rtl_dbg_trace(struct rtl_priv *rtlpriv, int comp, int level, + const char *modname, const char *fmt, ...); + #define RT_TRACE(rtlpriv, comp, level, fmt, ...) \ -do { \ - if (unlikely(((comp) & rtlpriv->dbg.global_debugcomponents) && \ - ((level) <= rtlpriv->dbg.global_debuglevel))) { \ - printk(KERN_DEBUG KBUILD_MODNAME ":%s():<%lx-%x> " fmt, \ - __func__, in_interrupt(), in_atomic(), \ - ##__VA_ARGS__); \ - } \ -} while (0) + _rtl_dbg_trace(rtlpriv, comp, level, \ + KBUILD_MODNAME, fmt, ##__VA_ARGS__) #define RTPRINT(rtlpriv, dbgtype, dbgflag, fmt, ...) \ do { \ diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.c b/drivers/net/wireless/realtek/rtlwifi/efuse.c index 0b4082c9272a..7becfef6cd5c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/efuse.c +++ b/drivers/net/wireless/realtek/rtlwifi/efuse.c @@ -24,6 +24,7 @@ *****************************************************************************/ #include "wifi.h" #include "efuse.h" +#include "pci.h" #include <linux/export.h> static const u8 MAX_PGPKT_SIZE = 9; @@ -1243,3 +1244,80 @@ static u8 efuse_calculate_word_cnts(u8 word_en) return word_cnts; } +int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv, + int max_size, u8 *hwinfo, int *params) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct device *dev = &rtlpcipriv->dev.pdev->dev; + u16 eeprom_id; + u16 i, usvalue; + + switch (rtlefuse->epromtype) { + case EEPROM_BOOT_EFUSE: + rtl_efuse_shadow_map_update(hw); + break; + + case EEPROM_93C46: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "RTL8XXX did not boot from eeprom, check it !!\n"); + return 1; + + default: + dev_warn(dev, "no efuse data\n"); + return 1; + } + + memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], max_size); + + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP", + hwinfo, max_size); + + eeprom_id = *((u16 *)&hwinfo[0]); + if (eeprom_id != params[0]) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "EEPROM ID(%#x) is invalid!!\n", eeprom_id); + rtlefuse->autoload_failflag = true; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); + rtlefuse->autoload_failflag = false; + } + + if (rtlefuse->autoload_failflag) + return 1; + + rtlefuse->eeprom_vid = *(u16 *)&hwinfo[params[1]]; + rtlefuse->eeprom_did = *(u16 *)&hwinfo[params[2]]; + rtlefuse->eeprom_svid = *(u16 *)&hwinfo[params[3]]; + rtlefuse->eeprom_smid = *(u16 *)&hwinfo[params[4]]; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROMId = 0x%4x\n", eeprom_id); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); + + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *)&hwinfo[params[5] + i]; + *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue; + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%pM\n", rtlefuse->dev_addr); + + rtlefuse->eeprom_channelplan = *&hwinfo[params[6]]; + rtlefuse->eeprom_version = *(u16 *)&hwinfo[params[7]]; + rtlefuse->txpwr_fromeprom = true; + rtlefuse->eeprom_oemid = *&hwinfo[params[8]]; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); + + /* set channel plan to world wide 13 */ + rtlefuse->channel_plan = params[9]; + + return 0; +} +EXPORT_SYMBOL_GPL(rtl_get_hwinfo); diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.h b/drivers/net/wireless/realtek/rtlwifi/efuse.h index be02e7894c61..51aa1210def5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/efuse.h +++ b/drivers/net/wireless/realtek/rtlwifi/efuse.h @@ -109,5 +109,7 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw); void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw); void efuse_force_write_vendor_Id(struct ieee80211_hw *hw); void efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx); +int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv, + int max_size, u8 *hwinfo, int *params); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c index 93579cac0d45..9a64f9b703e5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/ps.c +++ b/drivers/net/wireless/realtek/rtlwifi/ps.c @@ -76,9 +76,9 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw) } EXPORT_SYMBOL(rtl_ps_disable_nic); -bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, - enum rf_pwrstate state_toset, - u32 changesource, bool protect_or_not) +static bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, + enum rf_pwrstate state_toset, + u32 changesource) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); @@ -86,9 +86,6 @@ bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, bool actionallowed = false; u16 rfwait_cnt = 0; - if (protect_or_not) - goto no_protect; - /*Only one thread can change *the RF state at one time, and others *should wait to be executed. @@ -119,7 +116,6 @@ bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, } } -no_protect: rtstate = ppsc->rfpwr_state; switch (state_toset) { @@ -162,15 +158,12 @@ no_protect: if (actionallowed) rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset); - if (!protect_or_not) { - spin_lock(&rtlpriv->locks.rf_ps_lock); - ppsc->rfchange_inprogress = false; - spin_unlock(&rtlpriv->locks.rf_ps_lock); - } + spin_lock(&rtlpriv->locks.rf_ps_lock); + ppsc->rfchange_inprogress = false; + spin_unlock(&rtlpriv->locks.rf_ps_lock); return actionallowed; } -EXPORT_SYMBOL(rtl_ps_set_rf_state); static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) { @@ -191,7 +184,7 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) } rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate, - RF_CHANGE_BY_IPS, false); + RF_CHANGE_BY_IPS); if (ppsc->inactive_pwrstate == ERFOFF && rtlhal->interface == INTF_PCI) { @@ -587,7 +580,7 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw) } spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); - rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false); + rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS); spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); } @@ -630,7 +623,7 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) spin_unlock(&rtlpriv->locks.rf_ps_lock); spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); - rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS , false); + rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS); spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.h b/drivers/net/wireless/realtek/rtlwifi/ps.h index 29dfc514212d..0df2b5203030 100644 --- a/drivers/net/wireless/realtek/rtlwifi/ps.h +++ b/drivers/net/wireless/realtek/rtlwifi/ps.h @@ -28,9 +28,6 @@ #define MAX_SW_LPS_SLEEP_INTV 5 -bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, - enum rf_pwrstate state_toset, u32 changesource, - bool protect_or_not); bool rtl_ps_enable_nic(struct ieee80211_hw *hw); bool rtl_ps_disable_nic(struct ieee80211_hw *hw); void rtl_ips_nic_off(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/rc.c b/drivers/net/wireless/realtek/rtlwifi/rc.c index 1aca77719521..ce8621a0f7aa 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rc.c +++ b/drivers/net/wireless/realtek/rtlwifi/rc.c @@ -94,7 +94,7 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, struct ieee80211_sta *sta, struct ieee80211_tx_rate *rate, struct ieee80211_tx_rate_control *txrc, - u8 tries, char rix, int rtsctsenable, + u8 tries, s8 rix, int rtsctsenable, bool not_data) { struct rtl_mac *mac = rtl_mac(rtlpriv); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/Makefile b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/Makefile index a85419a37651..676e7de27f27 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/Makefile @@ -12,4 +12,4 @@ rtl8188ee-objs := \ obj-$(CONFIG_RTL8188EE) += rtl8188ee.o -ccflags-y += -Idrivers/net/wireless/rtlwifi -D__CHECK_ENDIAN__ +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c index db9a7829d568..f936a491371b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c @@ -886,7 +886,7 @@ static void dm_txpower_track_cb_therm(struct ieee80211_hw *hw) u8 thermalvalue_avg_count = 0; u32 thermalvalue_avg = 0; long ele_d, temp_cck; - char ofdm_index[2], cck_index = 0, + s8 ofdm_index[2], cck_index = 0, ofdm_index_old[2] = {0, 0}, cck_index_old = 0; int i = 0; /*bool is2t = false;*/ @@ -898,7 +898,7 @@ static void dm_txpower_track_cb_therm(struct ieee80211_hw *hw) /*0.1 the following TWO tables decide the *final index of OFDM/CCK swing table */ - char delta_swing_table_idx[2][15] = { + s8 delta_swing_table_idx[2][15] = { {0, 0, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11}, {0, 0, -1, -2, -3, -4, -4, -4, -4, -5, -7, -8, -9, -9, -10} }; @@ -1790,6 +1790,7 @@ void rtl88e_dm_watchdog(struct ieee80211_hw *hw) if (ppsc->p2p_ps_info.p2p_ps_mode) fw_ps_awake = false; + spin_lock(&rtlpriv->locks.rf_ps_lock); if ((ppsc->rfpwr_state == ERFON) && ((!fw_current_inpsmode) && fw_ps_awake) && (!ppsc->rfchange_inprogress)) { @@ -1802,4 +1803,5 @@ void rtl88e_dm_watchdog(struct ieee80211_hw *hw) rtl88e_dm_check_edca_turbo(hw); rtl88e_dm_antenna_diversity(hw); } + spin_unlock(&rtlpriv->locks.rf_ps_lock); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c index 8ee83b093c0d..4ab6201daf1a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c @@ -1835,74 +1835,24 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u16 i, usvalue; - u8 hwinfo[HWSET_MAX_SIZE]; - u16 eeprom_id; - - if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { - rtl_efuse_shadow_map_update(hw); - - memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], - HWSET_MAX_SIZE); - } else if (rtlefuse->epromtype == EEPROM_93C46) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "RTL819X Not boot from eeprom, check it !!"); - return; - } else { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "boot from neither eeprom nor efuse, check it !!"); + int params[] = {RTL8188E_EEPROM_ID, EEPROM_VID, EEPROM_DID, + EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, + EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, + COUNTRY_CODE_WORLD_WIDE_13}; + u8 *hwinfo; + + hwinfo = kzalloc(HWSET_MAX_SIZE, GFP_KERNEL); + if (!hwinfo) return; - } - - RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP\n", - hwinfo, HWSET_MAX_SIZE); - eeprom_id = *((u16 *)&hwinfo[0]); - if (eeprom_id != RTL8188E_EEPROM_ID) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "EEPROM ID(%#x) is invalid!!\n", eeprom_id); - rtlefuse->autoload_failflag = true; - } else { - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); - rtlefuse->autoload_failflag = false; - } + if (rtl_get_hwinfo(hw, rtlpriv, HWSET_MAX_SIZE, hwinfo, params)) + goto exit; - if (rtlefuse->autoload_failflag == true) - return; - /*VID DID SVID SDID*/ - rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; - rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID]; - rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID]; - rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID]; - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROMId = 0x%4x\n", eeprom_id); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); - /*customer ID*/ - rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID]; if (rtlefuse->eeprom_oemid == 0xFF) - rtlefuse->eeprom_oemid = 0; + rtlefuse->eeprom_oemid = 0; RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); - /*EEPROM version*/ - rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; - /*mac address*/ - for (i = 0; i < 6; i += 2) { - usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; - *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue; - } - - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - "dev_addr: %pM\n", rtlefuse->dev_addr); - /*channel plan */ - rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN]; /* set channel plan from efuse */ rtlefuse->channel_plan = rtlefuse->eeprom_channelplan; /*tx power*/ @@ -1976,6 +1926,8 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw) } } +exit: + kfree(hwinfo); } static void _rtl88ee_hal_customized_behavior(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c index 416a9ba6382e..7498a1218cba 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c @@ -373,7 +373,7 @@ static bool _rtl88e_phy_bb8188e_config_parafile(struct ieee80211_hw *hw) rtstatus = phy_config_bb_with_headerfile(hw, BASEBAND_CONFIG_PHY_REG); if (!rtstatus) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!"); + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!\n"); return false; } @@ -383,7 +383,7 @@ static bool _rtl88e_phy_bb8188e_config_parafile(struct ieee80211_hw *hw) phy_config_bb_with_pghdr(hw, BASEBAND_CONFIG_PHY_REG); } if (!rtstatus) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!"); + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!\n"); return false; } rtstatus = @@ -1239,7 +1239,7 @@ u8 rtl88e_phy_sw_chnl(struct ieee80211_hw *hw) if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { rtl88e_phy_sw_chnl_callback(hw); RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, - "sw_chnl_inprogress false schdule workitem current channel %d\n", + "sw_chnl_inprogress false schedule workitem current channel %d\n", rtlphy->current_channel); rtlphy->sw_chnl_inprogress = false; } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/rf.c index 40893cef7dfe..26ac4c2903c7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/rf.c @@ -498,7 +498,7 @@ static bool _rtl88e_phy_rf6052_config_parafile(struct ieee80211_hw *hw) if (rtstatus != true) { RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, - "Radio[%d] Fail!!", rfpath); + "Radio[%d] Fail!!\n", rfpath); return false; } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c index 11701064b0e1..3e3b88664883 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c @@ -59,7 +59,7 @@ static void _rtl88ee_query_rxphystatus(struct ieee80211_hw *hw, struct phy_status_rpt *phystrpt = (struct phy_status_rpt *)p_drvinfo; struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); - char rx_pwr_all = 0, rx_pwr[4]; + s8 rx_pwr_all = 0, rx_pwr[4]; u8 rf_rx_num = 0, evm, pwdb_all; u8 i, max_spatial_stream; u32 rssi, total_rssi = 0; @@ -540,7 +540,7 @@ void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_88e)); @@ -703,7 +703,7 @@ void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h index 5a24d194ac76..9a1c2087adee 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h @@ -593,8 +593,8 @@ struct rx_fwinfo_88e { u8 pwdb_all; u8 cfosho[4]; u8 cfotail[4]; - char rxevm[2]; - char rxsnr[4]; + s8 rxevm[2]; + s8 rxsnr[4]; u8 pdsnr[2]; u8 csi_current[2]; u8 csi_target[2]; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/dm_common.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/dm_common.h index 4422e31fedd9..6a72d0c8afa0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/dm_common.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/dm_common.h @@ -135,7 +135,7 @@ void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw); void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw); void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal); -void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta); void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery); void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c index 77e61b19bf36..60ab2ec4f4ef 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c @@ -213,7 +213,7 @@ bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw) rtstatus = rtlpriv->cfg->ops->config_bb_with_headerfile(hw, BASEBAND_CONFIG_PHY_REG); if (!rtstatus) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!"); + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!\n"); return false; } if (rtlphy->rf_type == RF_1T2R) { @@ -226,7 +226,7 @@ bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw) BASEBAND_CONFIG_PHY_REG); } if (!rtstatus) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!"); + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!\n"); return false; } rtstatus = rtlpriv->cfg->ops->config_bb_with_headerfile(hw, @@ -757,7 +757,7 @@ u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw) if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { rtl92c_phy_sw_chnl_callback(hw); RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, - "sw_chnl_inprogress false schdule workitem\n"); + "sw_chnl_inprogress false schedule workitem\n"); rtlphy->sw_chnl_inprogress = false; } else { RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, @@ -1353,7 +1353,7 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, } static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, - char delta, bool is2t) + s8 delta, bool is2t) { } @@ -1518,7 +1518,7 @@ void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw) } EXPORT_SYMBOL(rtl92c_phy_lc_calibrate); -void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta) +void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.h index 64bc49f4dbc6..202412577bf0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.h @@ -210,7 +210,7 @@ u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval); -void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta); void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c index 04eb5c3f8464..244607951e28 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c @@ -1680,58 +1680,18 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u16 i, usvalue; - u8 hwinfo[HWSET_MAX_SIZE]; - u16 eeprom_id; - - if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { - rtl_efuse_shadow_map_update(hw); - - memcpy((void *)hwinfo, - (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], - HWSET_MAX_SIZE); - } else if (rtlefuse->epromtype == EEPROM_93C46) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "RTL819X Not boot from eeprom, check it !!"); - } - - RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP", - hwinfo, HWSET_MAX_SIZE); - - eeprom_id = *((u16 *)&hwinfo[0]); - if (eeprom_id != RTL8190_EEPROM_ID) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "EEPROM ID(%#x) is invalid!!\n", eeprom_id); - rtlefuse->autoload_failflag = true; - } else { - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); - rtlefuse->autoload_failflag = false; - } - - if (rtlefuse->autoload_failflag) + int params[] = {RTL8190_EEPROM_ID, EEPROM_VID, EEPROM_DID, + EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, + EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, + COUNTRY_CODE_WORLD_WIDE_13}; + u8 *hwinfo; + + hwinfo = kzalloc(HWSET_MAX_SIZE, GFP_KERNEL); + if (!hwinfo) return; - rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; - rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID]; - rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID]; - rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID]; - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROMId = 0x%4x\n", eeprom_id); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); - - for (i = 0; i < 6; i += 2) { - usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; - *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; - } - - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%pM\n", rtlefuse->dev_addr); + if (rtl_get_hwinfo(hw, rtlpriv, HWSET_MAX_SIZE, hwinfo, params)) + goto exit; _rtl92ce_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag, @@ -1740,18 +1700,6 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) rtl8192ce_read_bt_coexist_info_from_hwpg(hw, rtlefuse->autoload_failflag, hwinfo); - - rtlefuse->eeprom_channelplan = *&hwinfo[EEPROM_CHANNELPLAN]; - rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; - rtlefuse->txpwr_fromeprom = true; - rtlefuse->eeprom_oemid = *&hwinfo[EEPROM_CUSTOMER_ID]; - - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); - - /* set channel paln to world wide 13 */ - rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; - if (rtlhal->oem_id == RT_CID_DEFAULT) { switch (rtlefuse->eeprom_oemid) { case EEPROM_CID_DEFAULT: @@ -1775,10 +1723,10 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) default: rtlhal->oem_id = RT_CID_DEFAULT; break; - } } - +exit: + kfree(hwinfo); } static void _rtl92ce_hal_customized_behavior(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.h index e5e1353a94c3..dadc02b5de0b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.h @@ -102,7 +102,7 @@ void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval); -void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta); void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c index 84ddd4d07a1d..781af1b99eb5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c @@ -49,7 +49,7 @@ static u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -static u8 _rtl92c_query_rxpwrpercentage(char antpower) +static u8 _rtl92c_query_rxpwrpercentage(s8 antpower) { if ((antpower <= -100) || (antpower >= 20)) return 0; @@ -59,9 +59,9 @@ static u8 _rtl92c_query_rxpwrpercentage(char antpower) return 100 + antpower; } -static u8 _rtl92c_evm_db_to_percentage(char value) +static u8 _rtl92c_evm_db_to_percentage(s8 value) { - char ret_val; + s8 ret_val; ret_val = value; if (ret_val >= 0) @@ -449,7 +449,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } rcu_read_lock(); @@ -615,7 +615,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.h index 4bec4b07e3e0..607304586c03 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.h @@ -537,8 +537,8 @@ struct rx_fwinfo_92c { u8 pwdb_all; u8 cfosho[4]; u8 cfotail[4]; - char rxevm[2]; - char rxsnr[4]; + s8 rxevm[2]; + s8 rxsnr[4]; u8 pdsnr[2]; u8 csi_current[2]; u8 csi_target[2]; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c index 34ce06441d1b..8789752f8143 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c @@ -347,50 +347,24 @@ static void _rtl92cu_read_adapter_info(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u16 i, usvalue; - u8 hwinfo[HWSET_MAX_SIZE] = {0}; - u16 eeprom_id; - - if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { - rtl_efuse_shadow_map_update(hw); - memcpy((void *)hwinfo, - (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], - HWSET_MAX_SIZE); - } else if (rtlefuse->epromtype == EEPROM_93C46) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "RTL819X Not boot from eeprom, check it !!\n"); - } - RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, "MAP", - hwinfo, HWSET_MAX_SIZE); - eeprom_id = le16_to_cpu(*((__le16 *)&hwinfo[0])); - if (eeprom_id != RTL8190_EEPROM_ID) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "EEPROM ID(%#x) is invalid!!\n", eeprom_id); - rtlefuse->autoload_failflag = true; - } else { - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); - rtlefuse->autoload_failflag = false; - } - if (rtlefuse->autoload_failflag) + int params[] = {RTL8190_EEPROM_ID, EEPROM_VID, EEPROM_DID, + EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, + EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, + 0}; + u8 *hwinfo; + + hwinfo = kzalloc(HWSET_MAX_SIZE, GFP_KERNEL); + if (!hwinfo) return; - for (i = 0; i < 6; i += 2) { - usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; - *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; - } - pr_info("MAC address: %pM\n", rtlefuse->dev_addr); + + if (rtl_get_hwinfo(hw, rtlpriv, HWSET_MAX_SIZE, hwinfo, params)) + goto exit; + _rtl92cu_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag, hwinfo); - rtlefuse->eeprom_vid = le16_to_cpu(*(__le16 *)&hwinfo[EEPROM_VID]); - rtlefuse->eeprom_did = le16_to_cpu(*(__le16 *)&hwinfo[EEPROM_DID]); - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, " VID = 0x%02x PID = 0x%02x\n", - rtlefuse->eeprom_vid, rtlefuse->eeprom_did); - rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN]; - rtlefuse->eeprom_version = - le16_to_cpu(*(__le16 *)&hwinfo[EEPROM_VERSION]); + _rtl92cu_read_board_type(hw, hwinfo); + rtlefuse->txpwr_fromeprom = true; - rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID]; - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM Customer ID: 0x%2x\n", - rtlefuse->eeprom_oemid); if (rtlhal->oem_id == RT_CID_DEFAULT) { switch (rtlefuse->eeprom_oemid) { case EEPROM_CID_DEFAULT: @@ -416,7 +390,8 @@ static void _rtl92cu_read_adapter_info(struct ieee80211_hw *hw) break; } } - _rtl92cu_read_board_type(hw, hwinfo); +exit: + kfree(hwinfo); } static void _rtl92cu_hal_customized_behavior(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c index 035713311a4a..68ca734853c1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c @@ -596,7 +596,7 @@ void rtl92c_set_min_space(struct ieee80211_hw *hw, bool is2T) /*==============================================================*/ -static u8 _rtl92c_query_rxpwrpercentage(char antpower) +static u8 _rtl92c_query_rxpwrpercentage(s8 antpower) { if ((antpower <= -100) || (antpower >= 20)) return 0; @@ -606,9 +606,9 @@ static u8 _rtl92c_query_rxpwrpercentage(char antpower) return 100 + antpower; } -static u8 _rtl92c_evm_db_to_percentage(char value) +static u8 _rtl92c_evm_db_to_percentage(s8 value) { - char ret_val; + s8 ret_val; ret_val = value; if (ret_val >= 0) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.h index 553a4bfac668..20a49ec8459b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.h @@ -79,8 +79,8 @@ struct rx_fwinfo_92c { u8 pwdb_all; u8 cfosho[4]; u8 cfotail[4]; - char rxevm[2]; - char rxsnr[4]; + s8 rxevm[2]; + s8 rxsnr[4]; u8 pdsnr[2]; u8 csi_current[2]; u8 csi_target[2]; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c index 5624ade92cc0..ec2ea56f7933 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c @@ -465,7 +465,7 @@ static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw) } if (!rtstatus) { RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, - "Radio[%d] Fail!!", rfpath); + "Radio[%d] Fail!!\n", rfpath); goto phy_rf_cfg_fail; } } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c index f49b60d31450..b0f632462335 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c @@ -1744,65 +1744,26 @@ static void _rtl92de_read_adapter_info(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u16 i, usvalue; - u8 hwinfo[HWSET_MAX_SIZE]; - u16 eeprom_id; - unsigned long flags; + int params[] = {RTL8190_EEPROM_ID, EEPROM_VID, EEPROM_DID, + EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR_MAC0_92D, + EEPROM_CHANNEL_PLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, + COUNTRY_CODE_WORLD_WIDE_13}; + int i; + u16 usvalue; + u8 *hwinfo; - if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { - spin_lock_irqsave(&globalmutex_for_power_and_efuse, flags); - rtl_efuse_shadow_map_update(hw); - _rtl92de_efuse_update_chip_version(hw); - spin_unlock_irqrestore(&globalmutex_for_power_and_efuse, flags); - memcpy((void *)hwinfo, (void *)&rtlefuse->efuse_map - [EFUSE_INIT_MAP][0], - HWSET_MAX_SIZE); - } else if (rtlefuse->epromtype == EEPROM_93C46) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "RTL819X Not boot from eeprom, check it !!\n"); - } - RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP", - hwinfo, HWSET_MAX_SIZE); + hwinfo = kzalloc(HWSET_MAX_SIZE, GFP_KERNEL); + if (!hwinfo) + return; - eeprom_id = *((u16 *)&hwinfo[0]); - if (eeprom_id != RTL8190_EEPROM_ID) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "EEPROM ID(%#x) is invalid!!\n", eeprom_id); - rtlefuse->autoload_failflag = true; - } else { - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); - rtlefuse->autoload_failflag = false; - } - if (rtlefuse->autoload_failflag) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "RTL819X Not boot from eeprom, check it !!\n"); + if (rtl_get_hwinfo(hw, rtlpriv, HWSET_MAX_SIZE, hwinfo, params)) return; - } - rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID]; - _rtl92de_read_macphymode_and_bandtype(hw, hwinfo); - /* VID, DID SE 0xA-D */ - rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; - rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID]; - rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID]; - rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID]; - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROMId = 0x%4x\n", eeprom_id); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); + _rtl92de_efuse_update_chip_version(hw); + _rtl92de_read_macphymode_and_bandtype(hw, hwinfo); - /* Read Permanent MAC address */ - if (rtlhal->interfaceindex == 0) { - for (i = 0; i < 6; i += 2) { - usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR_MAC0_92D + i]; - *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; - } - } else { + /* Read Permanent MAC address for 2nd interface */ + if (rtlhal->interfaceindex != 0) { for (i = 0; i < 6; i += 2) { usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR_MAC1_92D + i]; *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; @@ -1828,10 +1789,8 @@ static void _rtl92de_read_adapter_info(struct ieee80211_hw *hw) rtlefuse->channel_plan = COUNTRY_CODE_FCC; break; } - rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; rtlefuse->txpwr_fromeprom = true; - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); + kfree(hwinfo); } void rtl92de_read_eeprom_info(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c index 7810fe87dca7..d334d2a5ea63 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c @@ -2695,7 +2695,7 @@ void rtl92d_phy_lc_calibrate(struct ieee80211_hw *hw) RTPRINT(rtlpriv, FINIT, INIT_IQK, "LCK:Finish!!!\n"); } -void rtl92d_phy_ap_calibrate(struct ieee80211_hw *hw, char delta) +void rtl92d_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta) { return; } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.h index 48d5c6835b6a..8115bf4ac683 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.h @@ -160,7 +160,7 @@ void rtl92d_phy_config_maccoexist_rfpage(struct ieee80211_hw *hw); bool rtl92d_phy_check_poweroff(struct ieee80211_hw *hw); void rtl92d_phy_lc_calibrate(struct ieee80211_hw *hw); void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw); -void rtl92d_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl92d_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta); void rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw); void rtl92d_phy_reset_iqk_result(struct ieee80211_hw *hw); void rtl92d_release_cckandrw_pagea_ctl(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/rf.c index 6a6ac540d5b5..2f479d397644 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/rf.c @@ -601,7 +601,7 @@ bool rtl92d_phy_rf6052_config(struct ieee80211_hw *hw) } if (!rtstatus) { RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, - "Radio[%d] Fail!!", rfpath); + "Radio[%d] Fail!!\n", rfpath); goto phy_rf_cfg_fail; } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c index 1feaa629dd4f..e998e98d74cb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c @@ -48,7 +48,7 @@ static u8 _rtl92de_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -static u8 _rtl92d_query_rxpwrpercentage(char antpower) +static u8 _rtl92d_query_rxpwrpercentage(s8 antpower) { if ((antpower <= -100) || (antpower >= 20)) return 0; @@ -58,9 +58,9 @@ static u8 _rtl92d_query_rxpwrpercentage(char antpower) return 100 + antpower; } -static u8 _rtl92d_evm_db_to_percentage(char value) +static u8 _rtl92d_evm_db_to_percentage(s8 value) { - char ret_val = value; + s8 ret_val = value; if (ret_val >= 0) ret_val = 0; @@ -586,7 +586,7 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92d)); @@ -744,7 +744,7 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.h index fb5cf0634e8d..194d99f8bacf 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.h @@ -554,8 +554,8 @@ struct rx_fwinfo_92d { u8 pwdb_all; u8 cfosho[4]; u8 cfotail[4]; - char rxevm[2]; - char rxsnr[4]; + s8 rxevm[2]; + s8 rxsnr[4]; u8 pdsnr[2]; u8 csi_current[2]; u8 csi_target[2]; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c index 459f3d0efa2f..e6b5786c7d4a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c @@ -496,7 +496,7 @@ static void rtl92ee_dm_find_minimum_rssi(struct ieee80211_hw *hw) rtl_dm_dig->min_undec_pwdb_for_dm = rtlpriv->dm.entry_min_undec_sm_pwdb; RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, - "AP Ext Port or disconnet PWDB = 0x%x\n", + "AP Ext Port or disconnect PWDB = 0x%x\n", rtl_dm_dig->min_undec_pwdb_for_dm); } RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, @@ -983,7 +983,7 @@ static bool _rtl92ee_dm_ra_state_check(struct ieee80211_hw *hw, break; default: RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, - "wrong rssi level setting %d !", *ratr_state); + "wrong rssi level setting %d !\n", *ratr_state); break; } @@ -1219,6 +1219,7 @@ void rtl92ee_dm_watchdog(struct ieee80211_hw *hw) if (ppsc->p2p_ps_info.p2p_ps_mode) fw_ps_awake = false; + spin_lock(&rtlpriv->locks.rf_ps_lock); if ((ppsc->rfpwr_state == ERFON) && ((!fw_current_inpsmode) && fw_ps_awake) && (!ppsc->rfchange_inprogress)) { @@ -1233,4 +1234,5 @@ void rtl92ee_dm_watchdog(struct ieee80211_hw *hw) rtl92ee_dm_dynamic_atc_switch(hw); rtl92ee_dm_dynamic_primary_cca_ckeck(hw); } + spin_unlock(&rtlpriv->locks.rf_ps_lock); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index 9fd3f1b6e4a8..b07af8d15273 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -2098,73 +2098,24 @@ static void _rtl92ee_read_adapter_info(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u16 i, usvalue; - u8 hwinfo[HWSET_MAX_SIZE]; - u16 eeprom_id; - - if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { - rtl_efuse_shadow_map_update(hw); - - memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], - HWSET_MAX_SIZE); - } else if (rtlefuse->epromtype == EEPROM_93C46) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "RTL819X Not boot from eeprom, check it !!"); - return; - } else { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "boot from neither eeprom nor efuse, check it !!"); + int params[] = {RTL8192E_EEPROM_ID, EEPROM_VID, EEPROM_DID, + EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, + EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, + COUNTRY_CODE_WORLD_WIDE_13}; + u8 *hwinfo; + + hwinfo = kzalloc(HWSET_MAX_SIZE, GFP_KERNEL); + if (!hwinfo) return; - } - RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP\n", - hwinfo, HWSET_MAX_SIZE); + if (rtl_get_hwinfo(hw, rtlpriv, HWSET_MAX_SIZE, hwinfo, params)) + goto exit; - eeprom_id = *((u16 *)&hwinfo[0]); - if (eeprom_id != RTL8192E_EEPROM_ID) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "EEPROM ID(%#x) is invalid!!\n", eeprom_id); - rtlefuse->autoload_failflag = true; - } else { - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); - rtlefuse->autoload_failflag = false; - } - - if (rtlefuse->autoload_failflag) - return; - /*VID DID SVID SDID*/ - rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; - rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID]; - rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID]; - rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID]; - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROMId = 0x%4x\n", eeprom_id); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); - /*customer ID*/ - rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID]; if (rtlefuse->eeprom_oemid == 0xFF) rtlefuse->eeprom_oemid = 0; RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); - /*EEPROM version*/ - rtlefuse->eeprom_version = *(u8 *)&hwinfo[EEPROM_VERSION]; - /*mac address*/ - for (i = 0; i < 6; i += 2) { - usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; - *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue; - } - - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - "dev_addr: %pM\n", rtlefuse->dev_addr); - /*channel plan */ - rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; /* set channel plan from efuse */ rtlefuse->channel_plan = rtlefuse->eeprom_channelplan; /*tx power*/ @@ -2206,6 +2157,8 @@ static void _rtl92ee_read_adapter_info(struct ieee80211_hw *hw) break; } } +exit: + kfree(hwinfo); } static void _rtl92ee_hal_customized_behavior(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c index 018340aedf09..beafc9a10ad8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c @@ -547,7 +547,7 @@ static void _rtl92ee_phy_store_txpower_by_rate_base(struct ieee80211_hw *hw) static void _phy_convert_txpower_dbm_to_relative_value(u32 *data, u8 start, u8 end, u8 base) { - char i = 0; + s8 i = 0; u8 tmp = 0; u32 temp_data = 0; @@ -650,7 +650,7 @@ static bool _rtl92ee_phy_bb8192ee_config_parafile(struct ieee80211_hw *hw) rtstatus = phy_config_bb_with_hdr_file(hw, BASEBAND_CONFIG_PHY_REG); if (!rtstatus) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!"); + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!\n"); return false; } @@ -662,7 +662,7 @@ static bool _rtl92ee_phy_bb8192ee_config_parafile(struct ieee80211_hw *hw) } _rtl92ee_phy_txpower_by_rate_configuration(hw); if (!rtstatus) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!"); + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!\n"); return false; } rtstatus = phy_config_bb_with_hdr_file(hw, BASEBAND_CONFIG_AGC_TAB); @@ -1189,7 +1189,7 @@ static u8 _rtl92ee_get_txpower_by_rate(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &rtlpriv->phy; u8 shift = 0, sec, tx_num; - char diff = 0; + s8 diff = 0; sec = _rtl92ee_phy_get_ratesection_intxpower_byrate(rf, rate); tx_num = RF_TX_NUM_NONIMPLEMENT; @@ -1265,14 +1265,14 @@ static u8 _rtl92ee_get_txpower_index(struct ieee80211_hw *hw, "Illegal channel!!\n"); } - if (IS_CCK_RATE(rate)) + if (IS_CCK_RATE((s8)rate)) tx_power = rtlefuse->txpwrlevel_cck[rfpath][index]; else if (DESC92C_RATE6M <= rate) tx_power = rtlefuse->txpwrlevel_ht40_1s[rfpath][index]; /* OFDM-1T*/ if (DESC92C_RATE6M <= rate && rate <= DESC92C_RATE54M && - !IS_CCK_RATE(rate)) + !IS_CCK_RATE((s8)rate)) tx_power += rtlefuse->txpwr_legacyhtdiff[rfpath][TX_1S]; /* BW20-1S, BW20-2S */ @@ -1819,7 +1819,7 @@ u8 rtl92ee_phy_sw_chnl(struct ieee80211_hw *hw) if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { rtl92ee_phy_sw_chnl_callback(hw); RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, - "sw_chnl_inprogress false schdule workitem current channel %d\n", + "sw_chnl_inprogress false schedule workitem current channel %d\n", rtlphy->current_channel); rtlphy->sw_chnl_inprogress = false; } else { @@ -2414,19 +2414,10 @@ static void _rtl92ee_phy_reload_mac_registers(struct ieee80211_hw *hw, static void _rtl92ee_phy_path_adda_on(struct ieee80211_hw *hw, u32 *addareg, bool is_patha_on, bool is2t) { - u32 pathon; u32 i; - pathon = is_patha_on ? 0x0fc01616 : 0x0fc01616; - if (!is2t) { - pathon = 0x0fc01616; - rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0fc01616); - } else { - rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathon); - } - - for (i = 1; i < IQK_ADDA_REG_NUM; i++) - rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathon); + for (i = 0; i < IQK_ADDA_REG_NUM; i++) + rtl_set_bbreg(hw, addareg[i], MASKDWORD, 0x0fc01616); } static void _rtl92ee_phy_mac_setting_calibration(struct ieee80211_hw *hw, @@ -2978,7 +2969,7 @@ void rtl92ee_phy_lc_calibrate(struct ieee80211_hw *hw) rtlphy->lck_inprogress = false; } -void rtl92ee_phy_ap_calibrate(struct ieee80211_hw *hw, char delta) +void rtl92ee_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta) { } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.h index c6e97c8df54c..49bd0e554c65 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.h @@ -141,7 +141,7 @@ void rtl92ee_phy_set_bw_mode(struct ieee80211_hw *hw, void rtl92ee_phy_sw_chnl_callback(struct ieee80211_hw *hw); u8 rtl92ee_phy_sw_chnl(struct ieee80211_hw *hw); void rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); -void rtl92ee_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl92ee_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta); void rtl92ee_phy_lc_calibrate(struct ieee80211_hw *hw); void rtl92ee_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); bool rtl92ee_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/rf.c index c9bc33cd1090..73716c07d433 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/rf.c @@ -142,7 +142,7 @@ static bool _rtl92ee_phy_rf6052_config_parafile(struct ieee80211_hw *hw) if (!rtstatus) { RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, - "Radio[%d] Fail!!", rfpath); + "Radio[%d] Fail!!\n", rfpath); return false; } } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c index 35e6bf7e233d..2d48ccd02ac8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c @@ -56,7 +56,7 @@ static void _rtl92ee_query_rxphystatus(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); struct phy_status_rpt *p_phystrpt = (struct phy_status_rpt *)p_drvinfo; - char rx_pwr_all = 0, rx_pwr[4]; + s8 rx_pwr_all = 0, rx_pwr[4]; u8 rf_rx_num = 0, evm, pwdb_all; u8 i, max_spatial_stream; u32 rssi, total_rssi = 0; @@ -703,7 +703,7 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } @@ -867,7 +867,7 @@ void rtl92ee_tx_fill_cmddesc(struct ieee80211_hw *hw, if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } CLEAR_PCI_TX_DESC_CONTENT(pdesc, txdesc_len); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h index a4c38345233e..8053d1b12ec4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h @@ -650,8 +650,8 @@ struct rx_fwinfo { u8 pwdb_all; u8 cfosho[4]; u8 cfotail[4]; - char rxevm[2]; - char rxsnr[4]; + s8 rxevm[2]; + s8 rxsnr[4]; u8 pdsnr[2]; u8 csi_current[2]; u8 csi_target[2]; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c index 12b0978ba4fa..ddfa0aee5bf8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c @@ -1673,23 +1673,31 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct device *dev = &rtl_pcipriv(hw)->dev.pdev->dev; u16 i, usvalue; u16 eeprom_id; u8 tempval; u8 hwinfo[HWSET_MAX_SIZE_92S]; u8 rf_path, index; - if (rtlefuse->epromtype == EEPROM_93C46) { + switch (rtlefuse->epromtype) { + case EEPROM_BOOT_EFUSE: + rtl_efuse_shadow_map_update(hw); + break; + + case EEPROM_93C46: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "RTL819X Not boot from eeprom, check it !!\n"); - } else if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { - rtl_efuse_shadow_map_update(hw); + return; - memcpy((void *)hwinfo, (void *) - &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], - HWSET_MAX_SIZE_92S); + default: + dev_warn(dev, "no efuse data\n"); + return; } + memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + HWSET_MAX_SIZE_92S); + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP", hwinfo, HWSET_MAX_SIZE_92S); @@ -1995,7 +2003,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw) rtlefuse->b1ss_support = rtlefuse->b1x1_recvcombine; rtlefuse->eeprom_oemid = *&hwinfo[EEPROM_CUSTOMID]; - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM Customer ID: 0x%2x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); /* set channel paln to world wide 13 */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/rf.c index 9475aa2a8fa0..34e88a3f6abe 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/rf.c @@ -137,7 +137,7 @@ static void _rtl92s_set_antennadiff(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_phy *rtlphy = &(rtlpriv->phy); - char ant_pwr_diff = 0; + s8 ant_pwr_diff = 0; u32 u4reg_val = 0; if (rtlphy->rf_type == RF_2T2R) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c index 125b29bd2f93..d53bbf6bef81 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c @@ -360,7 +360,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } if (mac->opmode == NL80211_IFTYPE_STATION) { @@ -529,7 +529,7 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } /* Clear all status */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/dm.c index 4c1c96c96a5a..42a6fba90ba9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/dm.c @@ -816,6 +816,7 @@ void rtl8723e_dm_watchdog(struct ieee80211_hw *hw) if (ppsc->p2p_ps_info.p2p_ps_mode) fw_ps_awake = false; + spin_lock(&rtlpriv->locks.rf_ps_lock); if ((ppsc->rfpwr_state == ERFON) && ((!fw_current_inpsmode) && fw_ps_awake) && (!ppsc->rfchange_inprogress)) { @@ -829,6 +830,7 @@ void rtl8723e_dm_watchdog(struct ieee80211_hw *hw) rtl8723e_dm_bt_coexist(hw); rtl8723e_dm_check_edca_turbo(hw); } + spin_unlock(&rtlpriv->locks.rf_ps_lock); if (rtlpriv->btcoexist.init_set) rtl_write_byte(rtlpriv, 0x76e, 0xc); } @@ -874,8 +876,8 @@ void rtl8723e_dm_bt_coexist(struct ieee80211_hw *hw) tmp_byte = rtl_read_byte(rtlpriv, 0x40); RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[DM][BT], 0x40 is 0x%x", tmp_byte); + "[DM][BT], 0x40 is 0x%x\n", tmp_byte); RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, - "[DM][BT], bt_dm_coexist start"); + "[DM][BT], bt_dm_coexist start\n"); rtl8723e_dm_bt_coexist_8723(hw); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.c index 44de695dc999..ec9bcf32f0ab 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.c @@ -185,7 +185,7 @@ static void rtl8723e_dm_bt_set_hw_pta_mode(struct ieee80211_hw *hw, bool b_mode) struct rtl_priv *rtlpriv = rtl_priv(hw); if (BT_PTA_MODE_ON == b_mode) { - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, "PTA mode on, "); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, "PTA mode on\n"); /* Enable GPIO 0/1/2/3/8 pins for bt */ rtl_write_byte(rtlpriv, 0x40, 0x20); rtlpriv->btcoexist.hw_coexist_all_off = false; @@ -1401,7 +1401,7 @@ static void rtl8723e_dm_bt_inq_page_monitor(struct ieee80211_hw *hw) (long)hal_coex_8723.bt_inq_page_start_time) / HZ) >= 10) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, - "[BTCoex], BT Inquiry/page >= 10sec!!!"); + "[BTCoex], BT Inquiry/page >= 10sec!!!\n"); hal_coex_8723.bt_inq_page_start_time = 0; rtlpriv->btcoexist.cstate &= ~BT_COEX_STATE_BT_INQ_PAGE; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c index a4b7eac6856f..b88c7ee72dbf 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c @@ -1630,62 +1630,22 @@ static void _rtl8723e_read_adapter_info(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u16 i, usvalue; - u8 hwinfo[HWSET_MAX_SIZE]; - u16 eeprom_id; + int params[] = {RTL8190_EEPROM_ID, EEPROM_VID, EEPROM_DID, + EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, + EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, + COUNTRY_CODE_WORLD_WIDE_13}; + u8 *hwinfo; if (b_pseudo_test) { /* need add */ return; } - if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { - rtl_efuse_shadow_map_update(hw); - - memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], - HWSET_MAX_SIZE); - } else if (rtlefuse->epromtype == EEPROM_93C46) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "RTL819X Not boot from eeprom, check it !!"); - } - - RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP\n", - hwinfo, HWSET_MAX_SIZE); - - eeprom_id = *((u16 *)&hwinfo[0]); - if (eeprom_id != RTL8190_EEPROM_ID) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "EEPROM ID(%#x) is invalid!!\n", eeprom_id); - rtlefuse->autoload_failflag = true; - } else { - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); - rtlefuse->autoload_failflag = false; - } - - if (rtlefuse->autoload_failflag) + hwinfo = kzalloc(HWSET_MAX_SIZE, GFP_KERNEL); + if (!hwinfo) return; - rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; - rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID]; - rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID]; - rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID]; - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROMId = 0x%4x\n", eeprom_id); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); - - for (i = 0; i < 6; i += 2) { - usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; - *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue; - } - - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - "dev_addr: %pM\n", rtlefuse->dev_addr); + if (rtl_get_hwinfo(hw, rtlpriv, HWSET_MAX_SIZE, hwinfo, params)) + goto exit; _rtl8723e_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag, hwinfo); @@ -1693,144 +1653,138 @@ static void _rtl8723e_read_adapter_info(struct ieee80211_hw *hw, rtl8723e_read_bt_coexist_info_from_hwpg(hw, rtlefuse->autoload_failflag, hwinfo); - rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN]; - rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; - rtlefuse->txpwr_fromeprom = true; - rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID]; - - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); - - /* set channel paln to world wide 13 */ - rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; - - if (rtlhal->oem_id == RT_CID_DEFAULT) { - switch (rtlefuse->eeprom_oemid) { - case EEPROM_CID_DEFAULT: - if (rtlefuse->eeprom_did == 0x8176) { - if (CHK_SVID_SMID(0x10EC, 0x6151) || - CHK_SVID_SMID(0x10EC, 0x6152) || - CHK_SVID_SMID(0x10EC, 0x6154) || - CHK_SVID_SMID(0x10EC, 0x6155) || - CHK_SVID_SMID(0x10EC, 0x6177) || - CHK_SVID_SMID(0x10EC, 0x6178) || - CHK_SVID_SMID(0x10EC, 0x6179) || - CHK_SVID_SMID(0x10EC, 0x6180) || - CHK_SVID_SMID(0x10EC, 0x7151) || - CHK_SVID_SMID(0x10EC, 0x7152) || - CHK_SVID_SMID(0x10EC, 0x7154) || - CHK_SVID_SMID(0x10EC, 0x7155) || - CHK_SVID_SMID(0x10EC, 0x7177) || - CHK_SVID_SMID(0x10EC, 0x7178) || - CHK_SVID_SMID(0x10EC, 0x7179) || - CHK_SVID_SMID(0x10EC, 0x7180) || - CHK_SVID_SMID(0x10EC, 0x8151) || - CHK_SVID_SMID(0x10EC, 0x8152) || - CHK_SVID_SMID(0x10EC, 0x8154) || - CHK_SVID_SMID(0x10EC, 0x8155) || - CHK_SVID_SMID(0x10EC, 0x8181) || - CHK_SVID_SMID(0x10EC, 0x8182) || - CHK_SVID_SMID(0x10EC, 0x8184) || - CHK_SVID_SMID(0x10EC, 0x8185) || - CHK_SVID_SMID(0x10EC, 0x9151) || - CHK_SVID_SMID(0x10EC, 0x9152) || - CHK_SVID_SMID(0x10EC, 0x9154) || - CHK_SVID_SMID(0x10EC, 0x9155) || - CHK_SVID_SMID(0x10EC, 0x9181) || - CHK_SVID_SMID(0x10EC, 0x9182) || - CHK_SVID_SMID(0x10EC, 0x9184) || - CHK_SVID_SMID(0x10EC, 0x9185)) + if (rtlhal->oem_id != RT_CID_DEFAULT) + return; + + switch (rtlefuse->eeprom_oemid) { + case EEPROM_CID_DEFAULT: + switch (rtlefuse->eeprom_did) { + case 0x8176: + switch (rtlefuse->eeprom_svid) { + case 0x10EC: + switch (rtlefuse->eeprom_smid) { + case 0x6151 ... 0x6152: + case 0x6154 ... 0x6155: + case 0x6177 ... 0x6180: + case 0x7151 ... 0x7152: + case 0x7154 ... 0x7155: + case 0x7177 ... 0x7180: + case 0x8151 ... 0x8152: + case 0x8154 ... 0x8155: + case 0x8181 ... 0x8182: + case 0x8184 ... 0x8185: + case 0x9151 ... 0x9152: + case 0x9154 ... 0x9155: + case 0x9181 ... 0x9182: + case 0x9184 ... 0x9185: rtlhal->oem_id = RT_CID_TOSHIBA; - else if (rtlefuse->eeprom_svid == 0x1025) - rtlhal->oem_id = RT_CID_819X_ACER; - else if (CHK_SVID_SMID(0x10EC, 0x6191) || - CHK_SVID_SMID(0x10EC, 0x6192) || - CHK_SVID_SMID(0x10EC, 0x6193) || - CHK_SVID_SMID(0x10EC, 0x7191) || - CHK_SVID_SMID(0x10EC, 0x7192) || - CHK_SVID_SMID(0x10EC, 0x7193) || - CHK_SVID_SMID(0x10EC, 0x8191) || - CHK_SVID_SMID(0x10EC, 0x8192) || - CHK_SVID_SMID(0x10EC, 0x8193) || - CHK_SVID_SMID(0x10EC, 0x9191) || - CHK_SVID_SMID(0x10EC, 0x9192) || - CHK_SVID_SMID(0x10EC, 0x9193)) + break; + case 0x6191 ... 0x6193: + case 0x7191 ... 0x7193: + case 0x8191 ... 0x8193: + case 0x9191 ... 0x9193: rtlhal->oem_id = RT_CID_819X_SAMSUNG; - else if (CHK_SVID_SMID(0x10EC, 0x8195) || - CHK_SVID_SMID(0x10EC, 0x9195) || - CHK_SVID_SMID(0x10EC, 0x7194) || - CHK_SVID_SMID(0x10EC, 0x8200) || - CHK_SVID_SMID(0x10EC, 0x8201) || - CHK_SVID_SMID(0x10EC, 0x8202) || - CHK_SVID_SMID(0x10EC, 0x9200)) - rtlhal->oem_id = RT_CID_819X_LENOVO; - else if (CHK_SVID_SMID(0x10EC, 0x8197) || - CHK_SVID_SMID(0x10EC, 0x9196)) + break; + case 0x8197: + case 0x9196: rtlhal->oem_id = RT_CID_819X_CLEVO; - else if (CHK_SVID_SMID(0x1028, 0x8194) || - CHK_SVID_SMID(0x1028, 0x8198) || - CHK_SVID_SMID(0x1028, 0x9197) || - CHK_SVID_SMID(0x1028, 0x9198)) + break; + case 0x8203: + rtlhal->oem_id = RT_CID_819X_PRONETS; + break; + case 0x8195: + case 0x9195: + case 0x7194: + case 0x8200 ... 0x8202: + case 0x9200: + rtlhal->oem_id = RT_CID_819X_LENOVO; + break; + } + case 0x1025: + rtlhal->oem_id = RT_CID_819X_ACER; + break; + case 0x1028: + switch (rtlefuse->eeprom_smid) { + case 0x8194: + case 0x8198: + case 0x9197 ... 0x9198: rtlhal->oem_id = RT_CID_819X_DELL; - else if (CHK_SVID_SMID(0x103C, 0x1629)) + break; + } + break; + case 0x103C: + switch (rtlefuse->eeprom_smid) { + case 0x1629: rtlhal->oem_id = RT_CID_819X_HP; - else if (CHK_SVID_SMID(0x1A32, 0x2315)) + } + break; + case 0x1A32: + switch (rtlefuse->eeprom_smid) { + case 0x2315: rtlhal->oem_id = RT_CID_819X_QMI; - else if (CHK_SVID_SMID(0x10EC, 0x8203)) - rtlhal->oem_id = RT_CID_819X_PRONETS; - else if (CHK_SVID_SMID(0x1043, 0x84B5)) - rtlhal->oem_id = - RT_CID_819X_EDIMAX_ASUS; - else - rtlhal->oem_id = RT_CID_DEFAULT; - } else if (rtlefuse->eeprom_did == 0x8178) { - if (CHK_SVID_SMID(0x10EC, 0x6181) || - CHK_SVID_SMID(0x10EC, 0x6182) || - CHK_SVID_SMID(0x10EC, 0x6184) || - CHK_SVID_SMID(0x10EC, 0x6185) || - CHK_SVID_SMID(0x10EC, 0x7181) || - CHK_SVID_SMID(0x10EC, 0x7182) || - CHK_SVID_SMID(0x10EC, 0x7184) || - CHK_SVID_SMID(0x10EC, 0x7185) || - CHK_SVID_SMID(0x10EC, 0x8181) || - CHK_SVID_SMID(0x10EC, 0x8182) || - CHK_SVID_SMID(0x10EC, 0x8184) || - CHK_SVID_SMID(0x10EC, 0x8185) || - CHK_SVID_SMID(0x10EC, 0x9181) || - CHK_SVID_SMID(0x10EC, 0x9182) || - CHK_SVID_SMID(0x10EC, 0x9184) || - CHK_SVID_SMID(0x10EC, 0x9185)) - rtlhal->oem_id = RT_CID_TOSHIBA; - else if (rtlefuse->eeprom_svid == 0x1025) - rtlhal->oem_id = RT_CID_819X_ACER; - else if (CHK_SVID_SMID(0x10EC, 0x8186)) - rtlhal->oem_id = RT_CID_819X_PRONETS; - else if (CHK_SVID_SMID(0x1043, 0x8486)) + break; + } + break; + case 0x1043: + switch (rtlefuse->eeprom_smid) { + case 0x84B5: rtlhal->oem_id = - RT_CID_819X_EDIMAX_ASUS; - else - rtlhal->oem_id = RT_CID_DEFAULT; - } else { - rtlhal->oem_id = RT_CID_DEFAULT; + RT_CID_819X_EDIMAX_ASUS; + } + break; } break; - case EEPROM_CID_TOSHIBA: - rtlhal->oem_id = RT_CID_TOSHIBA; - break; - case EEPROM_CID_CCX: - rtlhal->oem_id = RT_CID_CCX; - break; - case EEPROM_CID_QMI: - rtlhal->oem_id = RT_CID_819X_QMI; - break; - case EEPROM_CID_WHQL: + case 0x8178: + switch (rtlefuse->eeprom_svid) { + case 0x10ec: + switch (rtlefuse->eeprom_smid) { + case 0x6181 ... 0x6182: + case 0x6184 ... 0x6185: + case 0x7181 ... 0x7182: + case 0x7184 ... 0x7185: + case 0x8181 ... 0x8182: + case 0x8184 ... 0x8185: + case 0x9181 ... 0x9182: + case 0x9184 ... 0x9185: + rtlhal->oem_id = RT_CID_TOSHIBA; + break; + case 0x8186: + rtlhal->oem_id = + RT_CID_819X_PRONETS; + break; + } break; - default: - rtlhal->oem_id = RT_CID_DEFAULT; + case 0x1025: + rtlhal->oem_id = RT_CID_819X_ACER; + break; + case 0x1043: + switch (rtlefuse->eeprom_smid) { + case 0x8486: + rtlhal->oem_id = + RT_CID_819X_EDIMAX_ASUS; + } + break; + } break; - } + break; + case EEPROM_CID_TOSHIBA: + rtlhal->oem_id = RT_CID_TOSHIBA; + break; + case EEPROM_CID_CCX: + rtlhal->oem_id = RT_CID_CCX; + break; + case EEPROM_CID_QMI: + rtlhal->oem_id = RT_CID_819X_QMI; + break; + case EEPROM_CID_WHQL: + break; + default: + rtlhal->oem_id = RT_CID_DEFAULT; + break; } +exit: + kfree(hwinfo); } static void _rtl8723e_hal_customized_behavior(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c index d367097f490b..601b78efedfb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c @@ -213,7 +213,7 @@ static bool _rtl8723e_phy_bb8192c_config_parafile(struct ieee80211_hw *hw) rtstatus = _rtl8723e_phy_config_bb_with_headerfile(hw, BASEBAND_CONFIG_PHY_REG); if (rtstatus != true) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!"); + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!\n"); return false; } @@ -227,7 +227,7 @@ static bool _rtl8723e_phy_bb8192c_config_parafile(struct ieee80211_hw *hw) BASEBAND_CONFIG_PHY_REG); } if (rtstatus != true) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!"); + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!\n"); return false; } rtstatus = @@ -893,7 +893,7 @@ u8 rtl8723e_phy_sw_chnl(struct ieee80211_hw *hw) if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { rtl8723e_phy_sw_chnl_callback(hw); RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, - "sw_chnl_inprogress false schdule workitem\n"); + "sw_chnl_inprogress false schedule workitem\n"); rtlphy->sw_chnl_inprogress = false; } else { RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/rf.c index 9ebc8281ff99..422771778e03 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/rf.c @@ -504,7 +504,7 @@ static bool _rtl8723e_phy_rf6052_config_parafile(struct ieee80211_hw *hw) if (rtstatus != true) { RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, - "Radio[%d] Fail!!", rfpath); + "Radio[%d] Fail!!\n", rfpath); return false; } } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c index 7b4a9b63583b..e93125ebed81 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c @@ -389,7 +389,7 @@ void rtl8723e_tx_fill_desc(struct ieee80211_hw *hw, if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } if (mac->opmode == NL80211_IFTYPE_STATION) { @@ -557,7 +557,7 @@ void rtl8723e_tx_fill_cmddesc(struct ieee80211_hw *hw, if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h index 32970bf18856..43d4c791d563 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h @@ -522,8 +522,8 @@ struct rx_fwinfo_8723e { u8 pwdb_all; u8 cfosho[4]; u8 cfotail[4]; - char rxevm[2]; - char rxsnr[4]; + s8 rxevm[2]; + s8 rxsnr[4]; u8 pdsnr[2]; u8 csi_current[2]; u8 csi_target[2]; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c index 3a81cdba8ca3..131c0d1d633e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c @@ -758,11 +758,11 @@ static void rtl8723be_dm_txpower_tracking_callback_thermalmeter( u8 ofdm_min_index = 6; u8 index_for_channel = 0; - char delta_swing_table_idx_tup_a[TXSCALE_TABLE_SIZE] = { + s8 delta_swing_table_idx_tup_a[TXSCALE_TABLE_SIZE] = { 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 15}; - char delta_swing_table_idx_tdown_a[TXSCALE_TABLE_SIZE] = { + s8 delta_swing_table_idx_tdown_a[TXSCALE_TABLE_SIZE] = { 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13, 14, 15}; @@ -1279,6 +1279,7 @@ void rtl8723be_dm_watchdog(struct ieee80211_hw *hw) if (ppsc->p2p_ps_info.p2p_ps_mode) fw_ps_awake = false; + spin_lock(&rtlpriv->locks.rf_ps_lock); if ((ppsc->rfpwr_state == ERFON) && ((!fw_current_inpsmode) && fw_ps_awake) && (!ppsc->rfchange_inprogress)) { @@ -1294,5 +1295,6 @@ void rtl8723be_dm_watchdog(struct ieee80211_hw *hw) rtl8723be_dm_check_txpower_tracking(hw); rtl8723be_dm_dynamic_txpower(hw); } + spin_unlock(&rtlpriv->locks.rf_ps_lock); rtlpriv->dm.dbginfo.num_qry_beacon_pkt = 0; } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index 5a3df9198ddf..82e4476cab23 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -1474,7 +1474,7 @@ static enum version_8723e _rtl8723be_read_chip_version(struct ieee80211_hw *hw) value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG1); if ((value32 & (CHIP_8723B)) != CHIP_8723B) - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "unkown chip version\n"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "unknown chip version\n"); else version = (enum version_8723e)CHIP_8723B; @@ -2026,9 +2026,12 @@ static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u16 i, usvalue; - u8 hwinfo[HWSET_MAX_SIZE]; - u16 eeprom_id; + int params[] = {RTL8723BE_EEPROM_ID, EEPROM_VID, EEPROM_DID, + EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, + EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, + COUNTRY_CODE_WORLD_WIDE_13}; + u8 *hwinfo; + int i; bool is_toshiba_smid1 = false; bool is_toshiba_smid2 = false; bool is_samsung_smid = false; @@ -2055,52 +2058,13 @@ static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw, /* needs to be added */ return; } - if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { - rtl_efuse_shadow_map_update(hw); - memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], - HWSET_MAX_SIZE); - } else if (rtlefuse->epromtype == EEPROM_93C46) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "RTL819X Not boot from eeprom, check it !!"); - } - RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"), - hwinfo, HWSET_MAX_SIZE); - - eeprom_id = *((u16 *)&hwinfo[0]); - if (eeprom_id != RTL8723BE_EEPROM_ID) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "EEPROM ID(%#x) is invalid!!\n", eeprom_id); - rtlefuse->autoload_failflag = true; - } else { - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); - rtlefuse->autoload_failflag = false; - } - - if (rtlefuse->autoload_failflag) + hwinfo = kzalloc(HWSET_MAX_SIZE, GFP_KERNEL); + if (!hwinfo) return; - rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; - rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID]; - rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID]; - rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID]; - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROMId = 0x%4x\n", eeprom_id); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); - - for (i = 0; i < 6; i += 2) { - usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; - *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue; - } - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "dev_addr: %pM\n", - rtlefuse->dev_addr); + if (rtl_get_hwinfo(hw, rtlpriv, HWSET_MAX_SIZE, hwinfo, params)) + goto exit; /*parse xtal*/ rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_8723BE]; @@ -2114,14 +2078,6 @@ static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw, rtlefuse->autoload_failflag, hwinfo); - rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN]; - rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; - rtlefuse->txpwr_fromeprom = true; - rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID]; - - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); - /* set channel plan from efuse */ rtlefuse->channel_plan = rtlefuse->eeprom_channelplan; @@ -2232,6 +2188,8 @@ static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw, break; } } +exit: + kfree(hwinfo); } static void _rtl8723be_hal_customized_behavior(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c index 445f681d08c0..285818df149b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c @@ -379,7 +379,7 @@ static void _rtl8723be_phy_store_txpower_by_rate_base(struct ieee80211_hw *hw) static void _phy_convert_txpower_dbm_to_relative_value(u32 *data, u8 start, u8 end, u8 base_val) { - char i = 0; + s8 i = 0; u8 temp_value = 0; u32 temp_data = 0; @@ -467,7 +467,7 @@ static bool _rtl8723be_phy_bb8723b_config_parafile(struct ieee80211_hw *hw) rtstatus = _rtl8723be_phy_config_bb_with_headerfile(hw, BASEBAND_CONFIG_PHY_REG); if (!rtstatus) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!"); + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!\n"); return false; } _rtl8723be_phy_init_tx_power_by_rate(hw); @@ -478,7 +478,7 @@ static bool _rtl8723be_phy_bb8723b_config_parafile(struct ieee80211_hw *hw) } phy_txpower_by_rate_config(hw); if (!rtstatus) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!"); + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!\n"); return false; } rtstatus = _rtl8723be_phy_config_bb_with_headerfile(hw, @@ -953,7 +953,7 @@ static u8 _rtl8723be_get_txpower_by_rate(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &rtlpriv->phy; u8 shift = 0, rate_section, tx_num; - char tx_pwr_diff = 0; + s8 tx_pwr_diff = 0; rate_section = _rtl8723be_phy_get_ratesection_intxpower_byrate(rfpath, rate); @@ -1019,7 +1019,7 @@ static u8 _rtl8723be_get_txpower_index(struct ieee80211_hw *hw, u8 path, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u8 index = (channel - 1); - u8 txpower; + u8 txpower = 0; u8 power_diff_byrate = 0; if (channel > 14 || channel < 1) { @@ -1395,7 +1395,7 @@ u8 rtl8723be_phy_sw_chnl(struct ieee80211_hw *hw) if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { rtl8723be_phy_sw_chnl_callback(hw); RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, - "sw_chnl_inprogress false schdule workitem current channel %d\n", + "sw_chnl_inprogress false schedule workitem current channel %d\n", rtlphy->current_channel); rtlphy->sw_chnl_inprogress = false; } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/rf.c index 97f5a0377e7a..78f4f18d87b5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/rf.c @@ -502,7 +502,7 @@ static bool _rtl8723be_phy_rf6052_config_parafile(struct ieee80211_hw *hw) if (!rtstatus) { RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, - "Radio[%d] Fail!!", rfpath); + "Radio[%d] Fail!!\n", rfpath); return false; } } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c index 60345975f9fd..2175aecbb8f4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c @@ -56,7 +56,7 @@ static void _rtl8723be_query_rxphystatus(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); struct phy_status_rpt *p_phystrpt = (struct phy_status_rpt *)p_drvinfo; - char rx_pwr_all = 0, rx_pwr[4]; + s8 rx_pwr_all = 0, rx_pwr[4]; u8 rf_rx_num = 0, evm, pwdb_all, pwdb_all_bt = 0; u8 i, max_spatial_stream; u32 rssi, total_rssi = 0; @@ -464,7 +464,7 @@ void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw, mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { - RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "DMA mapping error"); + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "DMA mapping error\n"); return; } CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_8723be)); @@ -616,7 +616,7 @@ void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h index 40c36607b8b9..8a9fe41ac15b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h @@ -385,9 +385,9 @@ struct phy_status_rpt { u8 cck_rpt_b_ofdm_cfosho_b; u8 rsvd_1;/* ch_corr_msb; */ u8 noise_power_db_msb; - char path_cfotail[2]; + s8 path_cfotail[2]; u8 pcts_mask[2]; - char stream_rxevm[2]; + s8 stream_rxevm[2]; u8 path_rxsnr[2]; u8 noise_power_db_lsb; u8 rsvd_2[3]; @@ -422,8 +422,8 @@ struct rx_fwinfo_8723be { u8 pwdb_all; u8 cfosho[4]; u8 cfotail[4]; - char rxevm[2]; - char rxsnr[2]; + s8 rxevm[2]; + s8 rxsnr[2]; u8 pcts_msk_rpt[2]; u8 pdsnr[2]; u8 csi_current[2]; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c index 17a681788611..bdfd444955d2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c @@ -843,7 +843,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) dm_digtable->rssi_val_min + offset; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, - "dm_digtable->rssi_val_min=0x%x,dm_digtable->rx_gain_max = 0x%x", + "dm_digtable->rssi_val_min=0x%x,dm_digtable->rx_gain_max = 0x%x\n", dm_digtable->rssi_val_min, dm_digtable->rx_gain_max); if (rtlpriv->dm.one_entry_only) { @@ -1355,7 +1355,7 @@ void rtl8812ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw, u32 final_swing_idx[2]; u8 pwr_tracking_limit = 26; /*+1.0dB*/ u8 tx_rate = 0xFF; - char final_ofdm_swing_index = 0; + s8 final_ofdm_swing_index = 0; if (rtldm->tx_rate != 0xFF) tx_rate = @@ -2045,7 +2045,7 @@ void rtl8821ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw, u32 final_swing_idx[1]; u8 pwr_tracking_limit = 26; /*+1.0dB*/ u8 tx_rate = 0xFF; - char final_ofdm_swing_index = 0; + s8 final_ofdm_swing_index = 0; if (rtldm->tx_rate != 0xFF) tx_rate = rtl8821ae_hw_rate_to_mrate(hw, rtldm->tx_rate); @@ -2682,9 +2682,9 @@ static void rtl8821ae_dm_check_edca_turbo(struct ieee80211_hw *hw) bool b_edca_turbo_on = false; RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD, - "rtl8821ae_dm_check_edca_turbo=====>"); + "rtl8821ae_dm_check_edca_turbo=====>\n"); RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD, - "Orginial BE PARAM: 0x%x\n", + "Original BE PARAM: 0x%x\n", rtl_read_dword(rtlpriv, DM_REG_EDCA_BE_11N)); if (rtlpriv->dm.dbginfo.num_non_be_pkt > 0x100) @@ -2949,6 +2949,7 @@ void rtl8821ae_dm_watchdog(struct ieee80211_hw *hw) if (ppsc->p2p_ps_info.p2p_ps_mode) fw_ps_awake = false; + spin_lock(&rtlpriv->locks.rf_ps_lock); if ((ppsc->rfpwr_state == ERFON) && ((!fw_current_inpsmode) && fw_ps_awake) && (!ppsc->rfchange_inprogress)) { @@ -2967,6 +2968,7 @@ void rtl8821ae_dm_watchdog(struct ieee80211_hw *hw) rtl8821ae_dm_check_txpower_tracking_thermalmeter(hw); rtl8821ae_dm_iq_calibrate(hw); } + spin_unlock(&rtlpriv->locks.rf_ps_lock); rtlpriv->dm.dbginfo.num_qry_beacon_pkt = 0; RT_TRACE(rtlpriv, COMP_DIG, DBG_DMESG, "\n"); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 71e4dd9965bb..0cddf1ad0fff 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -3101,79 +3101,22 @@ static void _rtl8821ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); - u16 i, usvalue; - u8 hwinfo[HWSET_MAX_SIZE]; - u16 eeprom_id; + int params[] = {RTL_EEPROM_ID, EEPROM_VID, EEPROM_DID, + EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, + EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, + COUNTRY_CODE_WORLD_WIDE_13}; + u8 *hwinfo; if (b_pseudo_test) { ;/* need add */ } - if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { - rtl_efuse_shadow_map_update(hw); - memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], - HWSET_MAX_SIZE); - } else if (rtlefuse->epromtype == EEPROM_93C46) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "RTL819X Not boot from eeprom, check it !!"); - } - - RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP\n", - hwinfo, HWSET_MAX_SIZE); - - eeprom_id = *((u16 *)&hwinfo[0]); - if (eeprom_id != RTL_EEPROM_ID) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "EEPROM ID(%#x) is invalid!!\n", eeprom_id); - rtlefuse->autoload_failflag = true; - } else { - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); - rtlefuse->autoload_failflag = false; - } - - if (rtlefuse->autoload_failflag) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "RTL8812AE autoload_failflag, check it !!"); + hwinfo = kzalloc(HWSET_MAX_SIZE, GFP_KERNEL); + if (!hwinfo) return; - } - - rtlefuse->eeprom_version = *(u8 *)&hwinfo[EEPROM_VERSION]; - if (rtlefuse->eeprom_version == 0xff) - rtlefuse->eeprom_version = 0; - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM version: 0x%2x\n", rtlefuse->eeprom_version); - - rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; - rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID]; - rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID]; - rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID]; - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROMId = 0x%4x\n", eeprom_id); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); - - /*customer ID*/ - rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID]; - if (rtlefuse->eeprom_oemid == 0xFF) - rtlefuse->eeprom_oemid = 0; - - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); - - for (i = 0; i < 6; i += 2) { - usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; - *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue; - } - - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - "dev_addr: %pM\n", rtlefuse->dev_addr); + if (rtl_get_hwinfo(hw, rtlpriv, HWSET_MAX_SIZE, hwinfo, params)) + goto exit; _rtl8821ae_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag, hwinfo); @@ -3273,6 +3216,8 @@ static void _rtl8821ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_ break; } } +exit: + kfree(hwinfo); } /*static void _rtl8821ae_hal_customized_behavior(struct ieee80211_hw *hw) @@ -3829,7 +3774,7 @@ void rtl8821ae_update_hal_rate_tbl(struct ieee80211_hw *hw, rtl8821ae_update_hal_rate_mask(hw, sta, rssi_level); else /*RT_TRACE(rtlpriv, COMP_RATR,DBG_LOUD, - "rtl8821ae_update_hal_rate_tbl() Error! 8821ae FW RA Only");*/ + "rtl8821ae_update_hal_rate_tbl() Error! 8821ae FW RA Only\n");*/ rtl8821ae_update_hal_rate_table(hw, sta); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c index 0c3b9ce86e2e..a71bfe38e7e1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c @@ -366,12 +366,12 @@ u32 phy_get_tx_swing_8812A(struct ieee80211_hw *hw, u8 band, struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_dm *rtldm = rtl_dm(rtlpriv); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - char reg_swing_2g = -1;/* 0xff; */ - char reg_swing_5g = -1;/* 0xff; */ - char swing_2g = -1 * reg_swing_2g; - char swing_5g = -1 * reg_swing_5g; + s8 reg_swing_2g = -1;/* 0xff; */ + s8 reg_swing_5g = -1;/* 0xff; */ + s8 swing_2g = -1 * reg_swing_2g; + s8 swing_5g = -1 * reg_swing_5g; u32 out = 0x200; - const char auto_temp = -1; + const s8 auto_temp = -1; RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, "===> PHY_GetTxBBSwing_8812A, bbSwing_2G: %d, bbSwing_5G: %d,autoload_failflag=%d.\n", @@ -524,7 +524,7 @@ void rtl8821ae_phy_switch_wirelessband(struct ieee80211_hw *hw, u8 band) struct rtl_dm *rtldm = rtl_dm(rtlpriv); u8 current_band = rtlhal->current_bandtype; u32 txpath, rxpath; - char bb_diff_between_band; + s8 bb_diff_between_band; txpath = rtl8821ae_phy_query_bb_reg(hw, RTXPATH, 0xf0); rxpath = rtl8821ae_phy_query_bb_reg(hw, RCCK_RX, 0x0f000000); @@ -581,7 +581,7 @@ void rtl8821ae_phy_switch_wirelessband(struct ieee80211_hw *hw, u8 band) count = 0; reg_41a = rtl_read_word(rtlpriv, REG_TXPKT_EMPTY); RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, - "Reg41A value %d", reg_41a); + "Reg41A value %d\n", reg_41a); reg_41a &= 0x30; while ((reg_41a != 0x30) && (count < 50)) { udelay(50); @@ -591,7 +591,7 @@ void rtl8821ae_phy_switch_wirelessband(struct ieee80211_hw *hw, u8 band) reg_41a &= 0x30; count++; RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, - "Reg41A value %d", reg_41a); + "Reg41A value %d\n", reg_41a); } if (count != 0) RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, @@ -986,7 +986,7 @@ static void _rtl8812ae_phy_cross_reference_ht_and_vht_txpower_limit(struct ieee8 struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &rtlpriv->phy; u8 regulation, bw, channel, rate_section; - char temp_pwrlmt = 0; + s8 temp_pwrlmt = 0; for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) { for (bw = 0; bw < MAX_5G_BANDWITH_NUM; ++bw) { @@ -1013,7 +1013,7 @@ static void _rtl8812ae_phy_cross_reference_ht_and_vht_txpower_limit(struct ieee8 rtlphy->txpwr_limit_5g[regulation][bw][3][channel][RF90_PATH_A]; } - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "use other value %d", temp_pwrlmt); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "use other value %d\n", temp_pwrlmt); } } } @@ -1155,7 +1155,7 @@ static void _rtl8812ae_phy_convert_txpower_limit_to_power_index(struct ieee80211 u8 regulation, bw, channel, rate_section; u8 base_index2_4G = 0; u8 base_index5G = 0; - char temp_value = 0, temp_pwrlmt = 0; + s8 temp_value = 0, temp_pwrlmt = 0; u8 rf_path = 0; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, @@ -1467,11 +1467,11 @@ static bool _rtl8812ae_eq_n_byte(u8 *str1, u8 *str2, u32 num) return true; } -static char _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(struct ieee80211_hw *hw, +static s8 _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(struct ieee80211_hw *hw, u8 band, u8 channel) { struct rtl_priv *rtlpriv = rtl_priv(hw); - char channel_index = -1; + s8 channel_index = -1; u8 i = 0; if (band == BAND_ON_2_4G) @@ -1482,12 +1482,12 @@ static char _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(struct ieee80211_hw *hw, channel_index = i; } } else - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Invalid Band %d in %s", + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Invalid Band %d in %s\n", band, __func__); if (channel_index == -1) RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, - "Invalid Channel %d of Band %d in %s", channel, + "Invalid Channel %d of Band %d in %s\n", channel, band, __func__); return channel_index; @@ -1502,7 +1502,7 @@ static void _rtl8812ae_phy_set_txpower_limit(struct ieee80211_hw *hw, u8 *pregul struct rtl_phy *rtlphy = &rtlpriv->phy; u8 regulation = 0, bandwidth = 0, rate_section = 0, channel; u8 channel_index; - char power_limit = 0, prev_power_limit, ret; + s8 power_limit = 0, prev_power_limit, ret; if (!_rtl8812ae_get_integer_from_string((char *)pchannel, &channel) || !_rtl8812ae_get_integer_from_string((char *)ppower_limit, @@ -1665,7 +1665,7 @@ static bool _rtl8821ae_phy_bb8821a_config_parafile(struct ieee80211_hw *hw) rtstatus = _rtl8821ae_phy_config_bb_with_headerfile(hw, BASEBAND_CONFIG_PHY_REG); if (rtstatus != true) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!"); + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!\n"); return false; } _rtl8821ae_phy_init_tx_power_by_rate(hw); @@ -1674,7 +1674,7 @@ static bool _rtl8821ae_phy_bb8821a_config_parafile(struct ieee80211_hw *hw) BASEBAND_CONFIG_PHY_REG); } if (rtstatus != true) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!"); + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!\n"); return false; } @@ -2254,9 +2254,9 @@ static bool _rtl8821ae_phy_get_chnl_index(u8 channel, u8 *chnl_index) return in_24g; } -static char _rtl8821ae_phy_get_ratesection_intxpower_byrate(u8 path, u8 rate) +static s8 _rtl8821ae_phy_get_ratesection_intxpower_byrate(u8 path, u8 rate) { - char rate_section = 0; + s8 rate_section = 0; switch (rate) { case DESC_RATE1M: case DESC_RATE2M: @@ -2338,9 +2338,9 @@ static char _rtl8821ae_phy_get_ratesection_intxpower_byrate(u8 path, u8 rate) return rate_section; } -static char _rtl8812ae_phy_get_world_wide_limit(char *limit_table) +static s8 _rtl8812ae_phy_get_world_wide_limit(s8 *limit_table) { - char min = limit_table[0]; + s8 min = limit_table[0]; u8 i = 0; for (i = 0; i < MAX_REGULATION_NUM; ++i) { @@ -2350,7 +2350,7 @@ static char _rtl8812ae_phy_get_world_wide_limit(char *limit_table) return min; } -static char _rtl8812ae_phy_get_txpower_limit(struct ieee80211_hw *hw, +static s8 _rtl8812ae_phy_get_txpower_limit(struct ieee80211_hw *hw, u8 band, enum ht_channel_width bandwidth, enum radio_path rf_path, @@ -2362,7 +2362,7 @@ static char _rtl8812ae_phy_get_txpower_limit(struct ieee80211_hw *hw, short band_temp = -1, regulation = -1, bandwidth_temp = -1, rate_section = -1, channel_temp = -1; u16 bd, regu, bdwidth, sec, chnl; - char power_limit = MAX_POWER_INDEX; + s8 power_limit = MAX_POWER_INDEX; if (rtlefuse->eeprom_regulatory == 2) return MAX_POWER_INDEX; @@ -2489,7 +2489,7 @@ static char _rtl8812ae_phy_get_txpower_limit(struct ieee80211_hw *hw, chnl = channel_temp; if (band == BAND_ON_2_4G) { - char limits[10] = {0}; + s8 limits[10] = {0}; u8 i; for (i = 0; i < 4; ++i) @@ -2501,7 +2501,7 @@ static char _rtl8812ae_phy_get_txpower_limit(struct ieee80211_hw *hw, rtlphy->txpwr_limit_2_4g[regu][bdwidth] [sec][chnl][rf_path]; } else if (band == BAND_ON_5G) { - char limits[10] = {0}; + s8 limits[10] = {0}; u8 i; for (i = 0; i < MAX_REGULATION_NUM; ++i) @@ -2519,14 +2519,14 @@ static char _rtl8812ae_phy_get_txpower_limit(struct ieee80211_hw *hw, return power_limit; } -static char _rtl8821ae_phy_get_txpower_by_rate(struct ieee80211_hw *hw, +static s8 _rtl8821ae_phy_get_txpower_by_rate(struct ieee80211_hw *hw, u8 band, u8 path, u8 rate) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &rtlpriv->phy; u8 shift = 0, rate_section, tx_num; - char tx_pwr_diff = 0; - char limit = 0; + s8 tx_pwr_diff = 0; + s8 limit = 0; rate_section = _rtl8821ae_phy_get_ratesection_intxpower_byrate(path, rate); tx_num = RF_TX_NUM_NONIMPLEMENT; @@ -2639,7 +2639,7 @@ static u8 _rtl8821ae_get_txpower_index(struct ieee80211_hw *hw, u8 path, u8 index = (channel - 1); u8 txpower = 0; bool in_24g = false; - char powerdiff_byrate = 0; + s8 powerdiff_byrate = 0; if (((rtlhal->current_bandtype == BAND_ON_2_4G) && (channel > 14 || channel < 1)) || @@ -4637,7 +4637,7 @@ void rtl8821ae_phy_lc_calibrate(struct ieee80211_hw *hw) { } -void rtl8821ae_phy_ap_calibrate(struct ieee80211_hw *hw, char delta) +void rtl8821ae_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta) { } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.h index c411f0a95cc4..1285e1adfe9d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.h @@ -236,7 +236,7 @@ void rtl8821ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); void rtl8812ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); -void rtl8821ae_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl8821ae_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta); void rtl8821ae_phy_lc_calibrate(struct ieee80211_hw *hw); void rtl8821ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); bool rtl8812ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/rf.c index 2922538160e5..c6ab957023e6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/rf.c @@ -454,7 +454,7 @@ static bool _rtl8821ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw) if (!rtstatus) { RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, - "Radio[%d] Fail!!", rfpath); + "Radio[%d] Fail!!\n", rfpath); return false; } } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c index 41efaa148d13..27727186ba5f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c @@ -48,7 +48,7 @@ static u8 _rtl8821ae_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -static u16 odm_cfo(char value) +static u16 odm_cfo(s8 value) { int ret_val; @@ -64,9 +64,9 @@ static u16 odm_cfo(char value) return ret_val; } -static u8 _rtl8821ae_evm_dbm_jaguar(char value) +static u8 _rtl8821ae_evm_dbm_jaguar(s8 value) { - char ret_val = value; + s8 ret_val = value; /* -33dB~0dB to 33dB ~ 0dB*/ if (ret_val == -128) @@ -88,7 +88,7 @@ static void query_rxphystatus(struct ieee80211_hw *hw, struct phy_status_rpt *p_phystrpt = (struct phy_status_rpt *)p_drvinfo; struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); struct rtl_phy *rtlphy = &rtlpriv->phy; - char rx_pwr_all = 0, rx_pwr[4]; + s8 rx_pwr_all = 0, rx_pwr[4]; u8 rf_rx_num = 0, evm, evmdbm, pwdb_all; u8 i, max_spatial_stream; u32 rssi, total_rssi = 0; @@ -170,7 +170,7 @@ static void query_rxphystatus(struct ieee80211_hw *hw, pwdb_all = 100; } } else { /* 8821 */ - char pout = -6; + s8 pout = -6; switch (lan_idx) { case 5: @@ -275,7 +275,7 @@ static void query_rxphystatus(struct ieee80211_hw *hw, if (bpacket_match_bssid) { for (i = RF90_PATH_A; i <= RF90_PATH_B; i++) rtl_priv(hw)->dm.cfo_tail[i] = - (char)p_phystrpt->cfotail[i]; + (s8)p_phystrpt->cfotail[i]; rtl_priv(hw)->dm.packet_count++; } @@ -716,7 +716,7 @@ void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_8821ae)); @@ -857,7 +857,7 @@ void rtl8821ae_tx_fill_cmddesc(struct ieee80211_hw *hw, if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, - "DMA mapping error"); + "DMA mapping error\n"); return; } CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h index ad565bebf1d5..b6f3c564b8d1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h @@ -390,11 +390,11 @@ struct phy_status_rpt { u8 cfosho[4]; /* DW 1 byte 1 DW 2 byte 0 */ /* DWORD 2 */ - char cfotail[4]; /* DW 2 byte 1 DW 3 byte 0 */ + s8 cfotail[4]; /* DW 2 byte 1 DW 3 byte 0 */ /* DWORD 3 */ - char rxevm[2]; /* DW 3 byte 1 DW 3 byte 2 */ - char rxsnr[2]; /* DW 3 byte 3 DW 4 byte 0 */ + s8 rxevm[2]; /* DW 3 byte 1 DW 3 byte 2 */ + s8 rxsnr[2]; /* DW 3 byte 3 DW 4 byte 0 */ /* DWORD 4 */ u8 pcts_msk_rpt[2]; @@ -418,8 +418,8 @@ struct rx_fwinfo_8821ae { u8 pwdb_all; u8 cfosho[4]; u8 cfotail[4]; - char rxevm[2]; - char rxsnr[4]; + s8 rxevm[2]; + s8 rxsnr[4]; u8 pdsnr[2]; u8 csi_current[2]; u8 csi_target[2]; diff --git a/drivers/net/wireless/realtek/rtlwifi/stats.c b/drivers/net/wireless/realtek/rtlwifi/stats.c index d8b30690b00d..61700fa05570 100644 --- a/drivers/net/wireless/realtek/rtlwifi/stats.c +++ b/drivers/net/wireless/realtek/rtlwifi/stats.c @@ -26,7 +26,7 @@ #include "stats.h" #include <linux/export.h> -u8 rtl_query_rxpwrpercentage(char antpower) +u8 rtl_query_rxpwrpercentage(s8 antpower) { if ((antpower <= -100) || (antpower >= 20)) return 0; @@ -37,9 +37,9 @@ u8 rtl_query_rxpwrpercentage(char antpower) } EXPORT_SYMBOL(rtl_query_rxpwrpercentage); -u8 rtl_evm_db_to_percentage(char value) +u8 rtl_evm_db_to_percentage(s8 value) { - char ret_val = clamp(-value, 0, 33) * 3; + s8 ret_val = clamp(-value, 0, 33) * 3; if (ret_val == 99) ret_val = 100; diff --git a/drivers/net/wireless/realtek/rtlwifi/stats.h b/drivers/net/wireless/realtek/rtlwifi/stats.h index 2b57dffef572..bd0108f93182 100644 --- a/drivers/net/wireless/realtek/rtlwifi/stats.h +++ b/drivers/net/wireless/realtek/rtlwifi/stats.h @@ -33,8 +33,8 @@ /* Rx smooth factor */ #define RX_SMOOTH_FACTOR 20 -u8 rtl_query_rxpwrpercentage(char antpower); -u8 rtl_evm_db_to_percentage(char value); +u8 rtl_query_rxpwrpercentage(s8 antpower); +u8 rtl_evm_db_to_percentage(s8 value); long rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig); void rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer, struct rtl_stats *pstatus); diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 4e0ab4d42aa6..c5086c2229aa 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1089,7 +1089,7 @@ struct dynamic_primary_cca { }; struct rtl_regulatory { - char alpha2[2]; + s8 alpha2[2]; u16 country_code; u16 max_power_level; u32 tp_scale; @@ -1256,16 +1256,16 @@ struct rtl_phy { u8 cur_bw20_txpwridx; u8 cur_bw40_txpwridx; - char txpwr_limit_2_4g[MAX_REGULATION_NUM] - [MAX_2_4G_BANDWITH_NUM] - [MAX_RATE_SECTION_NUM] - [CHANNEL_MAX_NUMBER_2G] - [MAX_RF_PATH_NUM]; - char txpwr_limit_5g[MAX_REGULATION_NUM] - [MAX_5G_BANDWITH_NUM] + s8 txpwr_limit_2_4g[MAX_REGULATION_NUM] + [MAX_2_4G_BANDWITH_NUM] [MAX_RATE_SECTION_NUM] - [CHANNEL_MAX_NUMBER_5G] + [CHANNEL_MAX_NUMBER_2G] [MAX_RF_PATH_NUM]; + s8 txpwr_limit_5g[MAX_REGULATION_NUM] + [MAX_5G_BANDWITH_NUM] + [MAX_RATE_SECTION_NUM] + [CHANNEL_MAX_NUMBER_5G] + [MAX_RF_PATH_NUM]; u32 rfreg_chnlval[2]; bool apk_done; @@ -1639,7 +1639,7 @@ struct fast_ant_training { }; struct dm_phy_dbg_info { - char rx_snrdb[4]; + s8 rx_snrdb[4]; u64 num_qry_phy_status; u64 num_qry_phy_status_cck; u64 num_qry_phy_status_ofdm; @@ -1688,16 +1688,16 @@ struct rtl_dm { u8 txpower_track_control; bool interrupt_migration; bool disable_tx_int; - char ofdm_index[MAX_RF_PATH]; + s8 ofdm_index[MAX_RF_PATH]; u8 default_ofdm_index; u8 default_cck_index; - char cck_index; - char delta_power_index[MAX_RF_PATH]; - char delta_power_index_last[MAX_RF_PATH]; - char power_index_offset[MAX_RF_PATH]; - char absolute_ofdm_swing_idx[MAX_RF_PATH]; - char remnant_ofdm_swing_idx[MAX_RF_PATH]; - char remnant_cck_idx; + s8 cck_index; + s8 delta_power_index[MAX_RF_PATH]; + s8 delta_power_index_last[MAX_RF_PATH]; + s8 power_index_offset[MAX_RF_PATH]; + s8 absolute_ofdm_swing_idx[MAX_RF_PATH]; + s8 remnant_ofdm_swing_idx[MAX_RF_PATH]; + s8 remnant_cck_idx; bool modify_txagc_flag_path_a; bool modify_txagc_flag_path_b; @@ -1726,8 +1726,8 @@ struct rtl_dm { u8 swing_idx_cck_base; bool swing_flag_cck; - char swing_diff_2g; - char swing_diff_5g; + s8 swing_diff_2g; + s8 swing_diff_5g; u8 delta_swing_table_idx_24gccka_p[DEL_SW_IDX_SZ]; u8 delta_swing_table_idx_24gccka_n[DEL_SW_IDX_SZ]; @@ -1838,17 +1838,17 @@ struct rtl_efuse { * * Sizes of these arrays are decided by the larger ones. */ - char txpwr_cckdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; - char txpwr_ht20diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; - char txpwr_ht40diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; - char txpwr_legacyhtdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + s8 txpwr_cckdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + s8 txpwr_ht20diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + s8 txpwr_ht40diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + s8 txpwr_legacyhtdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; u8 txpwr_5g_bw40base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; u8 txpwr_5g_bw80base[MAX_RF_PATH][CHANNEL_MAX_NUMBER_5G_80M]; - char txpwr_5g_ofdmdiff[MAX_RF_PATH][MAX_TX_COUNT]; - char txpwr_5g_bw20diff[MAX_RF_PATH][MAX_TX_COUNT]; - char txpwr_5g_bw40diff[MAX_RF_PATH][MAX_TX_COUNT]; - char txpwr_5g_bw80diff[MAX_RF_PATH][MAX_TX_COUNT]; + s8 txpwr_5g_ofdmdiff[MAX_RF_PATH][MAX_TX_COUNT]; + s8 txpwr_5g_bw20diff[MAX_RF_PATH][MAX_TX_COUNT]; + s8 txpwr_5g_bw40diff[MAX_RF_PATH][MAX_TX_COUNT]; + s8 txpwr_5g_bw80diff[MAX_RF_PATH][MAX_TX_COUNT]; u8 txpwr_safetyflag; /* Band edge enable flag */ u16 eeprom_txpowerdiff; @@ -2006,7 +2006,7 @@ struct rtl_stats { bool is_ht; bool packet_toself; bool packet_beacon; /*for rssi */ - char cck_adc_pwdb[4]; /*for rx path selection */ + s8 cck_adc_pwdb[4]; /*for rx path selection */ bool is_vht; bool is_short_gi; @@ -2413,9 +2413,9 @@ struct dig_t { u8 presta_cstate; u8 curmultista_cstate; u8 stop_dig; - char back_val; - char back_range_max; - char back_range_min; + s8 back_val; + s8 back_range_max; + s8 back_range_min; u8 rx_gain_max; u8 rx_gain_min; u8 min_undec_pwdb_for_dm; @@ -2441,8 +2441,8 @@ struct dig_t { u8 cur_cs_ratiostate; u8 pre_cs_ratiostate; u8 backoff_enable_flag; - char backoffval_range_max; - char backoffval_range_min; + s8 backoffval_range_max; + s8 backoffval_range_min; u8 dig_min_0; u8 dig_min_1; u8 bt30_cur_igi; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 569918c485b4..603c90470225 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2134,6 +2134,7 @@ static void rndis_get_scan_results(struct work_struct *work) struct rndis_wlan_private *priv = container_of(work, struct rndis_wlan_private, scan_work.work); struct usbnet *usbdev = priv->usbdev; + struct cfg80211_scan_info info = {}; int ret; netdev_dbg(usbdev->net, "get_scan_results\n"); @@ -2143,7 +2144,8 @@ static void rndis_get_scan_results(struct work_struct *work) ret = rndis_check_bssid_list(usbdev, NULL, NULL); - cfg80211_scan_done(priv->scan_request, ret < 0); + info.aborted = ret < 0; + cfg80211_scan_done(priv->scan_request, &info); priv->scan_request = NULL; } @@ -3574,7 +3576,11 @@ static int rndis_wlan_stop(struct usbnet *usbdev) flush_workqueue(priv->workqueue); if (priv->scan_request) { - cfg80211_scan_done(priv->scan_request, true); + struct cfg80211_scan_info info = { + .aborted = true, + }; + + cfg80211_scan_done(priv->scan_request, &info); priv->scan_request = NULL; } diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 40658b62d077..35c14cc3f0d2 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -398,7 +398,7 @@ static int rsi_mgmt_pkt_to_core(struct rsi_common *common, return -ENOLINK; msg_len -= pad_bytes; - if ((msg_len <= 0) || (!msg)) { + if (msg_len <= 0) { rsi_dbg(MGMT_RX_ZONE, "%s: Invalid rx msg of len = %d\n", __func__, msg_len); diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c index 983788156bb0..0a0ff7e31f5b 100644 --- a/drivers/net/wireless/st/cw1200/scan.c +++ b/drivers/net/wireless/st/cw1200/scan.c @@ -167,6 +167,10 @@ void cw1200_scan_work(struct work_struct *work) } if (!priv->scan.req || (priv->scan.curr == priv->scan.end)) { + struct cfg80211_scan_info info = { + .aborted = priv->scan.status ? 1 : 0, + }; + if (priv->scan.output_power != priv->output_power) wsm_set_output_power(priv, priv->output_power * 10); if (priv->join_status == CW1200_JOIN_STATUS_STA && @@ -188,7 +192,7 @@ void cw1200_scan_work(struct work_struct *work) cw1200_scan_restart_delayed(priv); wsm_unlock_tx(priv); mutex_unlock(&priv->conf_mutex); - ieee80211_scan_completed(priv->hw, priv->scan.status ? 1 : 0); + ieee80211_scan_completed(priv->hw, &info); up(&priv->scan.lock); return; } else { diff --git a/drivers/net/wireless/ti/wl1251/event.c b/drivers/net/wireless/ti/wl1251/event.c index c98630394a1a..d0593bc1f1a9 100644 --- a/drivers/net/wireless/ti/wl1251/event.c +++ b/drivers/net/wireless/ti/wl1251/event.c @@ -36,7 +36,11 @@ static int wl1251_event_scan_complete(struct wl1251 *wl, mbox->scheduled_scan_channels); if (wl->scanning) { - ieee80211_scan_completed(wl->hw, false); + struct cfg80211_scan_info info = { + .aborted = false, + }; + + ieee80211_scan_completed(wl->hw, &info); wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); wl->scanning = false; if (wl->hw->conf.flags & IEEE80211_CONF_IDLE) diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 56384a4e2a35..bbf7604889b7 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -448,7 +448,11 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) WARN_ON(wl->state != WL1251_STATE_ON); if (wl->scanning) { - ieee80211_scan_completed(wl->hw, true); + struct cfg80211_scan_info info = { + .aborted = true, + }; + + ieee80211_scan_completed(wl->hw, &info); wl->scanning = false; } diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c index ef811848d141..2c5df43b8ed9 100644 --- a/drivers/net/wireless/ti/wl18xx/event.c +++ b/drivers/net/wireless/ti/wl18xx/event.c @@ -112,12 +112,18 @@ static int wlcore_smart_config_decode_event(struct wl1271 *wl, return 0; } -static void wlcore_event_time_sync(struct wl1271 *wl, u16 tsf_msb, u16 tsf_lsb) +static void wlcore_event_time_sync(struct wl1271 *wl, + u16 tsf_high_msb, u16 tsf_high_lsb, + u16 tsf_low_msb, u16 tsf_low_lsb) { - u32 clock; - /* convert the MSB+LSB to a u32 TSF value */ - clock = (tsf_msb << 16) | tsf_lsb; - wl1271_info("TIME_SYNC_EVENT_ID: clock %u", clock); + u32 clock_low; + u32 clock_high; + + clock_high = (tsf_high_msb << 16) | tsf_high_lsb; + clock_low = (tsf_low_msb << 16) | tsf_low_lsb; + + wl1271_info("TIME_SYNC_EVENT_ID: clock_high %u, clock low %u", + clock_high, clock_low); } int wl18xx_process_mailbox_events(struct wl1271 *wl) @@ -138,8 +144,10 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl) if (vector & TIME_SYNC_EVENT_ID) wlcore_event_time_sync(wl, - mbox->time_sync_tsf_msb, - mbox->time_sync_tsf_lsb); + mbox->time_sync_tsf_high_msb, + mbox->time_sync_tsf_high_lsb, + mbox->time_sync_tsf_low_msb, + mbox->time_sync_tsf_low_lsb); if (vector & RADAR_DETECTED_EVENT_ID) { wl1271_info("radar event: channel %d type %s", @@ -187,11 +195,11 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl) */ if (vector & MAX_TX_FAILURE_EVENT_ID) wlcore_event_max_tx_failure(wl, - le32_to_cpu(mbox->tx_retry_exceeded_bitmap)); + le16_to_cpu(mbox->tx_retry_exceeded_bitmap)); if (vector & INACTIVE_STA_EVENT_ID) wlcore_event_inactive_sta(wl, - le32_to_cpu(mbox->inactive_sta_bitmap)); + le16_to_cpu(mbox->inactive_sta_bitmap)); if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID) wlcore_event_roc_complete(wl); diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h index 070de1274694..ce8ea9c04052 100644 --- a/drivers/net/wireless/ti/wl18xx/event.h +++ b/drivers/net/wireless/ti/wl18xx/event.h @@ -74,10 +74,16 @@ struct wl18xx_event_mailbox { __le16 bss_loss_bitmap; /* bitmap of stations (by HLID) which exceeded max tx retries */ - __le32 tx_retry_exceeded_bitmap; + __le16 tx_retry_exceeded_bitmap; + + /* time sync high msb*/ + __le16 time_sync_tsf_high_msb; /* bitmap of inactive stations (by HLID) */ - __le32 inactive_sta_bitmap; + __le16 inactive_sta_bitmap; + + /* time sync high lsb*/ + __le16 time_sync_tsf_high_lsb; /* rx BA win size indicated by RX_BA_WIN_SIZE_CHANGE_EVENT_ID */ u8 rx_ba_role_id; @@ -98,14 +104,15 @@ struct wl18xx_event_mailbox { u8 sc_sync_channel; u8 sc_sync_band; - /* time sync msb*/ - u16 time_sync_tsf_msb; + /* time sync low msb*/ + __le16 time_sync_tsf_low_msb; + /* radar detect */ u8 radar_channel; u8 radar_type; - /* time sync lsb*/ - u16 time_sync_tsf_lsb; + /* time sync low lsb*/ + __le16 time_sync_tsf_low_lsb; } __packed; diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index ae47c79cb9b6..00a04dfc03d1 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1214,6 +1214,10 @@ static void wl18xx_convert_fw_status(struct wl1271 *wl, void *raw_fw_status, int_fw_status->counters.tx_voice_released_blks; fw_status->counters.tx_last_rate = int_fw_status->counters.tx_last_rate; + fw_status->counters.tx_last_rate_mbps = + int_fw_status->counters.tx_last_rate_mbps; + fw_status->counters.hlid = + int_fw_status->counters.hlid; fw_status->log_start_addr = le32_to_cpu(int_fw_status->log_start_addr); @@ -1821,9 +1825,12 @@ static const struct ieee80211_iface_limit wl18xx_iface_limits[] = { }, { .max = 1, - .types = BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_P2P_CLIENT), + .types = BIT(NL80211_IFTYPE_AP) + | BIT(NL80211_IFTYPE_P2P_GO) + | BIT(NL80211_IFTYPE_P2P_CLIENT) +#ifdef CONFIG_MAC80211_MESH + | BIT(NL80211_IFTYPE_MESH_POINT) +#endif }, { .max = 1, @@ -1836,6 +1843,12 @@ static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = { .max = 2, .types = BIT(NL80211_IFTYPE_AP), }, +#ifdef CONFIG_MAC80211_MESH + { + .max = 1, + .types = BIT(NL80211_IFTYPE_MESH_POINT), + }, +#endif { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE), diff --git a/drivers/net/wireless/ti/wl18xx/tx.c b/drivers/net/wireless/ti/wl18xx/tx.c index ebaf66ef3f84..876aef10f95a 100644 --- a/drivers/net/wireless/ti/wl18xx/tx.c +++ b/drivers/net/wireless/ti/wl18xx/tx.c @@ -30,9 +30,9 @@ static void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif, - u8 band, struct ieee80211_tx_rate *rate) + u8 band, struct ieee80211_tx_rate *rate, u8 hlid) { - u8 fw_rate = wl->fw_status->counters.tx_last_rate; + u8 fw_rate = wl->links[hlid].fw_rate_idx; if (fw_rate > CONF_HW_RATE_INDEX_MAX) { wl1271_error("last Tx rate invalid: %d", fw_rate); @@ -79,6 +79,7 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte) struct sk_buff *skb; int id = tx_stat_byte & WL18XX_TX_STATUS_DESC_ID_MASK; bool tx_success; + struct wl1271_tx_hw_descr *tx_desc; /* check for id legality */ if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) { @@ -91,6 +92,7 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte) skb = wl->tx_frames[id]; info = IEEE80211_SKB_CB(skb); + tx_desc = (struct wl1271_tx_hw_descr *)skb->data; if (wl12xx_is_dummy_packet(wl, skb)) { wl1271_free_tx_id(wl, id); @@ -105,7 +107,9 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte) * the info->status structures */ wl18xx_get_last_tx_rate(wl, info->control.vif, - info->band, &info->status.rates[0]); + info->band, + &info->status.rates[0], + tx_desc->hlid); info->status.rates[0].count = 1; /* no data about retries */ info->status.ack_signal = -1; @@ -144,12 +148,22 @@ void wl18xx_tx_immediate_complete(struct wl1271 *wl) struct wl18xx_fw_status_priv *status_priv = (struct wl18xx_fw_status_priv *)wl->fw_status->priv; struct wl18xx_priv *priv = wl->priv; - u8 i; + u8 i, hlid; /* nothing to do here */ if (priv->last_fw_rls_idx == status_priv->fw_release_idx) return; + /* update rates per link */ + hlid = wl->fw_status->counters.hlid; + + if (hlid < WLCORE_MAX_LINKS) { + wl->links[hlid].fw_rate_idx = + wl->fw_status->counters.tx_last_rate; + wl->links[hlid].fw_rate_mbps = + wl->fw_status->counters.tx_last_rate_mbps; + } + /* freed Tx descriptors */ wl1271_debug(DEBUG_TX, "last released desc = %d, current idx = %d", priv->last_fw_rls_idx, status_priv->fw_release_idx); diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h index 71e9e382ce80..5371cbdd54e0 100644 --- a/drivers/net/wireless/ti/wl18xx/wl18xx.h +++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h @@ -29,7 +29,7 @@ #define WL18XX_IFTYPE_VER 9 #define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE #define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE -#define WL18XX_MINOR_VER 11 +#define WL18XX_MINOR_VER 58 #define WL18XX_CMD_MAX_SIZE 740 @@ -125,7 +125,11 @@ struct wl18xx_fw_packet_counters { /* Tx rate of the last transmitted packet */ u8 tx_last_rate; - u8 padding[2]; + /* Tx rate or Tx rate estimate pre-calculated by fw in mbps units */ + u8 tx_last_rate_mbps; + + /* hlid for which the rates were reported */ + u8 hlid; } __packed; /* FW status registers */ diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h index 0d61fae88dcb..6321ed472891 100644 --- a/drivers/net/wireless/ti/wlcore/acx.h +++ b/drivers/net/wireless/ti/wlcore/acx.h @@ -105,6 +105,7 @@ enum wl12xx_role { WL1271_ROLE_DEVICE, WL1271_ROLE_P2P_CL, WL1271_ROLE_P2P_GO, + WL1271_ROLE_MESH_POINT, WL12XX_INVALID_ROLE_TYPE = 0xff }; diff --git a/drivers/net/wireless/ti/wlcore/boot.c b/drivers/net/wireless/ti/wlcore/boot.c index 19b7ec7b69c2..f75d30444117 100644 --- a/drivers/net/wireless/ti/wlcore/boot.c +++ b/drivers/net/wireless/ti/wlcore/boot.c @@ -130,7 +130,7 @@ fail: wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is invalid.\n" "Please use at least FW %s\n" "You can get the latest firmwares at:\n" - "git://github.com/TI-OpenLink/firmwares.git", + "git://git.ti.com/wilink8-wlan/wl18xx_fw.git", fw_ver[FW_VER_CHIP], fw_ver[FW_VER_IF_TYPE], fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE], fw_ver[FW_VER_MINOR], min_fw_str); diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 33153565ad62..7f4da727bb7b 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -629,11 +629,14 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id); - /* trying to use hidden SSID with an old hostapd version */ - if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) { - wl1271_error("got a null SSID from beacon/bss"); - ret = -EINVAL; - goto out; + /* If MESH --> ssid_len is always 0 */ + if (!ieee80211_vif_is_mesh(vif)) { + /* trying to use hidden SSID with an old hostapd version */ + if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) { + wl1271_error("got a null SSID from beacon/bss"); + ret = -EINVAL; + goto out; + } } cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -1566,6 +1569,13 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates, wlvif->band)); + if (!cmd->supported_rates) { + wl1271_debug(DEBUG_CMD, + "peer has no supported rates yet, configuring basic rates: 0x%x", + wlvif->basic_rate_set); + cmd->supported_rates = cpu_to_le32(wlvif->basic_rate_set); + } + wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x", cmd->supported_rates, sta->uapsd_queues); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 10fd24c28ece..1d689169da76 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -221,6 +221,7 @@ static void wlcore_rc_update_work(struct work_struct *work) struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif, rc_update_work); struct wl1271 *wl = wlvif->wl; + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); mutex_lock(&wl->mutex); @@ -231,8 +232,16 @@ static void wlcore_rc_update_work(struct work_struct *work) if (ret < 0) goto out; - wlcore_hw_sta_rc_update(wl, wlvif); + if (ieee80211_vif_is_mesh(vif)) { + ret = wl1271_acx_set_ht_capabilities(wl, &wlvif->rc_ht_cap, + true, wlvif->sta.hlid); + if (ret < 0) + goto out_sleep; + } else { + wlcore_hw_sta_rc_update(wl, wlvif); + } +out_sleep: wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); @@ -2153,10 +2162,14 @@ static void wlcore_free_klv_template(struct wl1271 *wl, u8 *idx) static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + switch (wlvif->bss_type) { case BSS_TYPE_AP_BSS: if (wlvif->p2p) return WL1271_ROLE_P2P_GO; + else if (ieee80211_vif_is_mesh(vif)) + return WL1271_ROLE_MESH_POINT; else return WL1271_ROLE_AP; @@ -2198,6 +2211,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) wlvif->p2p = 1; /* fall-through */ case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: wlvif->bss_type = BSS_TYPE_AP_BSS; break; default: @@ -2615,6 +2629,10 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, if (wl->scan.state != WL1271_SCAN_STATE_IDLE && wl->scan_wlvif == wlvif) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + /* * Rearm the tx watchdog just before idling scan. This * prevents just-finished scans from triggering the watchdog @@ -2625,7 +2643,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan_wlvif = NULL; wl->scan.req = NULL; - ieee80211_scan_completed(wl->hw, true); + ieee80211_scan_completed(wl->hw, &info); } if (wl->sched_vif == wlvif) @@ -3649,6 +3667,9 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct cfg80211_scan_info info = { + .aborted = true, + }; int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan"); @@ -3681,7 +3702,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan_wlvif = NULL; wl->scan.req = NULL; - ieee80211_scan_completed(wl->hw, true); + ieee80211_scan_completed(wl->hw, &info); out_sleep: wl1271_ps_elp_sleep(wl); @@ -4124,9 +4145,14 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, if (ret < 0) goto out; - ret = wl1271_ap_set_probe_resp_tmpl(wl, wlvif->basic_rate, vif); - if (ret < 0) - goto out; + /* No need to set probe resp template for mesh */ + if (!ieee80211_vif_is_mesh(vif)) { + ret = wl1271_ap_set_probe_resp_tmpl(wl, + wlvif->basic_rate, + vif); + if (ret < 0) + goto out; + } ret = wlcore_set_beacon_template(wl, vif, true); if (ret < 0) @@ -4960,6 +4986,7 @@ static int wl12xx_sta_add(struct wl1271 *wl, return ret; wl_sta = (struct wl1271_station *)sta->drv_priv; + wl_sta->wl = wl; hlid = wl_sta->hlid; ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid); @@ -5091,6 +5118,11 @@ static int wl12xx_update_sta_state(struct wl1271 *wl, if (ret < 0) return ret; + /* reconfigure rates */ + ret = wl12xx_cmd_add_peer(wl, wlvif, sta, wl_sta->hlid); + if (ret < 0) + return ret; + ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, wl_sta->hlid); if (ret) @@ -5629,6 +5661,7 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw, /* this callback is atomic, so schedule a new work */ wlvif->rc_update_bw = sta->bandwidth; + memcpy(&wlvif->rc_ht_cap, &sta->ht_cap, sizeof(sta->ht_cap)); ieee80211_queue_work(hw, &wlvif->rc_update_work); } @@ -5667,6 +5700,16 @@ out: mutex_unlock(&wl->mutex); } +static u32 wlcore_op_get_expected_throughput(struct ieee80211_sta *sta) +{ + struct wl1271_station *wl_sta = (struct wl1271_station *)sta->drv_priv; + struct wl1271 *wl = wl_sta->wl; + u8 hlid = wl_sta->hlid; + + /* return in units of Kbps */ + return (wl->links[hlid].fw_rate_mbps * 1000); +} + static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; @@ -5867,6 +5910,7 @@ static const struct ieee80211_ops wl1271_ops = { .switch_vif_chanctx = wlcore_op_switch_vif_chanctx, .sta_rc_update = wlcore_op_sta_rc_update, .sta_statistics = wlcore_op_sta_statistics, + .get_expected_throughput = wlcore_op_get_expected_throughput, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; @@ -6050,7 +6094,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_DEVICE) | BIT(NL80211_IFTYPE_P2P_CLIENT) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif BIT(NL80211_IFTYPE_P2P_GO); + wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->max_sched_scan_ssids = 16; wl->hw->wiphy->max_match_sets = 16; diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index c9bd294a0aa6..b9e14045195f 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -222,6 +222,13 @@ int wlcore_rx(struct wl1271 *wl, struct wl_fw_status *status) enum wl_rx_buf_align rx_align; int ret = 0; + /* update rates per link */ + hlid = status->counters.hlid; + + if (hlid < WLCORE_MAX_LINKS) + wl->links[hlid].fw_rate_mbps = + status->counters.tx_last_rate_mbps; + while (drv_rx_counter != fw_rx_counter) { buf_size = 0; rx_counter = drv_rx_counter; diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c index 23343643207a..5612f5916b4e 100644 --- a/drivers/net/wireless/ti/wlcore/scan.c +++ b/drivers/net/wireless/ti/wlcore/scan.c @@ -36,6 +36,9 @@ void wl1271_scan_complete_work(struct work_struct *work) struct delayed_work *dwork; struct wl1271 *wl; struct wl12xx_vif *wlvif; + struct cfg80211_scan_info info = { + .aborted = false, + }; int ret; dwork = to_delayed_work(work); @@ -82,7 +85,7 @@ void wl1271_scan_complete_work(struct work_struct *work) wlcore_cmd_regdomain_config_locked(wl); - ieee80211_scan_completed(wl->hw, false); + ieee80211_scan_completed(wl->hw, &info); out: mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index c172da56b550..5839acbbc782 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -241,7 +241,6 @@ static int wlcore_probe_of(struct device *dev, int *irq, *irq = irq_of_parse_and_map(np, 0); if (!*irq) { dev_err(dev, "No irq in platform data\n"); - kfree(pdev_data); return -EINVAL; } diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index cea9443c22a6..6d24040889b8 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -70,16 +70,30 @@ #define WSPI_MAX_CHUNK_SIZE 4092 /* - * only support SPI for 12xx - this code should be reworked when 18xx - * support is introduced + * wl18xx driver aggregation buffer size is (13 * PAGE_SIZE) compared to + * (4 * PAGE_SIZE) for wl12xx, so use the larger buffer needed for wl18xx */ -#define SPI_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) +#define SPI_AGGR_BUFFER_SIZE (13 * PAGE_SIZE) /* Maximum number of SPI write chunks */ #define WSPI_MAX_NUM_OF_CHUNKS \ ((SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) + 1) +struct wilink_familiy_data { + char name[8]; +}; + +const struct wilink_familiy_data *wilink_data; + +static const struct wilink_familiy_data wl18xx_data = { + .name = "wl18xx", +}; + +static const struct wilink_familiy_data wl12xx_data = { + .name = "wl12xx", +}; + struct wl12xx_spi_glue { struct device *dev; struct platform_device *core; @@ -119,6 +133,7 @@ static void wl12xx_spi_init(struct device *child) struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); struct spi_transfer t; struct spi_message m; + struct spi_device *spi = to_spi_device(glue->dev); u8 *cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); if (!cmd) { @@ -151,6 +166,7 @@ static void wl12xx_spi_init(struct device *child) cmd[6] |= WSPI_INIT_CMD_EN_FIXEDBUSY; cmd[7] = crc7_be(0, cmd+2, WSPI_INIT_CMD_CRC_LEN) | WSPI_INIT_CMD_END; + /* * The above is the logical order; it must actually be stored * in the buffer byte-swapped. @@ -163,6 +179,28 @@ static void wl12xx_spi_init(struct device *child) spi_message_add_tail(&t, &m); spi_sync(to_spi_device(glue->dev), &m); + + /* Send extra clocks with inverted CS (high). this is required + * by the wilink family in order to successfully enter WSPI mode. + */ + spi->mode ^= SPI_CS_HIGH; + memset(&m, 0, sizeof(m)); + spi_message_init(&m); + + cmd[0] = 0xff; + cmd[1] = 0xff; + cmd[2] = 0xff; + cmd[3] = 0xff; + __swab32s((u32 *)cmd); + + t.tx_buf = cmd; + t.len = 4; + spi_message_add_tail(&t, &m); + + spi_sync(to_spi_device(glue->dev), &m); + + /* Restore chip select configration to normal */ + spi->mode ^= SPI_CS_HIGH; kfree(cmd); } @@ -270,22 +308,25 @@ static int __must_check wl12xx_spi_raw_read(struct device *child, int addr, return 0; } -static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, - void *buf, size_t len, bool fixed) +static int __wl12xx_spi_raw_write(struct device *child, int addr, + void *buf, size_t len, bool fixed) { struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); - /* SPI write buffers - 2 for each chunk */ - struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; + struct spi_transfer *t; struct spi_message m; u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; /* 1 command per chunk */ u32 *cmd; u32 chunk_len; int i; + /* SPI write buffers - 2 for each chunk */ + t = kzalloc(sizeof(*t) * 2 * WSPI_MAX_NUM_OF_CHUNKS, GFP_KERNEL); + if (!t) + return -ENOMEM; + WARN_ON(len > SPI_AGGR_BUFFER_SIZE); spi_message_init(&m); - memset(t, 0, sizeof(t)); cmd = &commands[0]; i = 0; @@ -318,9 +359,26 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, spi_sync(to_spi_device(glue->dev), &m); + kfree(t); return 0; } +static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, + void *buf, size_t len, bool fixed) +{ + int ret; + + /* The ELP wakeup write may fail the first time due to internal + * hardware latency. It is safer to send the wakeup command twice to + * avoid unexpected failures. + */ + if (addr == HW_ACCESS_ELP_CTRL_REG) + ret = __wl12xx_spi_raw_write(child, addr, buf, len, fixed); + ret = __wl12xx_spi_raw_write(child, addr, buf, len, fixed); + + return ret; +} + /** * wl12xx_spi_set_power - power on/off the wl12xx unit * @child: wl12xx device handle. @@ -349,17 +407,38 @@ static int wl12xx_spi_set_power(struct device *child, bool enable) return ret; } +/** + * wl12xx_spi_set_block_size + * + * This function is not needed for spi mode, but need to be present. + * Without it defined the wlcore fallback to use the wrong packet + * allignment on tx. + */ +static void wl12xx_spi_set_block_size(struct device *child, + unsigned int blksz) +{ +} + static struct wl1271_if_operations spi_ops = { .read = wl12xx_spi_raw_read, .write = wl12xx_spi_raw_write, .reset = wl12xx_spi_reset, .init = wl12xx_spi_init, .power = wl12xx_spi_set_power, - .set_block_size = NULL, + .set_block_size = wl12xx_spi_set_block_size, }; static const struct of_device_id wlcore_spi_of_match_table[] = { - { .compatible = "ti,wl1271" }, + { .compatible = "ti,wl1271", .data = &wl12xx_data}, + { .compatible = "ti,wl1273", .data = &wl12xx_data}, + { .compatible = "ti,wl1281", .data = &wl12xx_data}, + { .compatible = "ti,wl1283", .data = &wl12xx_data}, + { .compatible = "ti,wl1801", .data = &wl18xx_data}, + { .compatible = "ti,wl1805", .data = &wl18xx_data}, + { .compatible = "ti,wl1807", .data = &wl18xx_data}, + { .compatible = "ti,wl1831", .data = &wl18xx_data}, + { .compatible = "ti,wl1835", .data = &wl18xx_data}, + { .compatible = "ti,wl1837", .data = &wl18xx_data}, { } }; MODULE_DEVICE_TABLE(of, wlcore_spi_of_match_table); @@ -375,18 +454,24 @@ static int wlcore_probe_of(struct spi_device *spi, struct wl12xx_spi_glue *glue, struct wlcore_platdev_data *pdev_data) { struct device_node *dt_node = spi->dev.of_node; - int ret; + const struct of_device_id *of_id; + + of_id = of_match_node(wlcore_spi_of_match_table, dt_node); + if (!of_id) + return -ENODEV; + + wilink_data = of_id->data; + dev_info(&spi->dev, "selected chip familiy is %s\n", + wilink_data->name); if (of_find_property(dt_node, "clock-xtal", NULL)) pdev_data->ref_clock_xtal = true; - ret = of_property_read_u32(dt_node, "ref-clock-frequency", - &pdev_data->ref_clock_freq); - if (ret) { - dev_err(glue->dev, - "can't get reference clock frequency (%d)\n", ret); - return ret; - } + /* optional clock frequency params */ + of_property_read_u32(dt_node, "ref-clock-frequency", + &pdev_data->ref_clock_freq); + of_property_read_u32(dt_node, "tcxo-clock-frequency", + &pdev_data->tcxo_clock_freq); return 0; } @@ -437,7 +522,8 @@ static int wl1271_probe(struct spi_device *spi) return ret; } - glue->core = platform_device_alloc("wl12xx", PLATFORM_DEVID_AUTO); + glue->core = platform_device_alloc(wilink_data->name, + PLATFORM_DEVID_AUTO); if (!glue->core) { dev_err(glue->dev, "can't allocate platform_device\n"); return -ENOMEM; diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 5c4199f3a19a..242b4e37b94c 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -171,6 +171,12 @@ struct wl_fw_status { /* Tx rate of the last transmitted packet */ u8 tx_last_rate; + + /* Tx rate or Tx rate estimate pre calculated by fw in mbps */ + u8 tx_last_rate_mbps; + + /* hlid for which the rates were reported */ + u8 hlid; } counters; u32 log_start_addr; @@ -273,6 +279,12 @@ struct wl1271_link { /* bitmap of TIDs where RX BA sessions are active for this link */ u8 ba_bitmap; + /* the last fw rate index we used for this link */ + u8 fw_rate_idx; + + /* the last fw rate [Mbps] we used for this link */ + u8 fw_rate_mbps; + /* The wlvif this link belongs to. Might be null for global links */ struct wl12xx_vif *wlvif; @@ -335,6 +347,7 @@ struct wl1271_station { * Used in both AP and STA mode. */ u64 total_freed_pkts; + struct wl1271 *wl; }; struct wl12xx_vif { @@ -472,6 +485,7 @@ struct wl12xx_vif { /* update rate conrol */ enum ieee80211_sta_rx_bandwidth rc_update_bw; + struct ieee80211_sta_ht_cap rc_ht_cap; struct work_struct rc_update_work; /* diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 13fd734b61ec..82d94f83b6b4 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -378,8 +378,7 @@ static int wl3501_esbq_exec(struct wl3501_card *this, void *sig, int sig_size) return rc; } -static int wl3501_get_mib_value(struct wl3501_card *this, u8 index, - void *bf, int size) +static int wl3501_request_mib(struct wl3501_card *this, u8 index, void *bf) { struct wl3501_get_req sig = { .sig_id = WL3501_SIG_GET_REQ, @@ -395,20 +394,32 @@ static int wl3501_get_mib_value(struct wl3501_card *this, u8 index, wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); wl3501_esbq_req(this, &ptr); this->sig_get_confirm.mib_status = 255; - spin_unlock_irqrestore(&this->lock, flags); - rc = wait_event_interruptible(this->wait, - this->sig_get_confirm.mib_status != 255); - if (!rc) - memcpy(bf, this->sig_get_confirm.mib_value, - size); - goto out; + rc = 0; } } spin_unlock_irqrestore(&this->lock, flags); -out: + return rc; } +static int wl3501_get_mib_value(struct wl3501_card *this, u8 index, + void *bf, int size) +{ + int rc; + + rc = wl3501_request_mib(this, index, bf); + if (rc) + return rc; + + rc = wait_event_interruptible(this->wait, + this->sig_get_confirm.mib_status != 255); + if (rc) + return rc; + + memcpy(bf, this->sig_get_confirm.mib_value, size); + return 0; +} + static int wl3501_pwr_mgmt(struct wl3501_card *this, int suspend) { struct wl3501_pwr_mgmt_req sig = { |