From 6379103e896a5e5aa707ea818588604ddd80064d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Sep 2012 15:33:42 +0200 Subject: iwlwifi: remove unused IDI code stubs These stubs are from internal experimental code and aren't needed in the driver in the kernel so just remove them. Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/drv.c | 13 ------------- drivers/net/wireless/iwlwifi/pcie/rx.c | 10 ++-------- drivers/net/wireless/iwlwifi/pcie/trans.c | 8 ++------ 3 files changed, 4 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 89bfb43f4946..2a4675396707 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -263,8 +263,6 @@ MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); /* PCI registers */ #define PCI_CFG_RETRY_TIMEOUT 0x041 -#ifndef CONFIG_IWLWIFI_IDI - static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); @@ -307,8 +305,6 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } -#endif /* CONFIG_IWLWIFI_IDI */ - #ifdef CONFIG_PM_SLEEP static int iwl_pci_suspend(struct device *device) @@ -353,15 +349,6 @@ static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume); #endif -#ifdef CONFIG_IWLWIFI_IDI -/* - * Defined externally in iwl-idi.c - */ -int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); -void __devexit iwl_pci_remove(struct pci_dev *pdev); - -#endif /* CONFIG_IWLWIFI_IDI */ - static struct pci_driver iwl_pci_driver = { .name = DRV_NAME, .id_table = iwl_hw_card_ids, diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index d80604a2bb1a..7b2ac6736f76 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -35,10 +35,6 @@ #include "internal.h" #include "iwl-op-mode.h" -#ifdef CONFIG_IWLWIFI_IDI -#include "iwl-amfh.h" -#endif - /****************************************************************************** * * RX path functions @@ -723,11 +719,9 @@ void iwl_irq_tasklet(struct iwl_trans *trans) /* Disable periodic interrupt; we use it as just a one-shot. */ iwl_write8(trans, CSR_INT_PERIODIC_REG, CSR_INT_PERIODIC_DIS); -#ifdef CONFIG_IWLWIFI_IDI - iwl_amfh_rx_handler(); -#else + iwl_rx_handle(trans); -#endif + /* * Enable periodic interrupt in 8 msec only if we received * real RX interrupt (instead of just periodic int), to catch diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 38f51b04217e..e555dff70b78 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -855,10 +855,8 @@ static int iwl_nic_init(struct iwl_trans *trans) iwl_op_mode_nic_config(trans->op_mode); -#ifndef CONFIG_IWLWIFI_IDI /* Allocate the RX queue, or reset if it is already allocated */ iwl_rx_init(trans); -#endif /* Allocate or reset and init all Tx and Command queues */ if (iwl_tx_init(trans)) @@ -1184,9 +1182,8 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) */ if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) { iwl_trans_tx_stop(trans); -#ifndef CONFIG_IWLWIFI_IDI iwl_trans_rx_stop(trans); -#endif + /* Power-down device's busmaster DMA clocks */ iwl_write_prph(trans, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); @@ -1551,9 +1548,8 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); iwl_trans_pcie_tx_free(trans); -#ifndef CONFIG_IWLWIFI_IDI iwl_trans_pcie_rx_free(trans); -#endif + if (trans_pcie->irq_requested == true) { free_irq(trans_pcie->irq, trans); iwl_free_isr_ict(trans); -- cgit v1.2.3 From f8fffc7e51462f51ffca6d0df505ef16afee2fb6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2012 15:16:02 +0200 Subject: mac80211_hwsim: move module_init/exit These should be with the functions so move the module_init/exit statements. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 72b0456e41bf..e603adbfb985 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2056,7 +2056,7 @@ failed: mac80211_hwsim_free(); return err; } - +module_init(init_mac80211_hwsim); static void __exit exit_mac80211_hwsim(void) { @@ -2067,7 +2067,4 @@ static void __exit exit_mac80211_hwsim(void) mac80211_hwsim_free(); unregister_netdev(hwsim_mon); } - - -module_init(init_mac80211_hwsim); module_exit(exit_mac80211_hwsim); -- cgit v1.2.3 From e548c49e6dc6b08b59042930a2e90c69c13c9293 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 4 Sep 2012 17:08:23 +0200 Subject: mac80211: add key flag for management keys Mark keys that might be used to receive management frames so drivers can fall back on software crypto for them if they don't support hardware offload. As the new flag is only set correctly for RX keys and the existing IEEE80211_KEY_FLAG_SW_MGMT flag can only affect TX, also rename the latter to IEEE80211_KEY_FLAG_SW_MGMT_TX. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 2 +- include/net/mac80211.h | 12 ++++++++-- net/mac80211/cfg.c | 32 +++++++++++++++++++++++++++ net/mac80211/tx.c | 2 +- 6 files changed, 46 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index c89fa6ead615..155c70e4c26c 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -524,7 +524,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (key->cipher == WLAN_CIPHER_SUITE_TKIP) key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; if (key->cipher == WLAN_CIPHER_SUITE_CCMP) - key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; ret = 0; } break; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index c32f6e3ffb18..a6bb6e3698ca 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1449,7 +1449,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw, key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; if (priv->ah->sw_mgmt_crypto && key->cipher == WLAN_CIPHER_SUITE_CCMP) - key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; ret = 0; } break; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 4d8dc9ff5a75..06c628e85a43 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1441,7 +1441,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; if (sc->sc_ah->sw_mgmt_crypto && key->cipher == WLAN_CIPHER_SUITE_CCMP) - key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; ret = 0; } break; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 71f8262fc1df..82558c8decf8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -973,21 +973,29 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) * generation in software. * @IEEE80211_KEY_FLAG_PAIRWISE: Set by mac80211, this flag indicates * that the key is pairwise rather then a shared key. - * @IEEE80211_KEY_FLAG_SW_MGMT: This flag should be set by the driver for a + * @IEEE80211_KEY_FLAG_SW_MGMT_TX: This flag should be set by the driver for a * CCMP key if it requires CCMP encryption of management frames (MFP) to * be done in software. * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver * if space should be prepared for the IV, but the IV * itself should not be generated. Do not set together with * @IEEE80211_KEY_FLAG_GENERATE_IV on the same key. + * @IEEE80211_KEY_FLAG_RX_MGMT: This key will be used to decrypt received + * management frames. The flag can help drivers that have a hardware + * crypto implementation that doesn't deal with management frames + * properly by allowing them to not upload the keys to hardware and + * fall back to software crypto. Note that this flag deals only with + * RX, if your crypto engine can't deal with TX you can also set the + * %IEEE80211_KEY_FLAG_SW_MGMT_TX flag to encrypt such frames in SW. */ enum ieee80211_key_flags { IEEE80211_KEY_FLAG_WMM_STA = 1<<0, IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1, IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2, IEEE80211_KEY_FLAG_PAIRWISE = 1<<3, - IEEE80211_KEY_FLAG_SW_MGMT = 1<<4, + IEEE80211_KEY_FLAG_SW_MGMT_TX = 1<<4, IEEE80211_KEY_FLAG_PUT_IV_SPACE = 1<<5, + IEEE80211_KEY_FLAG_RX_MGMT = 1<<6, }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 03fe6d1cff42..00e31b488adc 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -170,6 +170,38 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, } } + switch (sdata->vif.type) { + case NL80211_IFTYPE_STATION: + if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED) + key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + /* Keys without a station are used for TX only */ + if (key->sta && test_sta_flag(key->sta, WLAN_STA_MFP)) + key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; + break; + case NL80211_IFTYPE_ADHOC: + /* no MFP (yet) */ + break; + case NL80211_IFTYPE_MESH_POINT: +#ifdef CONFIG_MAC80211_MESH + if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE) + key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; + break; +#endif + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_P2P_DEVICE: + case NL80211_IFTYPE_UNSPECIFIED: + case NUM_NL80211_IFTYPES: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + /* shouldn't happen */ + WARN_ON_ONCE(1); + break; + } + err = ieee80211_key_link(key, sdata, sta); if (err) ieee80211_key_free(sdata->local, key); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 29eb4e678235..e0e0d1d0e830 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -580,7 +580,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) tx->key = NULL; else skip_hw = (tx->key->conf.flags & - IEEE80211_KEY_FLAG_SW_MGMT) && + IEEE80211_KEY_FLAG_SW_MGMT_TX) && ieee80211_is_mgmt(hdr->frame_control); break; case WLAN_CIPHER_SUITE_AES_CMAC: -- cgit v1.2.3 From 8b61fa242ce56838ce1c41db3692b64b4c344776 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Wed, 8 Aug 2012 15:17:26 +0300 Subject: iwlwifi: don't reset interupts after disabling iwl_disable_interupts() already resets the register, no need to do it again. Signed-off-by: David Spinadel Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/trans.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index e555dff70b78..913ad46a6686 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1459,8 +1459,6 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, iwl_disable_interrupts(trans); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); - iwl_write32(trans, CSR_INT, 0xFFFFFFFF); - if (!op_mode_leaving) { /* * Even if we stop the HW, we still want the RF kill -- cgit v1.2.3 From ee7d737c45440062320c16bc7ad7bb5c9fe8888e Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Sun, 12 Aug 2012 08:14:04 +0300 Subject: iwlwifi: stop interrupts before stopping device If an RX interrupt is signalled after or during apm_stop we may try to access the peripherals which are already down. Prevent this by disabling interrupts first. Signed-off-by: David Spinadel Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/trans.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 913ad46a6686..7da075f5bffa 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1453,6 +1453,10 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, bool hw_rfkill; unsigned long flags; + spin_lock_irqsave(&trans_pcie->irq_lock, flags); + iwl_disable_interrupts(trans); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + iwl_apm_stop(trans); spin_lock_irqsave(&trans_pcie->irq_lock, flags); -- cgit v1.2.3 From 2d1c0044ddc708885146af1d6790436a613cac5b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 9 Sep 2012 20:59:17 +0200 Subject: iwlwifi: fix indentation in iwl_load_given_ucode There's a block of code that's indented too far, move it out to where it should be. Signed-off-by: Johannes Berg Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/trans.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 7da075f5bffa..3f11b17e14ce 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -979,17 +979,16 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num, static int iwl_load_given_ucode(struct iwl_trans *trans, const struct fw_img *image) { - int ret = 0; - int i; + int i, ret = 0; - for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) { - if (!image->sec[i].p_addr) - break; + for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) { + if (!image->sec[i].p_addr) + break; - ret = iwl_load_section(trans, i, &image->sec[i]); - if (ret) - return ret; - } + ret = iwl_load_section(trans, i, &image->sec[i]); + if (ret) + return ret; + } /* Remove all resets to allow NIC to operate */ iwl_write32(trans, CSR_RESET, 0); -- cgit v1.2.3 From 358a46d47eefadd5be67495682426bd743ce455c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 9 Sep 2012 16:39:18 +0300 Subject: iwlwifi: some clean up in transport layer Remove outdated iwlagn prefix to a few functions and fix comments that were not accurate. Signed-off-by: Emmanuel Grumbach Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/internal.h | 2 +- drivers/net/wireless/iwlwifi/pcie/rx.c | 54 ++++++++++++++++------------ drivers/net/wireless/iwlwifi/pcie/trans.c | 2 +- 3 files changed, 33 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 3ef8d5adc991..fa102b8a125f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -311,7 +311,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans); ******************************************************/ void iwl_bg_rx_replenish(struct work_struct *data); void iwl_irq_tasklet(struct iwl_trans *trans); -void iwlagn_rx_replenish(struct iwl_trans *trans); +void iwl_rx_replenish(struct iwl_trans *trans); void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, struct iwl_rx_queue *q); diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 7b2ac6736f76..7fc38217d76d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -177,15 +177,15 @@ void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, } /** - * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr + * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr */ -static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr) +static inline __le32 iwl_dma_addr2rbd_ptr(dma_addr_t dma_addr) { return cpu_to_le32((u32)(dma_addr >> 8)); } /** - * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool + * iwl_rx_queue_restock - refill RX queue from pre-allocated pool * * If there are slots in the RX queue that need to be restocked, * and we have free pre-allocated buffers, fill the ranks as much @@ -195,7 +195,7 @@ static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr) * also updates the memory address in the firmware to reference the new * target buffer. */ -static void iwlagn_rx_queue_restock(struct iwl_trans *trans) +static void iwl_rx_queue_restock(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rx_queue *rxq = &trans_pcie->rxq; @@ -215,7 +215,7 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans) list_del(element); /* Point to Rx buffer via next RBD in circular buffer */ - rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(rxb->page_dma); + rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(rxb->page_dma); rxq->queue[rxq->write] = rxb; rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; rxq->free_count--; @@ -226,7 +226,6 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans) if (rxq->free_count <= RX_LOW_WATERMARK) schedule_work(&trans_pcie->rx_replenish); - /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ if (rxq->write_actual != (rxq->write & ~0x7)) { @@ -237,15 +236,16 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans) } } -/** - * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free - * - * When moving to rx_free an SKB is allocated for the slot. +/* + * iwl_rx_allocate - allocate a page for each used RBD * - * Also restock the Rx queue via iwl_rx_queue_restock. - * This is called as a scheduled work item (except for during initialization) + * A used RBD is an Rx buffer that has been given to the stack. To use it again + * a page must be allocated and the RBD must point to the page. This function + * doesn't change the HW pointer but handles the list of pages that is used by + * iwl_rx_queue_restock. The latter function will update the HW to use the newly + * allocated buffers. */ -static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) +static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rx_queue *rxq = &trans_pcie->rxq; @@ -324,23 +324,31 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) } } -void iwlagn_rx_replenish(struct iwl_trans *trans) +/* + * iwl_rx_replenish - Move all used buffers from rx_used to rx_free + * + * When moving to rx_free an page is allocated for the slot. + * + * Also restock the Rx queue via iwl_rx_queue_restock. + * This is called as a scheduled work item (except for during initialization) + */ +void iwl_rx_replenish(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); unsigned long flags; - iwlagn_rx_allocate(trans, GFP_KERNEL); + iwl_rx_allocate(trans, GFP_KERNEL); spin_lock_irqsave(&trans_pcie->irq_lock, flags); - iwlagn_rx_queue_restock(trans); + iwl_rx_queue_restock(trans); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } -static void iwlagn_rx_replenish_now(struct iwl_trans *trans) +static void iwl_rx_replenish_now(struct iwl_trans *trans) { - iwlagn_rx_allocate(trans, GFP_ATOMIC); + iwl_rx_allocate(trans, GFP_ATOMIC); - iwlagn_rx_queue_restock(trans); + iwl_rx_queue_restock(trans); } void iwl_bg_rx_replenish(struct work_struct *data) @@ -348,7 +356,7 @@ void iwl_bg_rx_replenish(struct work_struct *data) struct iwl_trans_pcie *trans_pcie = container_of(data, struct iwl_trans_pcie, rx_replenish); - iwlagn_rx_replenish(trans_pcie->trans); + iwl_rx_replenish(trans_pcie->trans); } static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, @@ -526,7 +534,7 @@ static void iwl_rx_handle(struct iwl_trans *trans) count++; if (count >= 8) { rxq->read = i; - iwlagn_rx_replenish_now(trans); + iwl_rx_replenish_now(trans); count = 0; } } @@ -535,9 +543,9 @@ static void iwl_rx_handle(struct iwl_trans *trans) /* Backtrack one entry */ rxq->read = i; if (fill_rx) - iwlagn_rx_replenish_now(trans); + iwl_rx_replenish_now(trans); else - iwlagn_rx_queue_restock(trans); + iwl_rx_queue_restock(trans); } /** diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 3f11b17e14ce..d44fa2a220f1 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -216,7 +216,7 @@ static int iwl_rx_init(struct iwl_trans *trans) rxq->free_count = 0; spin_unlock_irqrestore(&rxq->lock, flags); - iwlagn_rx_replenish(trans); + iwl_rx_replenish(trans); iwl_trans_rx_hw_init(trans, rxq); -- cgit v1.2.3 From 7439046d9747966bb805ca8bfd1086a876a4b8fd Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 9 Sep 2012 16:58:07 +0300 Subject: iwlwifi: don't access the HW when it is not available When we kill the radio with the RF kill button we could access the HW after having stopped the APM which would result in the warning below. The flow goes like this: * RF kill iwlwifi notifies the stack which stops the driver fw sends CARD_STATE_NOTIFICATION * iwl_trans_pcie_stop_device stops the APM * the tasklet runs and calls to iwl_rx_handle * iwl_rx_handle calls iwl_rx_queue_restock * iwl_rx_queue_restock tries to access the HW... [255908.543823] ------------[ cut here ]------------ [255908.543843] WARNING: at drivers/net/wireless/iwlwifi/iwl-io.c:150 iwl_grab_nic_access+0x79/0xb0 [iwlwifi]() [255908.543849] Hardware name: Latitude E6410 [255908.543852] Timeout waiting for hardware access (CSR_GP_CNTRL 0x000003d8) [255908.543856] Modules linked in: iwlmvm iwlwifi mac80211 [...] [255908.543935] Pid: 0, comm: swapper Tainted: G W 3.1.0 #1 [255908.543939] Call Trace: [255908.543950] [] warn_slowpath_common+0x72/0xa0 [255908.543980] [] warn_slowpath_fmt+0x33/0x40 [255908.543992] [] iwl_grab_nic_access+0x79/0xb0 [iwlwifi] [255908.544004] [] iwl_write_direct32+0x2b/0xa0 [iwlwifi] [255908.544018] [] iwl_rx_queue_update_write_ptr+0x89/0x1d0 [iwlwifi] [255908.544054] [] iwlagn_rx_queue_restock+0x110/0x140 [iwlwifi] [255908.544067] [] iwl_irq_tasklet+0x82d/0xf40 [iwlwifi] [255908.544096] [] tasklet_action+0xbe/0x100 [255908.544102] [] __do_softirq+0xae/0x1f0 [255908.544227] ---[ end trace d150f49345d85009 ]--- Prevent this. Signed-off-by: Emmanuel Grumbach Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/rx.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 7fc38217d76d..6d71f51ef548 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -203,6 +203,17 @@ static void iwl_rx_queue_restock(struct iwl_trans *trans) struct iwl_rx_mem_buffer *rxb; unsigned long flags; + /* + * If the device isn't enabled - not need to try to add buffers... + * This can happen when we stop the device and still have an interrupt + * pending. We stop the APM before we sync the interrupts / tasklets + * because we have to (see comment there). On the other hand, since + * the APM is stopped, we cannot access the HW (in particular not prph). + * So don't try to restock if the APM has been already stopped. + */ + if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) + return; + spin_lock_irqsave(&rxq->lock, flags); while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { /* The overwritten rxb must be a used one */ -- cgit v1.2.3 From 83f84d7bd49f9e4deea0a77a76c9882673ee1f3c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Sep 2012 11:50:18 +0200 Subject: iwlwifi: load firmware in chunks Instead of allocating one big chunk of DMA-coherent memory for the firmware and keeping it around, only vmalloc() the firmware and copy it into a single page of DMA-coherent memory for the upload. The advantage is that we don't need DMA memory for the firmware image that is stored while the driver is operating, we only need it while uploading. This will make it easier for the driver to work if the system has fragmented memory. Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/ucode.c | 4 +-- drivers/net/wireless/iwlwifi/iwl-drv.c | 26 ++++++++------- drivers/net/wireless/iwlwifi/iwl-fw.h | 3 +- drivers/net/wireless/iwlwifi/pcie/trans.c | 53 ++++++++++++++++++++++++------- 4 files changed, 58 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 6d8d6dd7943f..2cb1efbc5ed1 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -295,7 +295,7 @@ static int iwl_alive_notify(struct iwl_priv *priv) static int iwl_verify_sec_sparse(struct iwl_priv *priv, const struct fw_desc *fw_desc) { - __le32 *image = (__le32 *)fw_desc->v_addr; + __le32 *image = (__le32 *)fw_desc->data; u32 len = fw_desc->len; u32 val; u32 i; @@ -319,7 +319,7 @@ static int iwl_verify_sec_sparse(struct iwl_priv *priv, static void iwl_print_mismatch_sec(struct iwl_priv *priv, const struct fw_desc *fw_desc) { - __le32 *image = (__le32 *)fw_desc->v_addr; + __le32 *image = (__le32 *)fw_desc->data; u32 len = fw_desc->len; u32 val; u32 offs; diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 48d6d44c16d0..198634b75ed0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -64,6 +64,7 @@ #include #include #include +#include #include "iwl-drv.h" #include "iwl-debug.h" @@ -164,10 +165,8 @@ struct fw_sec { static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc) { - if (desc->v_addr) - dma_free_coherent(drv->trans->dev, desc->len, - desc->v_addr, desc->p_addr); - desc->v_addr = NULL; + vfree(desc->data); + desc->data = NULL; desc->len = 0; } @@ -186,21 +185,24 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv) } static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, - struct fw_sec *sec) + struct fw_sec *sec) { - if (!sec || !sec->size) { - desc->v_addr = NULL; + void *data; + + desc->data = NULL; + + if (!sec || !sec->size) return -EINVAL; - } - desc->v_addr = dma_alloc_coherent(drv->trans->dev, sec->size, - &desc->p_addr, GFP_KERNEL); - if (!desc->v_addr) + data = vmalloc(sec->size); + if (!data) return -ENOMEM; desc->len = sec->size; desc->offset = sec->offset; - memcpy(desc->v_addr, sec->data, sec->size); + memcpy(data, sec->data, desc->len); + desc->data = data; + return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 2153e4cc5572..d1a86b66bc51 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -124,8 +124,7 @@ struct iwl_ucode_capabilities { /* one for each uCode image (inst/data, init/runtime/wowlan) */ struct fw_desc { - dma_addr_t p_addr; /* hardware address */ - void *v_addr; /* software address */ + const void *data; /* vmalloc'ed data */ u32 len; /* size in bytes */ u32 offset; /* offset in the device */ }; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index d44fa2a220f1..3cb4f858d4eb 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -923,13 +923,10 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans) /* * ucode */ -static int iwl_load_section(struct iwl_trans *trans, u8 section_num, - const struct fw_desc *section) +static int iwl_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); - dma_addr_t phy_addr = section->p_addr; - u32 byte_cnt = section->len; - u32 dst_addr = section->offset; int ret; trans_pcie->ucode_write_complete = false; @@ -943,8 +940,8 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num, dst_addr); iwl_write_direct32(trans, - FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), - phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); + FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), + phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); iwl_write_direct32(trans, FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), @@ -963,26 +960,58 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num, FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); - IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n", - section_num); ret = wait_event_timeout(trans_pcie->ucode_write_waitq, trans_pcie->ucode_write_complete, 5 * HZ); if (!ret) { - IWL_ERR(trans, "Could not load the [%d] uCode section\n", - section_num); + IWL_ERR(trans, "Failed to load firmware chunk!\n"); return -ETIMEDOUT; } return 0; } +static int iwl_load_section(struct iwl_trans *trans, u8 section_num, + const struct fw_desc *section) +{ + u8 *v_addr; + dma_addr_t p_addr; + u32 offset; + int ret = 0; + + IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n", + section_num); + + v_addr = dma_alloc_coherent(trans->dev, PAGE_SIZE, &p_addr, GFP_KERNEL); + if (!v_addr) + return -ENOMEM; + + for (offset = 0; offset < section->len; offset += PAGE_SIZE) { + u32 copy_size; + + copy_size = min_t(u32, PAGE_SIZE, section->len - offset); + + memcpy(v_addr, (u8 *)section->data + offset, copy_size); + ret = iwl_load_firmware_chunk(trans, section->offset + offset, + p_addr, copy_size); + if (ret) { + IWL_ERR(trans, + "Could not load the [%d] uCode section\n", + section_num); + break; + } + } + + dma_free_coherent(trans->dev, PAGE_SIZE, v_addr, p_addr); + return ret; +} + static int iwl_load_given_ucode(struct iwl_trans *trans, const struct fw_img *image) { int i, ret = 0; for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) { - if (!image->sec[i].p_addr) + if (!image->sec[i].data) break; ret = iwl_load_section(trans, i, &image->sec[i]); -- cgit v1.2.3 From 552bff0c2fec8953ba3793d75ee335032cc0b47c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Sep 2012 09:26:06 +0200 Subject: cfg80211: constify name parameter to add_virtual_intf The name can't be modified by the driver, make it const. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 4 ++-- drivers/net/wireless/ath/ath6kl/cfg80211.h | 2 +- drivers/net/wireless/mwifiex/cfg80211.c | 2 +- drivers/net/wireless/mwifiex/main.h | 2 +- include/net/cfg80211.h | 2 +- net/mac80211/cfg.c | 3 ++- 6 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 86aeef4b9d7e..7089f8160ad5 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1488,7 +1488,7 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, } static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, - char *name, + const char *name, enum nl80211_iftype type, u32 *flags, struct vif_params *params) @@ -3477,7 +3477,7 @@ void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif) ar->num_vif--; } -struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name, +struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, enum nl80211_iftype type, u8 fw_vif_idx, u8 nw_type) { diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index 56b1ebe79812..780f77775a91 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h @@ -25,7 +25,7 @@ enum ath6kl_cfg_suspend_mode { ATH6KL_CFG_SUSPEND_SCHED_SCAN, }; -struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name, +struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, enum nl80211_iftype type, u8 fw_vif_idx, u8 nw_type); void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index e57f543413de..49e20661b60b 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1597,7 +1597,7 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, * create a new virtual interface with the given name */ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, - char *name, + const char *name, enum nl80211_iftype type, u32 *flags, struct vif_params *params) diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 994bc4fc263e..d2fb3c3e1db1 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1030,7 +1030,7 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, - char *name, + const char *name, enum nl80211_iftype type, u32 *flags, struct vif_params *params); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 80051ffc2755..ab78b53bd6f5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1628,7 +1628,7 @@ struct cfg80211_ops { void (*set_wakeup)(struct wiphy *wiphy, bool enabled); struct wireless_dev * (*add_virtual_intf)(struct wiphy *wiphy, - char *name, + const char *name, enum nl80211_iftype type, u32 *flags, struct vif_params *params); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9bd56a744982..05f3a313db88 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -20,7 +20,8 @@ #include "rate.h" #include "mesh.h" -static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, char *name, +static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, + const char *name, enum nl80211_iftype type, u32 *flags, struct vif_params *params) -- cgit v1.2.3 From ca42613a55aa947704a40945597c6f9b856df437 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Sep 2012 11:55:49 +0200 Subject: iwlwifi: use eth_broadcast_addr Instead of memcpy() from a static array, just use the new helper function eth_broadcast_addr(). Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c index e3467fa86899..bb9f6252d28f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/iwlwifi/dvm/scan.c @@ -612,9 +612,9 @@ static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, return 0; frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - memcpy(frame->da, iwl_bcast_addr, ETH_ALEN); + eth_broadcast_addr(frame->da); memcpy(frame->sa, ta, ETH_ALEN); - memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN); + eth_broadcast_addr(frame->bssid); frame->seq_ctrl = 0; len += 24; -- cgit v1.2.3 From 513aa3b0d14be809490d5c151994cc7f047b0718 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 20 Sep 2012 16:06:14 +0200 Subject: iwlwifi: fix async station command crash Before Emmanuel's change to use a copy of the command ("iwlwifi: get the correct HCMD in the response handler") the iwl_add_sta_callback() function would have used a random pointer to somewhere when processing responses to an async command, while that wasn't valid data it was at least a valid pointer. Now, the pointer will be NULL in this case, thus crashing. Fix this by exiting the function early if no command is passed back which means it was sent asynchronously. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/sta.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index fe36a38f3505..cd9b6de4273e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -128,10 +128,11 @@ int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_addsta_cmd *addsta = - (struct iwl_addsta_cmd *) cmd->payload; - return iwl_process_add_sta_resp(priv, addsta, pkt); + if (!cmd) + return 0; + + return iwl_process_add_sta_resp(priv, (void *)cmd->payload, pkt); } int iwl_send_add_sta(struct iwl_priv *priv, -- cgit v1.2.3 From 215999f38017e8e26791fafc60631b4099ee04ea Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 12 Sep 2012 14:59:58 +0530 Subject: ath9k: Enable SGI correctly Set the driver specific SGI flag based on the station's HT capabilities, otherwise rate control uses the wrong rate. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 4b12c347d188..27ed80b54881 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1222,11 +1222,14 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta) caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; else if (sta->ht_cap.mcs.rx_mask[1]) caps |= WLAN_RC_DS_FLAG; - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { caps |= WLAN_RC_40_FLAG; - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40 || - sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) - caps |= WLAN_RC_SGI_FLAG; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) + caps |= WLAN_RC_SGI_FLAG; + } else { + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) + caps |= WLAN_RC_SGI_FLAG; + } } return caps; -- cgit v1.2.3 From 88033318e119bbf4647db4d50ad549fc86e0acf0 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 12 Sep 2012 18:59:19 +0530 Subject: ath9k_hw: move 2g5g switch before nfcal start During fast channel change, perform 2g5g_switch before starting noisefloor calibration to avoid nfload timeout. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 99cab44d2312..c40e901c2bf8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1733,12 +1733,12 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) if (!ret) goto fail; - ath9k_hw_loadnf(ah, ah->curchan); - ath9k_hw_start_nfcal(ah, true); - if (ath9k_hw_mci_is_enabled(ah)) ar9003_mci_2g5g_switch(ah, false); + ath9k_hw_loadnf(ah, ah->curchan); + ath9k_hw_start_nfcal(ah, true); + if (AR_SREV_9271(ah)) ar9002_hw_load_ani_reg(ah, chan); -- cgit v1.2.3 From bfbee42793a564762d2681d88dc19f4c2d8ee6fd Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 12 Sep 2012 18:59:20 +0530 Subject: ath9k_hw: fix ar9462 selfgen chainmask When the 9462 is operating in 2G mode and MCI is enabled then reduce the selfgen chain mask to chain 1. Otherwise poor performance was reported at short range at Rx side when COEX is enabled. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mci.c | 1 + drivers/net/wireless/ath/ath9k/ar9003_phy.c | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index b2e39e8a21b5..f6eb43ee87ee 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -1027,6 +1027,7 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force) if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) ar9003_mci_osla_setup(ah, true); + REG_WRITE(ah, AR_SELFGEN_MASK, 0x02); } else { ar9003_mci_send_lna_take(ah, true); udelay(5); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 0d800c62e227..158b50d3a853 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -605,9 +605,6 @@ static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7)) REG_WRITE(ah, AR_SELFGEN_MASK, 0x3); - else if (AR_SREV_9462(ah)) - /* xxx only when MCI support is enabled */ - REG_WRITE(ah, AR_SELFGEN_MASK, 0x3); else REG_WRITE(ah, AR_SELFGEN_MASK, tx); -- cgit v1.2.3 From d92bb98f0c13f711bb04f447f7e19da0163eded2 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 12 Sep 2012 18:59:21 +0530 Subject: ath9k: flush bt profile whenever it is requested Before processing BT profiles or status messages, check whether it is requested to flush BT profile. Otherwise it might increase number of BT profiles that affects the WLAN performance. Also flush the profiles when MCI is recovering from broken rx. After flushing BT profiles, query BT topology to refetch them. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mci.c | 4 ++++ drivers/net/wireless/ath/ath9k/ar9003_mci.h | 4 +++- drivers/net/wireless/ath/ath9k/mci.c | 12 +++++++++++- 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index f6eb43ee87ee..8d8df4b2c386 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -1236,6 +1236,10 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) case MCI_STATE_NEED_FTP_STOMP: value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); break; + case MCI_STATE_NEED_FLUSH_BT_INFO: + value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0; + mci->need_flush_btinfo = false; + break; default: break; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h index f3bef8d69edd..30acf2869aa4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h @@ -200,6 +200,7 @@ enum mci_state_type { MCI_STATE_RECOVER_RX, MCI_STATE_NEED_FTP_STOMP, MCI_STATE_DEBUG, + MCI_STATE_NEED_FLUSH_BT_INFO, MCI_STATE_MAX }; @@ -211,7 +212,8 @@ enum mci_gpm_coex_opcode { MCI_GPM_COEX_WLAN_CHANNELS, MCI_GPM_COEX_BT_PROFILE_INFO, MCI_GPM_COEX_BT_STATUS_UPDATE, - MCI_GPM_COEX_BT_UPDATE_FLAGS + MCI_GPM_COEX_BT_UPDATE_FLAGS, + MCI_GPM_COEX_NOOP, }; #define MCI_GPM_NOMORE 0 diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 8f0e8d9c2054..3a400c83c077 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -80,6 +80,7 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci) struct ath_mci_profile_info *info, *tinfo; mci->aggr_limit = 0; + mci->num_mgmt = 0; if (list_empty(&mci->info)) return; @@ -328,6 +329,13 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) u8 major, minor; u32 seq_num; + if (ar9003_mci_state(ah, MCI_STATE_NEED_FLUSH_BT_INFO) && + ar9003_mci_state(ah, MCI_STATE_ENABLE)) { + ath_dbg(common, MCI, "(MCI) Need to flush BT profiles\n"); + ath_mci_flush_profile(&sc->btcoex.mci); + ar9003_mci_state(ah, MCI_STATE_SEND_STATUS_QUERY); + } + switch (opcode) { case MCI_GPM_COEX_VERSION_QUERY: ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION); @@ -568,9 +576,11 @@ void ath_mci_intr(struct ath_softc *sc) } if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) || - (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) + (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) { mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR | AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT); + ath_mci_msg(sc, MCI_GPM_COEX_NOOP, NULL); + } } void ath_mci_enable(struct ath_softc *sc) -- cgit v1.2.3 From 9e62817b9faee8d286580673b8eafb05e778ec1d Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 12 Sep 2012 18:59:22 +0530 Subject: ath9k: move coex param updation within mci work Update all coex parameters in sigle place. So that we can avoid redoing the same operation in mutiple places and it eases debugging. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/mci.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 3a400c83c077..fa859e3fbc29 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -121,7 +121,14 @@ static void ath_mci_update_scheme(struct ath_softc *sc) if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_TUNING) goto skip_tuning; + mci->aggr_limit = 0; btcoex->duty_cycle = ath_mci_duty_cycle[num_profile]; + btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD; + if (NUM_PROF(mci)) + btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; + else + btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL : + ATH_BTCOEX_STOMP_LOW; if (num_profile == 1) { info = list_first_entry(&mci->info, @@ -133,7 +140,8 @@ static void ath_mci_update_scheme(struct ath_softc *sc) else if (info->T == 6) { mci->aggr_limit = 6; btcoex->duty_cycle = 30; - } + } else + mci->aggr_limit = 6; ath_dbg(common, MCI, "Single SCO, aggregation limit %d 1/4 ms\n", mci->aggr_limit); @@ -273,16 +281,6 @@ static void ath_mci_process_profile(struct ath_softc *sc, } else ath_mci_del_profile(common, mci, entry); - btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD; - mci->aggr_limit = mci->num_sco ? 6 : 0; - - btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)]; - if (NUM_PROF(mci)) - btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - else - btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL : - ATH_BTCOEX_STOMP_LOW; - ieee80211_queue_work(sc->hw, &sc->mci_work); } -- cgit v1.2.3 From 8f176a3a16d124285cecd6c53b70689eb3b9ba36 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 12 Sep 2012 18:59:23 +0530 Subject: ath9k: fill led_pin before drv_start Ensure that led pin is filled and set to OFF before starting the driver. With recent changes, drv_start is being called even before led_init is being completed. This is causing led is always OFF on driver load when the interface is UP. This patch splits the led init and fills the led pin before register hw. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++++ drivers/net/wireless/ath/ath9k/gpio.c | 44 +++++++++++++++++++--------------- drivers/net/wireless/ath/ath9k/init.c | 1 + 3 files changed, 30 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 96b8331ef9e7..fd24535677a6 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -537,6 +537,7 @@ struct ath9k_wow_pattern { #ifdef CONFIG_MAC80211_LEDS void ath_init_leds(struct ath_softc *sc); void ath_deinit_leds(struct ath_softc *sc); +void ath_fill_led_pin(struct ath_softc *sc); #else static inline void ath_init_leds(struct ath_softc *sc) { @@ -545,6 +546,9 @@ static inline void ath_init_leds(struct ath_softc *sc) static inline void ath_deinit_leds(struct ath_softc *sc) { } +static inline void ath_fill_led_pin(struct ath_softc *sc) +{ +} #endif /*******************************/ diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 45f24220b16e..1934cca8a6cc 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -44,25 +44,6 @@ void ath_init_leds(struct ath_softc *sc) if (AR_SREV_9100(sc->sc_ah)) return; - if (sc->sc_ah->led_pin < 0) { - if (AR_SREV_9287(sc->sc_ah)) - sc->sc_ah->led_pin = ATH_LED_PIN_9287; - else if (AR_SREV_9485(sc->sc_ah)) - sc->sc_ah->led_pin = ATH_LED_PIN_9485; - else if (AR_SREV_9300(sc->sc_ah)) - sc->sc_ah->led_pin = ATH_LED_PIN_9300; - else if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah)) - sc->sc_ah->led_pin = ATH_LED_PIN_9462; - else - sc->sc_ah->led_pin = ATH_LED_PIN_DEF; - } - - /* Configure gpio 1 for output */ - ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - /* LED off, active low */ - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); - if (!led_blink) sc->led_cdev.default_trigger = ieee80211_get_radio_led_name(sc->hw); @@ -78,6 +59,31 @@ void ath_init_leds(struct ath_softc *sc) sc->led_registered = true; } + +void ath_fill_led_pin(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + if (AR_SREV_9100(ah) || (ah->led_pin >= 0)) + return; + + if (AR_SREV_9287(ah)) + ah->led_pin = ATH_LED_PIN_9287; + else if (AR_SREV_9485(sc->sc_ah)) + ah->led_pin = ATH_LED_PIN_9485; + else if (AR_SREV_9300(sc->sc_ah)) + ah->led_pin = ATH_LED_PIN_9300; + else if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah)) + ah->led_pin = ATH_LED_PIN_9462; + else + ah->led_pin = ATH_LED_PIN_DEF; + + /* Configure gpio 1 for output */ + ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + + /* LED off, active low */ + ath9k_hw_set_gpio(ah, ah->led_pin, 1); +} #endif /*******************/ diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index f3ce5ca2f1d3..706255222598 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -597,6 +597,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ath9k_cmn_init_crypto(sc->sc_ah); ath9k_init_misc(sc); + ath_fill_led_pin(sc); if (common->bus_ops->aspm_init) common->bus_ops->aspm_init(common); -- cgit v1.2.3 From 7a03414686d8e01c660bf69df22cafcfd2753626 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 12 Sep 2012 18:59:24 +0530 Subject: ath9k: fix queuing MCI work twice Right now MCI work is being queued twice by profile and status updation. Queue MCI work once when it is needed. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/mci.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index fa859e3fbc29..8f51e9e358fd 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -250,8 +250,8 @@ static void ath9k_mci_work(struct work_struct *work) ath_mci_update_scheme(sc); } -static void ath_mci_process_profile(struct ath_softc *sc, - struct ath_mci_profile_info *info) +static u8 ath_mci_process_profile(struct ath_softc *sc, + struct ath_mci_profile_info *info) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_btcoex *btcoex = &sc->btcoex; @@ -277,15 +277,15 @@ static void ath_mci_process_profile(struct ath_softc *sc, if (info->start) { if (!entry && !ath_mci_add_profile(common, mci, info)) - return; + return 0; } else ath_mci_del_profile(common, mci, entry); - ieee80211_queue_work(sc->hw, &sc->mci_work); + return 1; } -static void ath_mci_process_status(struct ath_softc *sc, - struct ath_mci_profile_status *status) +static u8 ath_mci_process_status(struct ath_softc *sc, + struct ath_mci_profile_status *status) { struct ath_btcoex *btcoex = &sc->btcoex; struct ath_mci_profile *mci = &btcoex->mci; @@ -294,14 +294,14 @@ static void ath_mci_process_status(struct ath_softc *sc, /* Link status type are not handled */ if (status->is_link) - return; + return 0; info.conn_handle = status->conn_handle; if (ath_mci_find_profile(mci, &info)) - return; + return 0; if (status->conn_handle >= ATH_MCI_MAX_PROFILE) - return; + return 0; if (status->is_critical) __set_bit(status->conn_handle, mci->status); @@ -315,7 +315,9 @@ static void ath_mci_process_status(struct ath_softc *sc, } while (++i < ATH_MCI_MAX_PROFILE); if (old_num_mgmt != mci->num_mgmt) - ieee80211_queue_work(sc->hw, &sc->mci_work); + return 1; + + return 0; } static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) @@ -324,7 +326,7 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) struct ath_mci_profile_info profile_info; struct ath_mci_profile_status profile_status; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - u8 major, minor; + u8 major, minor, update_scheme = 0; u32 seq_num; if (ar9003_mci_state(ah, MCI_STATE_NEED_FLUSH_BT_INFO) && @@ -359,7 +361,7 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) break; } - ath_mci_process_profile(sc, &profile_info); + update_scheme += ath_mci_process_profile(sc, &profile_info); break; case MCI_GPM_COEX_BT_STATUS_UPDATE: profile_status.is_link = *(rx_payload + @@ -375,12 +377,14 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) profile_status.is_link, profile_status.conn_handle, profile_status.is_critical, seq_num); - ath_mci_process_status(sc, &profile_status); + update_scheme += ath_mci_process_status(sc, &profile_status); break; default: ath_dbg(common, MCI, "Unknown GPM COEX message = 0x%02x\n", opcode); break; } + if (update_scheme) + ieee80211_queue_work(sc->hw, &sc->mci_work); } int ath_mci_setup(struct ath_softc *sc) -- cgit v1.2.3 From e962610f8100e1b52973f5a9c855cbc3d1ba04ec Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 13 Sep 2012 10:33:28 +0800 Subject: wireless: ath9k-htc: fix possible use after free Inside ath9k_hif_usb_firmware_fail(), the instance of 'struct struct hif_device_usb' may be freed by ath9k_hif_usb_disconnect() after complete(&hif_dev->fw_done); But 'hif_dev' is still accessed after the line code above is executed. This patch fixes the issue by not accessing 'hif_dev' after 'complete(&hif_dev->fw_done)' inside ath9k_hif_usb_firmware_fail(). Cc: ath9k-devel@lists.ath9k.org Cc: "Luis R. Rodriguez" Cc: Jouni Malinen Cc: Vasanthakumar Thiagarajan Cc: Senthil Balasubramanian Cc: "John W. Linville" Signed-off-by: Ming Lei Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hif_usb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index ee6e50aebf8d..924c4616c3d9 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -1072,14 +1072,15 @@ static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev) */ static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev) { - struct device *parent = hif_dev->udev->dev.parent; + struct device *dev = &hif_dev->udev->dev; + struct device *parent = dev->parent; complete(&hif_dev->fw_done); if (parent) device_lock(parent); - device_release_driver(&hif_dev->udev->dev); + device_release_driver(dev); if (parent) device_unlock(parent); -- cgit v1.2.3 From 8514fd02baac42c6f6ef248e70c4bdddd5b66433 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 13 Sep 2012 21:11:57 +0200 Subject: brcmfmac: absorb brcmf_sendpkt into brcmf_netdev_start_xmit brcmf_sendpkt only called by brcmf_netdev_start_xmit now. Absorb it to increase readability. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 4 --- .../net/wireless/brcm80211/brcmfmac/dhd_linux.c | 41 +++++++++------------- 2 files changed, 16 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 4766d9f35696..55e489d2147d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -682,10 +682,6 @@ extern int brcmf_c_host_event(struct brcmf_pub *drvr, int *idx, extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx); -/* Send packet to dongle via data channel */ -extern int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx,\ - struct sk_buff *pkt); - extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg); extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, int enable, int master_mode); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index b08f3474d8e7..d7c76ce9d8cb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -272,30 +272,6 @@ static void brcmf_netdev_set_multicast_list(struct net_device *ndev) schedule_work(&drvr->multicast_work); } -int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf) -{ - /* Reject if down */ - if (!drvr->bus_if->drvr_up || (drvr->bus_if->state == BRCMF_BUS_DOWN)) - return -ENODEV; - - /* Update multicast statistic */ - if (pktbuf->len >= ETH_ALEN) { - u8 *pktdata = (u8 *) (pktbuf->data); - struct ethhdr *eh = (struct ethhdr *)pktdata; - - if (is_multicast_ether_addr(eh->h_dest)) - drvr->tx_multicast++; - if (ntohs(eh->h_proto) == ETH_P_PAE) - atomic_inc(&drvr->pend_8021x_cnt); - } - - /* If the protocol uses a data header, apply it */ - brcmf_proto_hdrpush(drvr, ifidx, pktbuf); - - /* Use bus module to send data frame */ - return drvr->bus_if->brcmf_bus_txdata(drvr->dev, pktbuf); -} - static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) { int ret; @@ -338,7 +314,22 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) } } - ret = brcmf_sendpkt(drvr, ifp->idx, skb); + /* Update multicast statistic */ + if (skb->len >= ETH_ALEN) { + u8 *pktdata = (u8 *)(skb->data); + struct ethhdr *eh = (struct ethhdr *)pktdata; + + if (is_multicast_ether_addr(eh->h_dest)) + drvr->tx_multicast++; + if (ntohs(eh->h_proto) == ETH_P_PAE) + atomic_inc(&drvr->pend_8021x_cnt); + } + + /* If the protocol uses a data header, apply it */ + brcmf_proto_hdrpush(drvr, ifp->idx, skb); + + /* Use bus module to send data frame */ + ret = drvr->bus_if->brcmf_bus_txdata(drvr->dev, skb); done: if (ret) -- cgit v1.2.3 From 86761fcbea8a779b0aa2af120173cd4ef7edd72f Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 13 Sep 2012 21:11:58 +0200 Subject: brcmfmac: remove obsolete sdio bus sleep mechanism Remove sdio bus sleep mechanism since it is never invoked. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 93 ---------------------- 1 file changed, 93 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 4580ff34c2d0..2ca9e8c179c7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -549,7 +549,6 @@ struct brcmf_sdio { s32 idleclock; /* How to set bus driver when idle */ s32 sd_rxchain; bool use_rxchain; /* If brcmf should use PKT chains */ - bool sleeping; /* Is SDIO bus sleeping? */ bool rxflow_mode; /* Rx flow control mode */ bool rxflow; /* Is rx flow control on */ bool alp_only; /* Don't use HT clock (ALP only) */ @@ -853,81 +852,6 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok) return 0; } -static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep) -{ - int ret; - - brcmf_dbg(INFO, "request %s (currently %s)\n", - sleep ? "SLEEP" : "WAKE", - bus->sleeping ? "SLEEP" : "WAKE"); - - /* Done if we're already in the requested state */ - if (sleep == bus->sleeping) - return 0; - - /* Going to sleep: set the alarm and turn off the lights... */ - if (sleep) { - /* Don't sleep if something is pending */ - if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) - return -EBUSY; - - /* Make sure the controller has the bus up */ - brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); - - /* Tell device to start using OOB wakeup */ - ret = w_sdreg32(bus, SMB_USE_OOB, - offsetof(struct sdpcmd_regs, tosbmailbox)); - if (ret != 0) - brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"); - - /* Turn off our contribution to the HT clock request */ - brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); - - brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, - SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); - - /* Isolate the bus */ - brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, - SBSDIO_DEVCTL_PADS_ISO, NULL); - - /* Change state */ - bus->sleeping = true; - - } else { - /* Waking up: bus power up is ok, set local state */ - - brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, - 0, NULL); - - /* Make sure the controller has the bus up */ - brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); - - /* Send misc interrupt to indicate OOB not needed */ - ret = w_sdreg32(bus, 0, - offsetof(struct sdpcmd_regs, tosbmailboxdata)); - if (ret == 0) - ret = w_sdreg32(bus, SMB_DEV_INT, - offsetof(struct sdpcmd_regs, tosbmailbox)); - - if (ret != 0) - brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"); - - /* Make sure we have SD bus access */ - brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); - - /* Change state */ - bus->sleeping = false; - } - - return 0; -} - -static void bus_wake(struct brcmf_sdio *bus) -{ - if (bus->sleeping) - brcmf_sdbrcm_bussleep(bus, false); -} - static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus) { u32 intstatus = 0; @@ -2267,8 +2191,6 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev) down(&bus->sdsem); - bus_wake(bus); - /* Enable clock for device interrupts */ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); @@ -2404,8 +2326,6 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) } } - bus_wake(bus); - /* Make sure backplane clock is on */ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true); if (bus->clkstate == CLK_PENDING) @@ -2918,8 +2838,6 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) /* Need to lock here to protect txseq and SDIO tx calls */ down(&bus->sdsem); - bus_wake(bus); - /* Make sure backplane clock is on */ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); @@ -3776,12 +3694,6 @@ void brcmf_sdbrcm_isr(void *arg) bus->sdcnt.intrcount++; bus->ipend = true; - /* Shouldn't get this interrupt if we're sleeping? */ - if (bus->sleeping) { - brcmf_dbg(ERROR, "INTERRUPT WHILE SLEEPING??\n"); - return; - } - /* Disable additional interrupts (is this needed now)? */ if (!bus->intr) brcmf_dbg(ERROR, "isr w/o interrupt configured!\n"); @@ -3801,10 +3713,6 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) brcmf_dbg(TIMER, "Enter\n"); - /* Ignore the timer if simulating bus down */ - if (bus->sleeping) - return false; - down(&bus->sdsem); /* Poll period: check device if appropriate. */ @@ -4024,7 +3932,6 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus) SDIO_FUNC_ENABLE_1, NULL); bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; - bus->sleeping = false; bus->rxflow = false; /* Done with backplane-dependent accesses, can drop clock... */ -- cgit v1.2.3 From 1d38227371d8db7d58b4f870192dd944f73f4352 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 13 Sep 2012 21:11:59 +0200 Subject: brcmfmac: use atomic variable for interrupt pending flag Interrupt pending flag used in SDIO bus layer could be used in multiple processes in different context. Use atomic_t make sure every interrupt is handled. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 2ca9e8c179c7..b0794e856a0a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -531,7 +531,7 @@ struct brcmf_sdio { bool intr; /* Use interrupts */ bool poll; /* Use polling */ - bool ipend; /* Device interrupt is pending */ + atomic_t ipend; /* Device interrupt is pending */ uint spurious; /* Count of spurious interrupts */ uint pollrate; /* Ticks between device polls */ uint polltick; /* Tick counter */ @@ -2151,7 +2151,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) if (ret != 0) break; if (intstatus & bus->hostintmask) - bus->ipend = true; + atomic_set(&bus->ipend, 1); } } @@ -2249,7 +2249,7 @@ static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus) unsigned long flags; spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags); - if (!bus->sdiodev->irq_en && !bus->ipend) { + if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) { enable_irq(bus->sdiodev->irq); bus->sdiodev->irq_en = true; } @@ -2332,8 +2332,8 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) goto clkwait; /* Pending interrupt indicates new device status */ - if (bus->ipend) { - bus->ipend = false; + if (atomic_read(&bus->ipend) > 0) { + atomic_set(&bus->ipend, 0); err = r_sdreg32(bus, &newstatus, offsetof(struct sdpcmd_regs, intstatus)); bus->sdcnt.f1regdata++; @@ -2478,7 +2478,7 @@ clkwait: } else if (bus->clkstate == CLK_PENDING) { brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n"); resched = true; - } else if (bus->intstatus || bus->ipend || + } else if (bus->intstatus || atomic_read(&bus->ipend) > 0 || (!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && data_ok(bus)) || PKT_AVAILABLE()) { resched = true; @@ -3692,7 +3692,7 @@ void brcmf_sdbrcm_isr(void *arg) } /* Count the interrupt call */ bus->sdcnt.intrcount++; - bus->ipend = true; + atomic_set(&bus->ipend, 1); /* Disable additional interrupts (is this needed now)? */ if (!bus->intr) @@ -3740,7 +3740,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) schedule the DPC */ if (intstatus) { bus->sdcnt.pollcnt++; - bus->ipend = true; + atomic_set(&bus->ipend, 1); bus->dpc_sched = true; if (bus->dpc_tsk) { @@ -3784,7 +3784,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) up(&bus->sdsem); - return bus->ipend; + return (atomic_read(&bus->ipend) > 0); } static bool brcmf_sdbrcm_chipmatch(u16 chipid) -- cgit v1.2.3 From f1e68c2e0a7af39907355e300dbbc76fcebc7fc8 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 13 Sep 2012 21:12:00 +0200 Subject: brcmfmac: convert SDIO dpc implementation to workqueue Switch SDIO dpc implementation from kernel thread to workqueue for better performance and compatibility. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 185 +++++++++------------ 1 file changed, 83 insertions(+), 102 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index b0794e856a0a..1d80e055b5f8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -495,7 +495,6 @@ struct brcmf_sdio { u32 hostintmask; /* Copy of Host Interrupt Mask */ u32 intstatus; /* Intstatus bits (events) pending */ - bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ bool fcstate; /* State of dongle flow-control */ uint blocksize; /* Block size of SDIO transfers */ @@ -569,8 +568,8 @@ struct brcmf_sdio { bool wd_timer_valid; uint save_ms; - struct task_struct *dpc_tsk; - struct completion dpc_wait; + struct workqueue_struct *brcmf_wq; + struct work_struct datawork; struct list_head dpc_tsklst; spinlock_t dpc_tl_lock; @@ -2183,12 +2182,6 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev) bus->watchdog_tsk = NULL; } - if (bus->dpc_tsk && bus->dpc_tsk != current) { - send_sig(SIGTERM, bus->dpc_tsk, 1); - kthread_stop(bus->dpc_tsk); - bus->dpc_tsk = NULL; - } - down(&bus->sdsem); /* Enable clock for device interrupts */ @@ -2261,15 +2254,31 @@ static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus) } #endif /* CONFIG_BRCMFMAC_SDIO_OOB */ -static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) +static inline void brcmf_sdbrcm_adddpctsk(struct brcmf_sdio *bus) +{ + struct list_head *new_hd; + unsigned long flags; + + if (in_interrupt()) + new_hd = kzalloc(sizeof(struct list_head), GFP_ATOMIC); + else + new_hd = kzalloc(sizeof(struct list_head), GFP_KERNEL); + if (new_hd == NULL) + return; + + spin_lock_irqsave(&bus->dpc_tl_lock, flags); + list_add_tail(new_hd, &bus->dpc_tsklst); + spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); +} + +static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) { u32 intstatus, newstatus = 0; uint rxlimit = bus->rxbound; /* Rx frames to read before resched */ uint txlimit = bus->txbound; /* Tx frames to send before resched */ uint framecnt = 0; /* Temporary counter of tx/rx frames */ bool rxdone = true; /* Flag for no more read data */ - bool resched = false; /* Flag indicating resched wanted */ - int err; + int err = 0; brcmf_dbg(TRACE, "Enter\n"); @@ -2454,7 +2463,6 @@ clkwait: if (ret == 0) bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - brcmf_dbg(INFO, "Return_dpc value is : %d\n", ret); bus->ctrl_frame_stat = false; brcmf_sdbrcm_wait_event_wakeup(bus); } @@ -2477,15 +2485,13 @@ clkwait: bus->intstatus = 0; } else if (bus->clkstate == CLK_PENDING) { brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n"); - resched = true; + brcmf_sdbrcm_adddpctsk(bus); } else if (bus->intstatus || atomic_read(&bus->ipend) > 0 || (!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && data_ok(bus)) || PKT_AVAILABLE()) { - resched = true; + brcmf_sdbrcm_adddpctsk(bus); } - bus->dpc_sched = resched; - /* If we're done for now, turn off clock request. */ if ((bus->clkstate != CLK_PENDING) && bus->idletime == BRCMF_IDLE_IMMEDIATE) { @@ -2494,65 +2500,6 @@ clkwait: } up(&bus->sdsem); - - return resched; -} - -static inline void brcmf_sdbrcm_adddpctsk(struct brcmf_sdio *bus) -{ - struct list_head *new_hd; - unsigned long flags; - - if (in_interrupt()) - new_hd = kzalloc(sizeof(struct list_head), GFP_ATOMIC); - else - new_hd = kzalloc(sizeof(struct list_head), GFP_KERNEL); - if (new_hd == NULL) - return; - - spin_lock_irqsave(&bus->dpc_tl_lock, flags); - list_add_tail(new_hd, &bus->dpc_tsklst); - spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); -} - -static int brcmf_sdbrcm_dpc_thread(void *data) -{ - struct brcmf_sdio *bus = (struct brcmf_sdio *) data; - struct list_head *cur_hd, *tmp_hd; - unsigned long flags; - - allow_signal(SIGTERM); - /* Run until signal received */ - while (1) { - if (kthread_should_stop()) - break; - - if (list_empty(&bus->dpc_tsklst)) - if (wait_for_completion_interruptible(&bus->dpc_wait)) - break; - - spin_lock_irqsave(&bus->dpc_tl_lock, flags); - list_for_each_safe(cur_hd, tmp_hd, &bus->dpc_tsklst) { - spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); - - if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) { - /* after stopping the bus, exit thread */ - brcmf_sdbrcm_bus_stop(bus->sdiodev->dev); - bus->dpc_tsk = NULL; - spin_lock_irqsave(&bus->dpc_tl_lock, flags); - break; - } - - if (brcmf_sdbrcm_dpc(bus)) - brcmf_sdbrcm_adddpctsk(bus); - - spin_lock_irqsave(&bus->dpc_tl_lock, flags); - list_del(cur_hd); - kfree(cur_hd); - } - spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); - } - return 0; } static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) @@ -2562,6 +2509,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; + unsigned long flags; brcmf_dbg(TRACE, "Enter\n"); @@ -2600,13 +2548,15 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) if (pktq_plen(&bus->txq, prec) > qcount[prec]) qcount[prec] = pktq_plen(&bus->txq, prec); #endif - /* Schedule DPC if needed to send queued packet(s) */ - if (!bus->dpc_sched) { - bus->dpc_sched = true; - if (bus->dpc_tsk) { - brcmf_sdbrcm_adddpctsk(bus); - complete(&bus->dpc_wait); - } + + spin_lock_irqsave(&bus->dpc_tl_lock, flags); + if (list_empty(&bus->dpc_tsklst)) { + spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); + + brcmf_sdbrcm_adddpctsk(bus); + queue_work(bus->brcmf_wq, &bus->datawork); + } else { + spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); } return ret; @@ -2802,6 +2752,7 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; + unsigned long flags; brcmf_dbg(TRACE, "Enter\n"); @@ -2885,9 +2836,15 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) } while (ret < 0 && retries++ < TXRETRIES); } - if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) { + spin_lock_irqsave(&bus->dpc_tl_lock, flags); + if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && + list_empty(&bus->dpc_tsklst)) { + spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); + bus->activity = false; brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); + } else { + spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); } up(&bus->sdsem); @@ -3698,11 +3655,8 @@ void brcmf_sdbrcm_isr(void *arg) if (!bus->intr) brcmf_dbg(ERROR, "isr w/o interrupt configured!\n"); - bus->dpc_sched = true; - if (bus->dpc_tsk) { - brcmf_sdbrcm_adddpctsk(bus); - complete(&bus->dpc_wait); - } + brcmf_sdbrcm_adddpctsk(bus); + queue_work(bus->brcmf_wq, &bus->datawork); } static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) @@ -3710,6 +3664,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) #ifdef DEBUG struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev); #endif /* DEBUG */ + unsigned long flags; brcmf_dbg(TIMER, "Enter\n"); @@ -3726,14 +3681,20 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) if (!bus->intr || (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) { - if (!bus->dpc_sched) { + spin_lock_irqsave(&bus->dpc_tl_lock, flags); + if (list_empty(&bus->dpc_tsklst)) { u8 devpend; + spin_unlock_irqrestore(&bus->dpc_tl_lock, + flags); devpend = brcmf_sdio_regrb(bus->sdiodev, SDIO_CCCR_INTx, NULL); intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2); + } else { + spin_unlock_irqrestore(&bus->dpc_tl_lock, + flags); } /* If there is something, make like the ISR and @@ -3742,11 +3703,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) bus->sdcnt.pollcnt++; atomic_set(&bus->ipend, 1); - bus->dpc_sched = true; - if (bus->dpc_tsk) { - brcmf_sdbrcm_adddpctsk(bus); - complete(&bus->dpc_wait); - } + brcmf_sdbrcm_adddpctsk(bus); + queue_work(bus->brcmf_wq, &bus->datawork); } } @@ -3800,6 +3758,26 @@ static bool brcmf_sdbrcm_chipmatch(u16 chipid) return false; } +static void brcmf_sdio_dataworker(struct work_struct *work) +{ + struct brcmf_sdio *bus = container_of(work, struct brcmf_sdio, + datawork); + struct list_head *cur_hd, *tmp_hd; + unsigned long flags; + + spin_lock_irqsave(&bus->dpc_tl_lock, flags); + list_for_each_safe(cur_hd, tmp_hd, &bus->dpc_tsklst) { + spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); + + brcmf_sdbrcm_dpc(bus); + + spin_lock_irqsave(&bus->dpc_tl_lock, flags); + list_del(cur_hd); + kfree(cur_hd); + } + spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); +} + static void brcmf_sdbrcm_release_malloc(struct brcmf_sdio *bus) { brcmf_dbg(TRACE, "Enter\n"); @@ -4012,6 +3990,9 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus) /* De-register interrupt handler */ brcmf_sdio_intr_unregister(bus->sdiodev); + cancel_work_sync(&bus->datawork); + destroy_workqueue(bus->brcmf_wq); + if (bus->sdiodev->bus_if->drvr) { brcmf_detach(bus->sdiodev->dev); brcmf_sdbrcm_release_dongle(bus); @@ -4064,6 +4045,13 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) init_waitqueue_head(&bus->ctrl_wait); init_waitqueue_head(&bus->dcmd_resp_wait); + bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq"); + if (bus->brcmf_wq == NULL) { + brcmf_dbg(ERROR, "insufficient memory to create txworkqueue\n"); + goto fail; + } + INIT_WORK(&bus->datawork, brcmf_sdio_dataworker); + /* Set up the watchdog timer */ init_timer(&bus->timer); bus->timer.data = (unsigned long)bus; @@ -4081,15 +4069,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) bus->watchdog_tsk = NULL; } /* Initialize DPC thread */ - init_completion(&bus->dpc_wait); INIT_LIST_HEAD(&bus->dpc_tsklst); spin_lock_init(&bus->dpc_tl_lock); - bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread, - bus, "brcmf_dpc"); - if (IS_ERR(bus->dpc_tsk)) { - pr_warn("brcmf_dpc thread failed to start\n"); - bus->dpc_tsk = NULL; - } /* Assign bus interface call back */ bus->sdiodev->bus_if->brcmf_bus_stop = brcmf_sdbrcm_bus_stop; -- cgit v1.2.3 From 03d5c360dcbcb62cfc45caaca163cce8e10f00d6 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 13 Sep 2012 21:12:01 +0200 Subject: brcmfmac: streamline SDIO dpc Streamline SDIO dpc by removing some unnecessary code path. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 27 ++++++---------------- 1 file changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 1d80e055b5f8..90a3849b41fe 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2330,15 +2330,11 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; } bus->clkstate = CLK_AVAIL; - } else { - goto clkwait; } } /* Make sure backplane clock is on */ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true); - if (bus->clkstate == CLK_PENDING) - goto clkwait; /* Pending interrupt indicates new device status */ if (atomic_read(&bus->ipend) > 0) { @@ -2412,7 +2408,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) intstatus &= ~I_HMB_FRAME_IND; /* On frame indication, read available frames */ - if (PKT_AVAILABLE()) { + if (PKT_AVAILABLE() && bus->clkstate == CLK_AVAIL) { framecnt = brcmf_sdbrcm_readframes(bus, rxlimit, &rxdone); if (rxdone || bus->rxskip) intstatus &= ~I_HMB_FRAME_IND; @@ -2422,22 +2418,21 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) /* Keep still-pending events for next scheduling */ bus->intstatus = intstatus; -clkwait: brcmf_sdbrcm_clrintr(bus); if (data_ok(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { - int ret, i; + int i; - ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad, + err = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, bus->ctrl_frame_buf, (u32) bus->ctrl_frame_len); - if (ret < 0) { + if (err < 0) { /* On failure, abort the command and terminate the frame */ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", - ret); + err); bus->sdcnt.tx_sderrs++; brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); @@ -2459,10 +2454,9 @@ clkwait: break; } - } - if (ret == 0) + } else { bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - + } bus->ctrl_frame_stat = false; brcmf_sdbrcm_wait_event_wakeup(bus); } @@ -2475,17 +2469,10 @@ clkwait: txlimit -= framecnt; } - /* Resched if events or tx frames are pending, - else await next interrupt */ - /* On failed register access, all bets are off: - no resched or interrupts */ if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || (err != 0)) { brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation\n"); bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; bus->intstatus = 0; - } else if (bus->clkstate == CLK_PENDING) { - brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n"); - brcmf_sdbrcm_adddpctsk(bus); } else if (bus->intstatus || atomic_read(&bus->ipend) > 0 || (!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && data_ok(bus)) || PKT_AVAILABLE()) { -- cgit v1.2.3 From 7057fd00da45c31a5a927a742d0f43efe4470173 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 13 Sep 2012 21:12:02 +0200 Subject: brcmfmac: raise SDIO host lock to higher level Use SDIO host lock to protect the entire communication process of register access or data read/write rather than function calls to MMC/SDIO stack only. This can help to avoid unintentional memory access and unexpected interruption. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 37 +++++++++++++++++++--- .../net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 25 --------------- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 4 +++ 3 files changed, 36 insertions(+), 30 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 8e7e6928c936..0c1d08ae726b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -249,7 +249,9 @@ u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret) int retval; brcmf_dbg(INFO, "addr:0x%08x\n", addr); + sdio_claim_host(sdiodev->func[1]); retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); + sdio_release_host(sdiodev->func[1]); brcmf_dbg(INFO, "data:0x%02x\n", data); if (ret) @@ -264,7 +266,9 @@ u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret) int retval; brcmf_dbg(INFO, "addr:0x%08x\n", addr); + sdio_claim_host(sdiodev->func[1]); retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); + sdio_release_host(sdiodev->func[1]); brcmf_dbg(INFO, "data:0x%08x\n", data); if (ret) @@ -279,7 +283,9 @@ void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, int retval; brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data); + sdio_claim_host(sdiodev->func[1]); retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); + sdio_release_host(sdiodev->func[1]); if (ret) *ret = retval; @@ -291,7 +297,9 @@ void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, int retval; brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data); + sdio_claim_host(sdiodev->func[1]); retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); + sdio_release_host(sdiodev->func[1]); if (ret) *ret = retval; @@ -356,15 +364,20 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, pkt->len); + sdio_claim_host(sdiodev->func[1]); + width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr); if (err) - return err; + goto done; incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ, fn, addr, pkt); +done: + sdio_release_host(sdiodev->func[1]); + return err; } @@ -378,15 +391,20 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, pktq->qlen); + sdio_claim_host(sdiodev->func[1]); + width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr); if (err) - return err; + goto done; incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr, pktq); +done: + sdio_release_host(sdiodev->func[1]); + return err; } @@ -428,10 +446,12 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, if (flags & SDIO_REQ_ASYNC) return -ENOTSUPP; + sdio_claim_host(sdiodev->func[1]); + if (bar0 != sdiodev->sbwad) { err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); if (err) - return err; + goto done; sdiodev->sbwad = bar0; } @@ -443,8 +463,13 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, if (width == 4) addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn, - addr, pkt); + err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn, + addr, pkt); + +done: + sdio_release_host(sdiodev->func[1]); + + return err; } int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr, @@ -485,8 +510,10 @@ int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn) brcmf_dbg(TRACE, "Enter\n"); /* issue abort cmd52 command through F0 */ + sdio_claim_host(sdiodev->func[1]); brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0, SDIO_CCCR_ABORT, &t_func); + sdio_release_host(sdiodev->func[1]); brcmf_dbg(TRACE, "Exit\n"); return 0; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index e0b313c7f5ce..70f21a435532 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -103,7 +103,6 @@ static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev, if (regaddr == SDIO_CCCR_IOEx) { sdfunc = sdiodev->func[2]; if (sdfunc) { - sdio_claim_host(sdfunc); if (*byte & SDIO_FUNC_ENABLE_2) { /* Enable Function 2 */ err_ret = sdio_enable_func(sdfunc); @@ -119,7 +118,6 @@ static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev, "Disable F2 failed:%d\n", err_ret); } - sdio_release_host(sdfunc); } } else if ((regaddr == SDIO_CCCR_ABORT) || (regaddr == SDIO_CCCR_IENx)) { @@ -128,17 +126,13 @@ static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev, if (!sdfunc) return -ENOMEM; sdfunc->num = 0; - sdio_claim_host(sdfunc); sdio_writeb(sdfunc, *byte, regaddr, &err_ret); - sdio_release_host(sdfunc); kfree(sdfunc); } else if (regaddr < 0xF0) { brcmf_dbg(ERROR, "F0 Wr:0x%02x: write disallowed\n", regaddr); err_ret = -EPERM; } else { - sdio_claim_host(sdfunc); sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret); - sdio_release_host(sdfunc); } return err_ret; @@ -159,7 +153,6 @@ int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func, /* handle F0 separately */ err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte); } else { - sdio_claim_host(sdiodev->func[func]); if (rw) /* CMD52 Write */ sdio_writeb(sdiodev->func[func], *byte, regaddr, &err_ret); @@ -170,7 +163,6 @@ int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func, *byte = sdio_readb(sdiodev->func[func], regaddr, &err_ret); } - sdio_release_host(sdiodev->func[func]); } if (err_ret) @@ -197,8 +189,6 @@ int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); if (brcmf_pm_resume_error(sdiodev)) return -EIO; - /* Claim host controller */ - sdio_claim_host(sdiodev->func[func]); if (rw) { /* CMD52 Write */ if (nbytes == 4) @@ -219,9 +209,6 @@ int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes); } - /* Release host controller */ - sdio_release_host(sdiodev->func[func]); - if (err_ret) brcmf_dbg(ERROR, "Failed to %s word, Err: 0x%08x\n", rw ? "write" : "read", err_ret); @@ -275,9 +262,6 @@ brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc, if (brcmf_pm_resume_error(sdiodev)) return -EIO; - /* Claim host controller */ - sdio_claim_host(sdiodev->func[func]); - skb_queue_walk(pktq, pkt) { uint pkt_len = pkt->len; pkt_len += 3; @@ -300,9 +284,6 @@ brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc, SGCount++; } - /* Release host controller */ - sdio_release_host(sdiodev->func[func]); - brcmf_dbg(TRACE, "Exit\n"); return err_ret; } @@ -328,9 +309,6 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, if (brcmf_pm_resume_error(sdiodev)) return -EIO; - /* Claim host controller */ - sdio_claim_host(sdiodev->func[func]); - pkt_len += 3; pkt_len &= (uint)~3; @@ -344,9 +322,6 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, write ? "TX" : "RX", pkt, addr, pkt_len); } - /* Release host controller */ - sdio_release_host(sdiodev->func[func]); - return status; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 90a3849b41fe..619f3cdcb8e2 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2564,6 +2564,8 @@ brcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data, else dsize = size; + sdio_claim_host(bus->sdiodev->func[1]); + /* Set the backplane window to include the start address */ bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address); if (bcmerror) { @@ -2605,6 +2607,8 @@ xfer_done: brcmf_dbg(ERROR, "FAILED to set window back to 0x%x\n", bus->sdiodev->sbwad); + sdio_release_host(bus->sdiodev->func[1]); + return bcmerror; } -- cgit v1.2.3 From 4531603a7acb1463ec0b466dcfedc6682e7a1718 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 13 Sep 2012 21:12:03 +0200 Subject: brcmfmac: clear status for in-band interrupt in brcmf_sdbrcm_isr SDIO in-band interrupt is level sensitive according to SDIO standard. When the register interrupt handler gets called by SDIO stack it is running in non interrupt context and expected to clear the interrupt from the dongle. Therefore in-band and out-of-band interrupt need to be handled differently. Cc: Wei Ni Cc: Stephen Warren Reported-by: Wei Ni Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Tested-by: Stephen Warren Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 2 +- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 97 +++++++++++++++------- .../net/wireless/brcm80211/brcmfmac/sdio_host.h | 2 + 3 files changed, 68 insertions(+), 33 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 0c1d08ae726b..3b2c4c20e7fc 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -185,7 +185,7 @@ brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address) return err; } -static int +int brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, void *data, bool write) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 619f3cdcb8e2..ff7e8297830c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -494,8 +494,8 @@ struct brcmf_sdio { u32 ramsize; /* Size of RAM in SOCRAM (bytes) */ u32 hostintmask; /* Copy of Host Interrupt Mask */ - u32 intstatus; /* Intstatus bits (events) pending */ - bool fcstate; /* State of dongle flow-control */ + atomic_t intstatus; /* Intstatus bits (events) pending */ + atomic_t fcstate; /* State of dongle flow-control */ uint blocksize; /* Block size of SDIO transfers */ uint roundup; /* Max roundup limit */ @@ -2271,20 +2271,53 @@ static inline void brcmf_sdbrcm_adddpctsk(struct brcmf_sdio *bus) spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); } +static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) +{ + u8 idx; + u32 addr; + unsigned long val; + int n, ret; + + idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); + addr = bus->ci->c_inf[idx].base + + offsetof(struct sdpcmd_regs, intstatus); + + ret = brcmf_sdio_regrw_helper(bus->sdiodev, addr, &val, false); + bus->sdcnt.f1regdata++; + if (ret != 0) + val = 0; + + val &= bus->hostintmask; + atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE)); + + /* Clear interrupts */ + if (val) { + ret = brcmf_sdio_regrw_helper(bus->sdiodev, addr, &val, true); + bus->sdcnt.f1regdata++; + } + + if (ret) { + atomic_set(&bus->intstatus, 0); + } else if (val) { + for_each_set_bit(n, &val, 32) + set_bit(n, (unsigned long *)&bus->intstatus.counter); + } + + return ret; +} + static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) { - u32 intstatus, newstatus = 0; + u32 newstatus = 0; + unsigned long intstatus; uint rxlimit = bus->rxbound; /* Rx frames to read before resched */ uint txlimit = bus->txbound; /* Tx frames to send before resched */ uint framecnt = 0; /* Temporary counter of tx/rx frames */ bool rxdone = true; /* Flag for no more read data */ - int err = 0; + int err = 0, n; brcmf_dbg(TRACE, "Enter\n"); - /* Start with leftover status bits */ - intstatus = bus->intstatus; - down(&bus->sdsem); /* If waiting for HTAVAIL, check status */ @@ -2339,24 +2372,13 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) /* Pending interrupt indicates new device status */ if (atomic_read(&bus->ipend) > 0) { atomic_set(&bus->ipend, 0); - err = r_sdreg32(bus, &newstatus, - offsetof(struct sdpcmd_regs, intstatus)); - bus->sdcnt.f1regdata++; - if (err != 0) - newstatus = 0; - newstatus &= bus->hostintmask; - bus->fcstate = !!(newstatus & I_HMB_FC_STATE); - if (newstatus) { - err = w_sdreg32(bus, newstatus, - offsetof(struct sdpcmd_regs, - intstatus)); - bus->sdcnt.f1regdata++; - } + sdio_claim_host(bus->sdiodev->func[1]); + err = brcmf_sdio_intr_rstatus(bus); + sdio_release_host(bus->sdiodev->func[1]); } - /* Merge new bits with previous */ - intstatus |= newstatus; - bus->intstatus = 0; + /* Start with leftover status bits */ + intstatus = atomic_xchg(&bus->intstatus, 0); /* Handle flow-control change: read new state in case our ack * crossed another change interrupt. If change still set, assume @@ -2370,8 +2392,8 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) err = r_sdreg32(bus, &newstatus, offsetof(struct sdpcmd_regs, intstatus)); bus->sdcnt.f1regdata += 2; - bus->fcstate = - !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); + atomic_set(&bus->fcstate, + !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE))); intstatus |= (newstatus & bus->hostintmask); } @@ -2416,7 +2438,10 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) } /* Keep still-pending events for next scheduling */ - bus->intstatus = intstatus; + if (intstatus) { + for_each_set_bit(n, &intstatus, 32) + set_bit(n, (unsigned long *)&bus->intstatus.counter); + } brcmf_sdbrcm_clrintr(bus); @@ -2461,7 +2486,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) brcmf_sdbrcm_wait_event_wakeup(bus); } /* Send queued frames (limit 1 if rx may still be pending) */ - else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && + else if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && data_ok(bus)) { framecnt = rxdone ? txlimit : min(txlimit, bus->txminmax); @@ -2472,10 +2497,12 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || (err != 0)) { brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation\n"); bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; - bus->intstatus = 0; - } else if (bus->intstatus || atomic_read(&bus->ipend) > 0 || - (!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) - && data_ok(bus)) || PKT_AVAILABLE()) { + atomic_set(&bus->intstatus, 0); + } else if (atomic_read(&bus->intstatus) || + atomic_read(&bus->ipend) > 0 || + (!atomic_read(&bus->fcstate) && + brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && + data_ok(bus)) || PKT_AVAILABLE()) { brcmf_sdbrcm_adddpctsk(bus); } @@ -3640,7 +3667,13 @@ void brcmf_sdbrcm_isr(void *arg) } /* Count the interrupt call */ bus->sdcnt.intrcount++; - atomic_set(&bus->ipend, 1); + if (in_interrupt()) + atomic_set(&bus->ipend, 1); + else + if (brcmf_sdio_intr_rstatus(bus)) { + brcmf_dbg(ERROR, "failed backplane access\n"); + bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; + } /* Disable additional interrupts (is this needed now)? */ if (!bus->intr) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h index 29bf78d264e0..0d30afd8c672 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h @@ -174,6 +174,8 @@ extern void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, u8 data, int *ret); extern void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, u32 data, int *ret); +extern int brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, + void *data, bool write); /* Buffer transfer to/from device (client) core via cmd53. * fn: function number -- cgit v1.2.3 From 9cd23a7191f1abc32252ba92494a910d5cc5fd02 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Thu, 13 Sep 2012 21:12:04 +0200 Subject: brcmfmac: fix bug causing errorneous free on exception. This patch fixes bug where driver frees resources twice when an exception occurs. Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/usb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index c6d5aeb27a02..03f59cd0572a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -1340,10 +1340,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo, struct device *dev = devinfo->dev; bus_pub = brcmf_usb_attach(devinfo, BRCMF_USB_NRXQ, BRCMF_USB_NTXQ); - if (!bus_pub) { - ret = -ENODEV; - goto fail; - } + if (!bus_pub) + return -ENODEV; bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC); if (!bus) { -- cgit v1.2.3 From 4f6e1cafe25df11f4c8afe5d6a3ee051aa6d5de3 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 13 Sep 2012 21:12:05 +0200 Subject: brcmfmac: add parameter check in brcmf_c_mkiovar() This patch assures data is only appended in output buffer when data is not NULL and datalen is not zero. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index f6b862d77986..c45270a2a1d9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -80,8 +80,10 @@ brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) strncpy(buf, name, buflen); /* append data onto the end of the name string */ - memcpy(&buf[len], data, datalen); - len += datalen; + if (data && datalen) { + memcpy(&buf[len], data, datalen); + len += datalen; + } return len; } -- cgit v1.2.3 From 97ed15c7ebfb95f0d23b023fffd23608205f7946 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 13 Sep 2012 21:12:06 +0200 Subject: brcmfmac: simplify handling e-scan result firmware event Upon handling an e-scan result event from the firmware in brcmf_cfg80211_escan_handler() the status may indicate e-scan is completed or aborted. If so brcmf_notify_escan_complete() is called. However, that function and brcmf_cfg80211_escan_handler() both log the same debug message and both enable MPC flag in the firmware. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 65cf8f92cb3e..3491086053cd 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -2871,6 +2871,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_priv *cfg_priv, u32 bi_length; struct brcmf_scan_results *list; u32 i; + bool aborted; status = be32_to_cpu(e->status); @@ -2943,16 +2944,9 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_priv *cfg_priv, cfg_priv->bss_list = (struct brcmf_scan_results *) cfg_priv->escan_info.escan_buf; brcmf_inform_bss(cfg_priv); - if (status == BRCMF_E_STATUS_SUCCESS) { - WL_SCAN("ESCAN Completed\n"); - brcmf_notify_escan_complete(cfg_priv, ndev, - false, false); - } else { - WL_ERR("ESCAN Aborted, Event 0x%x\n", status); - brcmf_notify_escan_complete(cfg_priv, ndev, - true, false); - } - brcmf_set_mpc(ndev, 1); + aborted = status != BRCMF_E_STATUS_SUCCESS; + brcmf_notify_escan_complete(cfg_priv, ndev, aborted, + false); } else WL_ERR("Unexpected scan result 0x%x\n", status); } -- cgit v1.2.3 From 5418b0f0ad389989037d5ed700bcd8b67dbdf018 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 14 Sep 2012 18:43:58 +0530 Subject: ath9k: update hw_timer_enabled to false when we stop generic timers Update the 'hw_timer_enabled' to 'false' wherever we are stopping hardware generic timers, excecpt the case where we start them again immediately. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/gpio.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 1934cca8a6cc..bf7d29ec1a87 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -320,8 +320,10 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc) ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n"); /* make sure duty cycle timer is also stopped when resuming */ - if (btcoex->hw_timer_enabled) + if (btcoex->hw_timer_enabled) { ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); + btcoex->hw_timer_enabled = false; + } btcoex->bt_priority_cnt = 0; btcoex->bt_priority_time = jiffies; @@ -342,18 +344,20 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc) del_timer_sync(&btcoex->period_timer); - if (btcoex->hw_timer_enabled) + if (btcoex->hw_timer_enabled) { ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); - - btcoex->hw_timer_enabled = false; + btcoex->hw_timer_enabled = false; + } } void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; - if (btcoex->hw_timer_enabled) + if (btcoex->hw_timer_enabled) { ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); + btcoex->hw_timer_enabled = false; + } } u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) -- cgit v1.2.3 From 915154b62bfe09102498b12e323b77dc762e5bec Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 16 Sep 2012 08:05:23 +0530 Subject: ath9k_hw: Use HW cap ATH9K_HW_CAP_ANT_DIV_COMB Instead of trying to determine whether antenna diversity is enabled by parsing eeprom data, use ATH9K_HW_CAP_ANT_DIV_COMB which is already filled at init time. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index b5659cb688fe..8d434df26818 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3562,9 +3562,9 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, int chain, static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) { + struct ath9k_hw_capabilities *pCap = &ah->caps; int chain; u32 regval; - u32 ant_div_ctl1; static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = { AR_PHY_SWITCH_CHAIN_0, AR_PHY_SWITCH_CHAIN_1, @@ -3636,9 +3636,8 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) regval &= (~AR_FAST_DIV_ENABLE); regval |= ((value >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); - ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); - /* check whether antenna diversity is enabled */ - if ((ant_div_ctl1 >> 0x6) == 0x3) { + + if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); /* * clear bits 25-30 main_lnaconf, alt_lnaconf, @@ -3655,10 +3654,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) AR_PHY_ANT_DIV_ALT_LNACONF_S); REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); } - - } - } static void ar9003_hw_drive_strength_apply(struct ath_hw *ah) -- cgit v1.2.3 From d85ed4196ebb065906eacfdc4b1cec824a3799dd Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 16 Sep 2012 08:05:40 +0530 Subject: ath9k: Remove redundant variable assignment Set main_gaintb and alt_gaintb once instead of zero'ing them in every case. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 51 ++------------------------------ 1 file changed, 3 insertions(+), 48 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index bbcfeb3b2a60..eb61c6bc480e 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -311,6 +311,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, struct ath_ant_comb *antcomb, int alt_ratio) { + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + if (ant_conf->div_group == 0) { /* Adjust the fast_div_bias based on main and alt lna conf */ switch ((ant_conf->main_lna_conf << 4) | @@ -360,18 +363,12 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->alt_lna_conf) { case 0x01: /* A-B LNA2 */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x02: /* A-B LNA1 */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x03: /* A-B A+B */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x10: /* LNA2 A-B */ if (!(antcomb->scan) && @@ -379,13 +376,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x3f; else ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x12: /* LNA2 LNA1 */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x13: /* LNA2 A+B */ if (!(antcomb->scan) && @@ -393,8 +386,6 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x3f; else ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x20: /* LNA1 A-B */ if (!(antcomb->scan) && @@ -402,13 +393,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x3f; else ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x21: /* LNA1 LNA2 */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x23: /* LNA1 A+B */ if (!(antcomb->scan) && @@ -416,23 +403,15 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x3f; else ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x30: /* A+B A-B */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x31: /* A+B LNA2 */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x32: /* A+B LNA1 */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; default: break; @@ -443,18 +422,12 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->alt_lna_conf) { case 0x01: /* A-B LNA2 */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x02: /* A-B LNA1 */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x03: /* A-B A+B */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x10: /* LNA2 A-B */ if (!(antcomb->scan) && @@ -462,13 +435,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x1; else ant_conf->fast_div_bias = 0x2; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x12: /* LNA2 LNA1 */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x13: /* LNA2 A+B */ if (!(antcomb->scan) && @@ -476,8 +445,6 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x1; else ant_conf->fast_div_bias = 0x2; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x20: /* LNA1 A-B */ if (!(antcomb->scan) && @@ -485,13 +452,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x1; else ant_conf->fast_div_bias = 0x2; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x21: /* LNA1 LNA2 */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x23: /* LNA1 A+B */ if (!(antcomb->scan) && @@ -499,23 +462,15 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x1; else ant_conf->fast_div_bias = 0x2; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x30: /* A+B A-B */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x31: /* A+B LNA2 */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; case 0x32: /* A+B LNA1 */ ant_conf->fast_div_bias = 0x1; - ant_conf->main_gaintb = 0; - ant_conf->alt_gaintb = 0; break; default: break; -- cgit v1.2.3 From 9b460d77e715b5b774ff927a1925b80b483283b1 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 16 Sep 2012 08:05:54 +0530 Subject: ath9k: Remove a couple of unused variables Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index fd24535677a6..8e27f4fb21fe 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -600,8 +600,6 @@ struct ath_ant_comb { int main_conf; enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf; enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf; - int first_bias; - int second_bias; bool first_ratio; bool second_ratio; unsigned long scan_start_time; -- cgit v1.2.3 From 5317c9c3e9258b326c076d372e2eabf565d9a462 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 16 Sep 2012 08:06:08 +0530 Subject: ath9k_hw: Add antenna diversity group for AR9565 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/antenna.c | 62 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/ar9003_phy.c | 3 ++ 2 files changed, 65 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index eb61c6bc480e..8eb274f16861 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -475,6 +475,68 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, default: break; } + } else if (ant_conf->div_group == 3) { + switch ((ant_conf->main_lna_conf << 4) | + ant_conf->alt_lna_conf) { + case 0x01: /* A-B LNA2 */ + ant_conf->fast_div_bias = 0x1; + break; + case 0x02: /* A-B LNA1 */ + ant_conf->fast_div_bias = 0x39; + break; + case 0x03: /* A-B A+B */ + ant_conf->fast_div_bias = 0x1; + break; + case 0x10: /* LNA2 A-B */ + if ((antcomb->scan == 0) && + (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { + ant_conf->fast_div_bias = 0x3f; + } else { + ant_conf->fast_div_bias = 0x1; + } + break; + case 0x12: /* LNA2 LNA1 */ + ant_conf->fast_div_bias = 0x39; + break; + case 0x13: /* LNA2 A+B */ + if ((antcomb->scan == 0) && + (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { + ant_conf->fast_div_bias = 0x3f; + } else { + ant_conf->fast_div_bias = 0x1; + } + break; + case 0x20: /* LNA1 A-B */ + if ((antcomb->scan == 0) && + (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { + ant_conf->fast_div_bias = 0x3f; + } else { + ant_conf->fast_div_bias = 0x4; + } + break; + case 0x21: /* LNA1 LNA2 */ + ant_conf->fast_div_bias = 0x6; + break; + case 0x23: /* LNA1 A+B */ + if ((antcomb->scan == 0) && + (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { + ant_conf->fast_div_bias = 0x3f; + } else { + ant_conf->fast_div_bias = 0x6; + } + break; + case 0x30: /* A+B A-B */ + ant_conf->fast_div_bias = 0x1; + break; + case 0x31: /* A+B LNA2 */ + ant_conf->fast_div_bias = 0x6; + break; + case 0x32: /* A+B LNA1 */ + ant_conf->fast_div_bias = 0x1; + break; + default: + break; + } } } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 158b50d3a853..a8ab81bf74c4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1291,6 +1291,9 @@ static void ar9003_hw_antdiv_comb_conf_get(struct ath_hw *ah, } else if (AR_SREV_9485(ah)) { antconf->lna1_lna2_delta = -9; antconf->div_group = 2; + } else if (AR_SREV_9565(ah)) { + antconf->lna1_lna2_delta = -3; + antconf->div_group = 3; } else { antconf->lna1_lna2_delta = -3; antconf->div_group = 0; -- cgit v1.2.3 From 68f7586c7b2c471750f11ccb3e5ac8f57b1b953e Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 16 Sep 2012 08:06:22 +0530 Subject: ath9k_hw: Update AR9565 initvals Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/ar9565_1p0_initvals.h | 100 ++++++++++----------- 1 file changed, 49 insertions(+), 51 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h index fa9e0932769c..843e79f67ff2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h @@ -58,8 +58,6 @@ static const u32 ar9565_1p0_mac_core[][2] = { {0x00008040, 0x00000000}, {0x00008044, 0x00000000}, {0x00008048, 0x00000000}, - {0x0000804c, 0xffffffff}, - {0x00008050, 0xffffffff}, {0x00008054, 0x00000000}, {0x00008058, 0x00000000}, {0x0000805c, 0x000fc78f}, @@ -246,7 +244,7 @@ static const u32 ar9565_1p0_baseband_core[][2] = { {0x00009e50, 0x00ff03f1}, {0x00009e54, 0xe4c355c7}, {0x00009e5c, 0xe9198724}, - {0x00009fc0, 0x823e4788}, + {0x00009fc0, 0x823e4fc8}, {0x00009fc4, 0x0001efb5}, {0x00009fcc, 0x40000014}, {0x0000a20c, 0x00000000}, @@ -291,7 +289,7 @@ static const u32 ar9565_1p0_baseband_core[][2] = { {0x0000a3ec, 0x20202020}, {0x0000a3f0, 0x00000000}, {0x0000a3f4, 0x00000006}, - {0x0000a3f8, 0x0cdbd380}, + {0x0000a3f8, 0x0c9bd380}, {0x0000a3fc, 0x000f0f01}, {0x0000a400, 0x8fa91f01}, {0x0000a404, 0x00000000}, @@ -355,11 +353,11 @@ static const u32 ar9565_1p0_baseband_postamble[][5] = { {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, + {0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222}, {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, - {0x0000a204, 0x033187c0, 0x033187c4, 0x033187c4, 0x033187c0}, + {0x0000a204, 0x07318fc0, 0x07318fc4, 0x07318fc4, 0x07318fc0}, {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, {0x0000a22c, 0x01026a2f, 0x01026a27, 0x01026a2f, 0x01026a2f}, {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, @@ -375,9 +373,9 @@ static const u32 ar9565_1p0_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, {0x0000a288, 0x00100510, 0x00100510, 0x00100510, 0x00100510}, {0x0000a28c, 0x00021551, 0x00021551, 0x00021551, 0x00021551}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, {0x0000a2d0, 0x00071982, 0x00071982, 0x00071982, 0x00071982}, - {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a}, + {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000ae04, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -417,7 +415,7 @@ static const u32 ar9565_1p0_radio_core[][2] = { {0x00016144, 0x02084080}, {0x00016148, 0x000080c0}, {0x00016280, 0x050a0001}, - {0x00016284, 0x3d841400}, + {0x00016284, 0x3d841440}, {0x00016288, 0x00000000}, {0x0001628c, 0xe3000000}, {0x00016290, 0xa1004080}, @@ -840,27 +838,27 @@ static const u32 ar9565_1p0_common_wo_xlna_rx_gain_table[][2] = { {0x0000a0b4, 0x00000000}, {0x0000a0b8, 0x00000000}, {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x301f3000}, - {0x0000a0c4, 0x41004101}, - {0x0000a0c8, 0x411e411f}, - {0x0000a0cc, 0x411c411d}, - {0x0000a0d0, 0x42434244}, - {0x0000a0d4, 0x42414242}, - {0x0000a0d8, 0x425f4240}, - {0x0000a0dc, 0x5342425e}, - {0x0000a0e0, 0x53405341}, - {0x0000a0e4, 0x535e535f}, - {0x0000a0e8, 0x7402535d}, - {0x0000a0ec, 0x74007401}, - {0x0000a0f0, 0x741e741f}, - {0x0000a0f4, 0x7522741d}, - {0x0000a0f8, 0x75207521}, - {0x0000a0fc, 0x753e753f}, - {0x0000a100, 0x76617662}, - {0x0000a104, 0x767f7660}, - {0x0000a108, 0x767d767e}, - {0x0000a10c, 0x77e277e3}, - {0x0000a110, 0x77e077e1}, + {0x0000a0c0, 0x00bf00a0}, + {0x0000a0c4, 0x11a011a1}, + {0x0000a0c8, 0x11be11bf}, + {0x0000a0cc, 0x11bc11bd}, + {0x0000a0d0, 0x22632264}, + {0x0000a0d4, 0x22612262}, + {0x0000a0d8, 0x227f2260}, + {0x0000a0dc, 0x4322227e}, + {0x0000a0e0, 0x43204321}, + {0x0000a0e4, 0x433e433f}, + {0x0000a0e8, 0x4462433d}, + {0x0000a0ec, 0x44604461}, + {0x0000a0f0, 0x447e447f}, + {0x0000a0f4, 0x5582447d}, + {0x0000a0f8, 0x55805581}, + {0x0000a0fc, 0x559e559f}, + {0x0000a100, 0x66816682}, + {0x0000a104, 0x669f6680}, + {0x0000a108, 0x669d669e}, + {0x0000a10c, 0x77627763}, + {0x0000a110, 0x77607761}, {0x0000a114, 0x00000000}, {0x0000a118, 0x00000000}, {0x0000a11c, 0x00000000}, @@ -872,27 +870,27 @@ static const u32 ar9565_1p0_common_wo_xlna_rx_gain_table[][2] = { {0x0000a134, 0x00000000}, {0x0000a138, 0x00000000}, {0x0000a13c, 0x00000000}, - {0x0000a140, 0x301f3000}, - {0x0000a144, 0x41004101}, - {0x0000a148, 0x411e411f}, - {0x0000a14c, 0x411c411d}, - {0x0000a150, 0x42434244}, - {0x0000a154, 0x42414242}, - {0x0000a158, 0x425f4240}, - {0x0000a15c, 0x5342425e}, - {0x0000a160, 0x53405341}, - {0x0000a164, 0x535e535f}, - {0x0000a168, 0x7402535d}, - {0x0000a16c, 0x74007401}, - {0x0000a170, 0x741e741f}, - {0x0000a174, 0x7522741d}, - {0x0000a178, 0x75207521}, - {0x0000a17c, 0x753e753f}, - {0x0000a180, 0x76617662}, - {0x0000a184, 0x767f7660}, - {0x0000a188, 0x767d767e}, - {0x0000a18c, 0x77e277e3}, - {0x0000a190, 0x77e077e1}, + {0x0000a140, 0x00bf00a0}, + {0x0000a144, 0x11a011a1}, + {0x0000a148, 0x11be11bf}, + {0x0000a14c, 0x11bc11bd}, + {0x0000a150, 0x22632264}, + {0x0000a154, 0x22612262}, + {0x0000a158, 0x227f2260}, + {0x0000a15c, 0x4322227e}, + {0x0000a160, 0x43204321}, + {0x0000a164, 0x433e433f}, + {0x0000a168, 0x4462433d}, + {0x0000a16c, 0x44604461}, + {0x0000a170, 0x447e447f}, + {0x0000a174, 0x5582447d}, + {0x0000a178, 0x55805581}, + {0x0000a17c, 0x559e559f}, + {0x0000a180, 0x66816682}, + {0x0000a184, 0x669f6680}, + {0x0000a188, 0x669d669e}, + {0x0000a18c, 0x77627763}, + {0x0000a190, 0x77607761}, {0x0000a194, 0x00000000}, {0x0000a198, 0x00000000}, {0x0000a19c, 0x00000000}, -- cgit v1.2.3 From 362cd03fd828af38327fb448416c07a7c7a8e3cb Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 16 Sep 2012 08:06:36 +0530 Subject: ath9k_hw: Add a HW callback to set diversity This patch adds a new callback to handle WLAN RX diversity for AR9565. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 10 +++++ drivers/net/wireless/ath/ath9k/ar9003_phy.c | 60 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/ar9003_phy.h | 24 +++++++++++ drivers/net/wireless/ath/ath9k/hw-ops.h | 7 +++ drivers/net/wireless/ath/ath9k/hw.c | 4 ++ drivers/net/wireless/ath/ath9k/hw.h | 3 +- 6 files changed, 107 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 8d434df26818..e65aad07d9ee 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3629,6 +3629,16 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) /* enable_lnadiv */ regval &= (~AR_PHY_ANT_DIV_LNADIV); regval |= ((value >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S; + + if (AR_SREV_9565(ah)) { + if (ah->shared_chain_lnadiv) { + regval |= (1 << AR_PHY_ANT_SW_RX_PROT_S); + } else { + regval &= ~(1 << AR_PHY_ANT_DIV_LNADIV_S); + regval &= ~(1 << AR_PHY_ANT_SW_RX_PROT_S); + } + } + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); /*enable fast_div */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index a8ab81bf74c4..fc67844a1430 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1325,6 +1325,65 @@ static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); } +static void ar9003_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah, + bool enable) +{ + u8 ant_div_ctl1; + u32 regval; + + if (!AR_SREV_9565(ah)) + return; + + ah->shared_chain_lnadiv = enable; + ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); + + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + regval &= (~AR_ANT_DIV_CTRL_ALL); + regval |= (ant_div_ctl1 & 0x3f) << AR_ANT_DIV_CTRL_ALL_S; + regval &= ~AR_PHY_ANT_DIV_LNADIV; + regval |= ((ant_div_ctl1 >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S; + + if (enable) + regval |= AR_ANT_DIV_ENABLE; + + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); + + regval = REG_READ(ah, AR_PHY_CCK_DETECT); + regval &= ~AR_FAST_DIV_ENABLE; + regval |= ((ant_div_ctl1 >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; + + if (enable) + regval |= AR_FAST_DIV_ENABLE; + + REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); + + if (enable) { + REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, + (1 << AR_PHY_ANT_SW_RX_PROT_S)); + if (IS_CHAN_2GHZ(ah->curchan)) + REG_SET_BIT(ah, AR_PHY_RESTART, + AR_PHY_RESTART_ENABLE_DIV_M2FLAG); + REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, + AR_BTCOEX_WL_LNADIV_FORCE_ON); + } else { + REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE); + REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, + (1 << AR_PHY_ANT_SW_RX_PROT_S)); + REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE); + REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV, + AR_BTCOEX_WL_LNADIV_FORCE_ON); + + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + regval &= ~(AR_PHY_ANT_DIV_MAIN_LNACONF | + AR_PHY_ANT_DIV_ALT_LNACONF | + AR_PHY_ANT_DIV_MAIN_GAINTB | + AR_PHY_ANT_DIV_ALT_GAINTB); + regval |= (AR_PHY_ANT_DIV_LNA1 << AR_PHY_ANT_DIV_MAIN_LNACONF_S); + regval |= (AR_PHY_ANT_DIV_LNA2 << AR_PHY_ANT_DIV_ALT_LNACONF_S); + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); + } +} + static int ar9003_hw_fast_chan_change(struct ath_hw *ah, struct ath9k_channel *chan, u8 *ini_reloaded) @@ -1423,6 +1482,7 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; + ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv; ar9003_hw_set_nf_limits(ah); ar9003_hw_set_radar_conf(ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index fdabc9a28a96..9a48e3d2f231 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -282,6 +282,8 @@ #define AR_PHY_ANT_FAST_DIV_BIAS 0x00007e00 #define AR_PHY_ANT_FAST_DIV_BIAS_S 9 +#define AR_PHY_ANT_SW_RX_PROT 0x00800000 +#define AR_PHY_ANT_SW_RX_PROT_S 23 #define AR_PHY_ANT_DIV_LNADIV 0x01000000 #define AR_PHY_ANT_DIV_LNADIV_S 24 #define AR_PHY_ANT_DIV_ALT_LNACONF 0x06000000 @@ -422,6 +424,8 @@ #define AR_PHY_FIND_SIG_RELSTEP 0x1f #define AR_PHY_FIND_SIG_RELSTEP_S 0 #define AR_PHY_FIND_SIG_RELSTEP_SIGN_BIT 5 +#define AR_PHY_RESTART_ENABLE_DIV_M2FLAG 0x00200000 +#define AR_PHY_RESTART_ENABLE_DIV_M2FLAG_S 21 #define AR_PHY_RESTART_DIV_GC 0x001C0000 #define AR_PHY_RESTART_DIV_GC_S 18 #define AR_PHY_RESTART_ENA 0x01 @@ -1261,4 +1265,24 @@ #define AR_PHY_CL_TAB_CL_GAIN_MOD 0x1f #define AR_PHY_CL_TAB_CL_GAIN_MOD_S 0 +#define AR_BTCOEX_WL_LNADIV 0x1a64 +#define AR_BTCOEX_WL_LNADIV_PREDICTED_PERIOD 0x00003FFF +#define AR_BTCOEX_WL_LNADIV_PREDICTED_PERIOD_S 0 +#define AR_BTCOEX_WL_LNADIV_DPDT_IGNORE_PRIORITY 0x00004000 +#define AR_BTCOEX_WL_LNADIV_DPDT_IGNORE_PRIORITY_S 14 +#define AR_BTCOEX_WL_LNADIV_FORCE_ON 0x00008000 +#define AR_BTCOEX_WL_LNADIV_FORCE_ON_S 15 +#define AR_BTCOEX_WL_LNADIV_MODE_OPTION 0x00030000 +#define AR_BTCOEX_WL_LNADIV_MODE_OPTION_S 16 +#define AR_BTCOEX_WL_LNADIV_MODE 0x007c0000 +#define AR_BTCOEX_WL_LNADIV_MODE_S 18 +#define AR_BTCOEX_WL_LNADIV_ALLOWED_TX_ANTDIV_WL_TX_REQ 0x00800000 +#define AR_BTCOEX_WL_LNADIV_ALLOWED_TX_ANTDIV_WL_TX_REQ_S 23 +#define AR_BTCOEX_WL_LNADIV_DISABLE_TX_ANTDIV_ENABLE 0x01000000 +#define AR_BTCOEX_WL_LNADIV_DISABLE_TX_ANTDIV_ENABLE_S 24 +#define AR_BTCOEX_WL_LNADIV_CONTINUOUS_BT_ACTIVE_PROTECT 0x02000000 +#define AR_BTCOEX_WL_LNADIV_CONTINUOUS_BT_ACTIVE_PROTECT_S 25 +#define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD 0xFC000000 +#define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD_S 26 + #endif /* AR9003_PHY_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 265bf77598a2..0f2b97f6b739 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -78,6 +78,13 @@ static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf); } +static inline void ath9k_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah, + bool enable) +{ + if (ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv) + ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv(ah, enable); +} + /* Private hardware call ops */ /* PHY ops */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c40e901c2bf8..1ac2e5c0fcfb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -24,6 +24,7 @@ #include "rc.h" #include "ar9003_mac.h" #include "ar9003_mci.h" +#include "ar9003_phy.h" #include "debug.h" #include "ath9k.h" @@ -2025,6 +2026,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_apply_gpio_override(ah); + if (AR_SREV_9565(ah) && ah->shared_chain_lnadiv) + REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON); + return 0; } EXPORT_SYMBOL(ath9k_hw_reset); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 0d17ce0b0ff4..17203b527507 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -687,7 +687,7 @@ struct ath_hw_ops { struct ath_hw_antcomb_conf *antconf); void (*antdiv_comb_conf_set)(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf); - + void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable); }; struct ath_nf_limits { @@ -731,6 +731,7 @@ struct ath_hw { bool aspm_enabled; bool is_monitoring; bool need_an_top2_fixup; + bool shared_chain_lnadiv; u16 tx_trig_level; u32 nf_regs[6]; -- cgit v1.2.3 From e09f2dc73c5c4927cbc55d9c29bef4209c2d866d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 16 Sep 2012 08:06:56 +0530 Subject: ath9k: Add a module parameter to enable diversity Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 1 + drivers/net/wireless/ath/ath9k/antenna.c | 4 ++++ drivers/net/wireless/ath/ath9k/init.c | 12 ++++++++++++ 3 files changed, 17 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 6169fbd23ed1..4521342c62cc 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -159,6 +159,7 @@ struct ath_common { bool btcoex_enabled; bool disable_ani; + bool antenna_diversity; }; struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 8eb274f16861..664844c5d3d5 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -776,6 +776,7 @@ div_comb_done: void ath_ant_comb_update(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_hw_antcomb_conf div_ant_conf; u8 lna_conf; @@ -790,4 +791,7 @@ void ath_ant_comb_update(struct ath_softc *sc) div_ant_conf.alt_lna_conf = lna_conf; ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf); + + if (common->antenna_diversity) + ath9k_hw_antctrl_shared_chain_lnadiv(ah, true); } diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 706255222598..fad3ccd5cd91 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -46,6 +46,10 @@ static int ath9k_btcoex_enable; module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444); MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); +static int ath9k_enable_diversity; +module_param_named(enable_diversity, ath9k_enable_diversity, int, 0444); +MODULE_PARM_DESC(enable_diversity, "Enable Antenna diversity for AR9565"); + bool is_ath9k_unloaded; /* We use the hw_value as an index into our private channel structure */ @@ -546,6 +550,14 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, common->debug_mask = ath9k_debug; common->btcoex_enabled = ath9k_btcoex_enable == 1; common->disable_ani = false; + + /* + * Enable Antenna diversity only when BTCOEX is disabled + * and the user manually requests the feature. + */ + if (!common->btcoex_enabled && ath9k_enable_diversity) + common->antenna_diversity = 1; + spin_lock_init(&common->cc_lock); spin_lock_init(&sc->sc_serial_rw); -- cgit v1.2.3 From 06236e53ce83d9f770a25a5305b8651544ff8b67 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 16 Sep 2012 08:07:12 +0530 Subject: ath9k_hw: Enable WLAN RX diversity for AR9565 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 1ac2e5c0fcfb..2cc08a7912ab 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2543,7 +2543,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) } - if (AR_SREV_9330(ah) || AR_SREV_9485(ah)) { + if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) { ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); /* * enable the diversity-combining algorithm only when -- cgit v1.2.3 From 8c6728b08ee589ae3c7a75f0d1aa5d73a9c042f1 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sun, 16 Sep 2012 22:29:49 +0200 Subject: rt2x00: Code clean up in rt2800lib. Make the code in rt2800_get_default_vgc more understandable and readable, especially for the 5GHz band values. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 9e09367c9739..cec4a992374e 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2896,6 +2896,8 @@ EXPORT_SYMBOL_GPL(rt2800_link_stats); static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev) { + u8 vgc; + if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { if (rt2x00_rt(rt2x00dev, RT3070) || rt2x00_rt(rt2x00dev, RT3071) || @@ -2904,15 +2906,17 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev) rt2x00_rt(rt2x00dev, RT3390) || rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392)) - return 0x1c + (2 * rt2x00dev->lna_gain); + vgc = 0x1c + (2 * rt2x00dev->lna_gain); + else + vgc = 0x2e + rt2x00dev->lna_gain; + } else { /* 5GHZ band */ + if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) + vgc = 0x32 + (rt2x00dev->lna_gain * 5) / 3; else - return 0x2e + rt2x00dev->lna_gain; + vgc = 0x3a + (rt2x00dev->lna_gain * 5) / 3; } - if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) - return 0x32 + (rt2x00dev->lna_gain * 5) / 3; - else - return 0x3a + (rt2x00dev->lna_gain * 5) / 3; + return vgc; } static inline void rt2800_set_vgc(struct rt2x00_dev *rt2x00dev, -- cgit v1.2.3 From d961e447a616c83ab7a7022bd98d60ec086f07ab Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sun, 16 Sep 2012 22:29:50 +0200 Subject: rt2x00: rt2800 - Fix default vgc values for RT3572 Align with the values used by the RT3572 Ralink vendor driver v2.5.0.0. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index cec4a992374e..17b8a281094f 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2904,16 +2904,21 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev) rt2x00_rt(rt2x00dev, RT3090) || rt2x00_rt(rt2x00dev, RT3290) || rt2x00_rt(rt2x00dev, RT3390) || + rt2x00_rt(rt2x00dev, RT3572) || rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392)) vgc = 0x1c + (2 * rt2x00dev->lna_gain); else vgc = 0x2e + rt2x00dev->lna_gain; } else { /* 5GHZ band */ - if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) - vgc = 0x32 + (rt2x00dev->lna_gain * 5) / 3; - else - vgc = 0x3a + (rt2x00dev->lna_gain * 5) / 3; + if (rt2x00_rt(rt2x00dev, RT3572)) + vgc = 0x22 + (rt2x00dev->lna_gain * 5) / 3; + else { + if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) + vgc = 0x32 + (rt2x00dev->lna_gain * 5) / 3; + else + vgc = 0x3a + (rt2x00dev->lna_gain * 5) / 3; + } } return vgc; -- cgit v1.2.3 From 59d1287428ed93e2fead507b5be9a5ee453b8ebf Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sun, 16 Sep 2012 22:29:51 +0200 Subject: rt2x00: rt2800lib - code cleanup. Move RT3290 BBP initialization sequence (part) to the right place in the code. This is just a code style change, no functional changes. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 17b8a281094f..37f64ba83221 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3535,6 +3535,11 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) } else if (rt2800_is_305x_soc(rt2x00dev)) { rt2800_bbp_write(rt2x00dev, 78, 0x0e); rt2800_bbp_write(rt2x00dev, 80, 0x08); + } else if (rt2x00_rt(rt2x00dev, RT3290)) { + rt2800_bbp_write(rt2x00dev, 74, 0x0b); + rt2800_bbp_write(rt2x00dev, 79, 0x18); + rt2800_bbp_write(rt2x00dev, 80, 0x09); + rt2800_bbp_write(rt2x00dev, 81, 0x33); } else if (rt2x00_rt(rt2x00dev, RT3352)) { rt2800_bbp_write(rt2x00dev, 78, 0x0e); rt2800_bbp_write(rt2x00dev, 80, 0x08); @@ -3543,13 +3548,6 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 81, 0x37); } - if (rt2x00_rt(rt2x00dev, RT3290)) { - rt2800_bbp_write(rt2x00dev, 74, 0x0b); - rt2800_bbp_write(rt2x00dev, 79, 0x18); - rt2800_bbp_write(rt2x00dev, 80, 0x09); - rt2800_bbp_write(rt2x00dev, 81, 0x33); - } - rt2800_bbp_write(rt2x00dev, 82, 0x62); if (rt2x00_rt(rt2x00dev, RT3290) || rt2x00_rt(rt2x00dev, RT5390) || -- cgit v1.2.3 From 5b196139e57a96d06b86a99533a438c86d6354c9 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sun, 16 Sep 2012 22:29:52 +0200 Subject: rt2x00: Code style cleanup in rt2800lib.c Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 37f64ba83221..d745c32a7361 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3090,7 +3090,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); } else if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) { + rt2x00_rt(rt2x00dev, RT5392)) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); -- cgit v1.2.3 From 7ad630352216c5f4f2750978f661bc9c748423cc Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sun, 16 Sep 2012 22:29:53 +0200 Subject: rt2x00: Clean up RFCSR1 programming in rt2800_config_channel_rf3xxx. Setting of the individual fields of the RF register can be simplified. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 37 +++++++-------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index d745c32a7361..540c94f8505a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1763,36 +1763,15 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); + rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, + rt2x00dev->default_ant.rx_chain_num <= 1); + rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, + rt2x00dev->default_ant.rx_chain_num <= 2); rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); - if (rt2x00_rt(rt2x00dev, RT3390)) { - rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, - rt2x00dev->default_ant.rx_chain_num == 1); - rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, - rt2x00dev->default_ant.tx_chain_num == 1); - } else { - rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0); - rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0); - rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0); - rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0); - - switch (rt2x00dev->default_ant.tx_chain_num) { - case 1: - rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1); - /* fall through */ - case 2: - rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1); - break; - } - - switch (rt2x00dev->default_ant.rx_chain_num) { - case 1: - rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1); - /* fall through */ - case 2: - rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1); - break; - } - } + rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, + rt2x00dev->default_ant.tx_chain_num <= 1); + rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, + rt2x00dev->default_ant.tx_chain_num <= 2); rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); -- cgit v1.2.3 From 9a17bad1c7cc794b8faa50386495b6b9c91673e4 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 18 Sep 2012 15:33:32 -0700 Subject: mwifiex: fix issue in resumed scan operation When delayed scan operation is resumed, we just add next scan command in queue but don't wakeup main thread to process the command. Hence the command is downloaded to firmware only after waking up the main thread by any other means. This bug which was introduced after "mwifiex: improve scan delay logic.." patch is fixed here. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/init.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 9c1549ee4c09..b2ba262f8a13 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -118,6 +118,7 @@ static void scan_delay_timer_fn(unsigned long data) mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + queue_work(adapter->workqueue, &adapter->main_work); goto done; } } else { -- cgit v1.2.3 From 029591f3485c9bd198513df39605e14d2ab7477d Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 19 Sep 2012 22:21:06 +0200 Subject: brcmfmac: fix sparse warnings in e-scan related code With the introduction of e-scan mechanism in brcmfmac (e756af5 brcmfmac: add e-scan support.) a couple of sparse warnings were introduced. This patch resolves those. Reported-by: Fengguang Wu Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 35 +++++++++++----------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 3491086053cd..58949723cbb9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -698,11 +698,11 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, u32 n_channels; s32 i; s32 offset; - __le16 chanspec; + u16 chanspec; u16 channel; struct ieee80211_channel *req_channel; char *ptr; - struct brcmf_ssid ssid; + struct brcmf_ssid_le ssid_le; memcpy(params_le->bssid, ether_bcast, ETH_ALEN); params_le->bss_type = DOT11_BSSTYPE_ANY; @@ -745,13 +745,10 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, chanspec |= WL_CHANSPEC_CTL_SB_UPPER; } - params_le->channel_list[i] = - (channel & WL_CHANSPEC_CHAN_MASK) | - chanspec; + chanspec |= (channel & WL_CHANSPEC_CHAN_MASK); WL_SCAN("Chan : %d, Channel spec: %x\n", - channel, params_le->channel_list[i]); - params_le->channel_list[i] = - cpu_to_le16(params_le->channel_list[i]); + channel, chanspec); + params_le->channel_list[i] = cpu_to_le16(chanspec); } } else { WL_SCAN("Scanning all channels\n"); @@ -764,17 +761,18 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, offset = roundup(offset, sizeof(u32)); ptr = (char *)params_le + offset; for (i = 0; i < n_ssids; i++) { - memset(&ssid, 0, sizeof(ssid)); - ssid.SSID_len = cpu_to_le32(request->ssids[i].ssid_len); - memcpy(ssid.SSID, request->ssids[i].ssid, - request->ssids[i].ssid_len); - if (!ssid.SSID_len) + memset(&ssid_le, 0, sizeof(ssid_le)); + ssid_le.SSID_len = + cpu_to_le32(request->ssids[i].ssid_len); + memcpy(ssid_le.SSID, request->ssids[i].ssid, + request->ssids[i].ssid_len); + if (!ssid_le.SSID_len) WL_SCAN("%d: Broadcast scan\n", i); else WL_SCAN("%d: scan for %s size =%d\n", i, - ssid.SSID, ssid.SSID_len); - memcpy(ptr, &ssid, sizeof(ssid)); - ptr += sizeof(ssid); + ssid_le.SSID, ssid_le.SSID_len); + memcpy(ptr, &ssid_le, sizeof(ssid_le)); + ptr += sizeof(ssid_le); } } else { WL_SCAN("Broadcast scan %p\n", request->ssids); @@ -2840,10 +2838,13 @@ brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss, !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) { if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) == (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) { + s16 bss_rssi = le16_to_cpu(bss->RSSI); + s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI); + /* preserve max RSSI if the measurements are * both on-channel or both off-channel */ - if (bss_info_le->RSSI > bss->RSSI) + if (bss_info_rssi > bss_rssi) bss->RSSI = bss_info_le->RSSI; } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) && (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) { -- cgit v1.2.3 From 108a4bee9db5d50e99b3aea349cbc987cc857b32 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 19 Sep 2012 22:21:07 +0200 Subject: brcmfmac: extend brcmf_term_iscan() to abort e-scan With the introduction of E-Scan there are two scan mechanisms in the driver. I-Scan was aborted on suspend and bringing down the device using brcmf_term_iscan(). The function has been renamed to brcmf_abort_scanning() and covers e-scan abort as well. Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 44 +++++++++++----------- 1 file changed, 21 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 58949723cbb9..97ed75f6e277 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -2589,11 +2589,13 @@ update_bss_info_out: return err; } -static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv) +static void brcmf_abort_scanning(struct brcmf_cfg80211_priv *cfg_priv) { struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); + struct escan_info *escan = &cfg_priv->escan_info; struct brcmf_ssid ssid; + set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); if (cfg_priv->iscan_on) { iscan->state = WL_ISCAN_STATE_IDLE; @@ -2607,7 +2609,20 @@ static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv) /* Abort iscan running in FW */ memset(&ssid, 0, sizeof(ssid)); brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT); + + if (cfg_priv->scan_request) { + /* Indidate scan abort to cfg80211 layer */ + WL_INFO("Terminating scan in progress\n"); + cfg80211_scan_done(cfg_priv->scan_request, true); + cfg_priv->scan_request = NULL; + } + } + if (cfg_priv->escan_on && cfg_priv->scan_request) { + escan->escan_state = WL_ESCAN_STATE_IDLE; + brcmf_notify_escan_complete(cfg_priv, escan->ndev, true, true); } + clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); + clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); } static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, @@ -3032,18 +3047,10 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, brcmf_delay(500); } - set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); if (test_bit(WL_STATUS_READY, &cfg_priv->status)) - brcmf_term_iscan(cfg_priv); - - if (cfg_priv->scan_request) { - /* Indidate scan abort to cfg80211 layer */ - WL_INFO("Terminating scan in progress\n"); - cfg80211_scan_done(cfg_priv->scan_request, true); - cfg_priv->scan_request = NULL; - } - clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); - clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); + brcmf_abort_scanning(cfg_priv); + else + clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); /* Turn off watchdog timer */ if (test_bit(WL_STATUS_READY, &cfg_priv->status)) @@ -3950,7 +3957,7 @@ static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv) cfg_priv->dongle_up = false; /* dongle down */ brcmf_flush_eq(cfg_priv); brcmf_link_down(cfg_priv); - brcmf_term_iscan(cfg_priv); + brcmf_abort_scanning(cfg_priv); brcmf_deinit_priv_mem(cfg_priv); } @@ -4361,17 +4368,8 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv) brcmf_delay(500); } - set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); - brcmf_term_iscan(cfg_priv); - if (cfg_priv->scan_request) { - cfg80211_scan_done(cfg_priv->scan_request, true); - /* May need to perform this to cover rmmod */ - /* wl_set_mpc(cfg_to_ndev(wl), 1); */ - cfg_priv->scan_request = NULL; - } + brcmf_abort_scanning(cfg_priv); clear_bit(WL_STATUS_READY, &cfg_priv->status); - clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); - clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); brcmf_debugfs_remove_netdev(cfg_priv); -- cgit v1.2.3 From e58060723c91a2345318fe809fc99945776a7a25 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 19 Sep 2012 22:21:08 +0200 Subject: brcmfmac: introduce scheduled scan support This change add support for NL80211 scheduled scan. This may be used to offload scanning to the device, which may give the host opportunity to sleep. The newer versions of wpa_supplicant have support for this functionality. Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 306 ++++++++++++++++++++- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | 82 ++++++ 2 files changed, 387 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 97ed75f6e277..daaac4e2658d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -36,6 +36,18 @@ #include "dhd.h" #include "wl_cfg80211.h" +#define BRCMF_SCAN_IE_LEN_MAX 2048 +#define BRCMF_PNO_VERSION 2 +#define BRCMF_PNO_TIME 30 +#define BRCMF_PNO_REPEAT 4 +#define BRCMF_PNO_FREQ_EXPO_MAX 3 +#define BRCMF_PNO_MAX_PFN_COUNT 16 +#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6 +#define BRCMF_PNO_HIDDEN_BIT 2 +#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF +#define BRCMF_PNO_SCAN_COMPLETE 1 +#define BRCMF_PNO_SCAN_INCOMPLETE 0 + #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) @@ -830,7 +842,17 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_priv *cfg_priv, if (err) WL_ERR("Scan abort failed\n"); } - if (scan_request) { + /* + * e-scan can be initiated by scheduled scan + * which takes precedence. + */ + if (cfg_priv->sched_escan) { + WL_SCAN("scheduled scan completed\n"); + cfg_priv->sched_escan = false; + if (!aborted) + cfg80211_sched_scan_results(cfg_to_wiphy(cfg_priv)); + brcmf_set_mpc(ndev, 1); + } else if (scan_request) { WL_SCAN("ESCAN Completed scan: %s\n", aborted ? "Aborted" : "Done"); cfg80211_scan_done(scan_request, aborted); @@ -3229,6 +3251,269 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) } +/* + * PFN result doesn't have all the info which are + * required by the supplicant + * (For e.g IEs) Do a target Escan so that sched scan results are reported + * via wl_inform_single_bss in the required format. Escan does require the + * scan request in the form of cfg80211_scan_request. For timebeing, create + * cfg80211_scan_request one out of the received PNO event. + */ +static s32 +brcmf_notify_sched_scan_results(struct brcmf_cfg80211_priv *cfg_priv, + struct net_device *ndev, + const struct brcmf_event_msg *e, void *data) +{ + struct brcmf_pno_net_info_le *netinfo, *netinfo_start; + struct cfg80211_scan_request *request = NULL; + struct cfg80211_ssid *ssid = NULL; + struct ieee80211_channel *channel = NULL; + struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); + int err = 0; + int channel_req = 0; + int band = 0; + struct brcmf_pno_scanresults_le *pfn_result; + u32 result_count; + u32 status; + + WL_SCAN("Enter\n"); + + if (e->event_type == cpu_to_be32(BRCMF_E_PFN_NET_LOST)) { + WL_SCAN("PFN NET LOST event. Do Nothing\n"); + return 0; + } + + pfn_result = (struct brcmf_pno_scanresults_le *)data; + result_count = le32_to_cpu(pfn_result->count); + status = le32_to_cpu(pfn_result->status); + + /* + * PFN event is limited to fit 512 bytes so we may get + * multiple NET_FOUND events. For now place a warning here. + */ + WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE); + WL_SCAN("PFN NET FOUND event. count: %d\n", result_count); + if (result_count > 0) { + int i; + + request = kzalloc(sizeof(*request), GFP_KERNEL); + ssid = kzalloc(sizeof(*ssid) * result_count, GFP_KERNEL); + channel = kzalloc(sizeof(*channel) * result_count, GFP_KERNEL); + if (!request || !ssid || !channel) { + err = -ENOMEM; + goto out_err; + } + + request->wiphy = wiphy; + data += sizeof(struct brcmf_pno_scanresults_le); + netinfo_start = (struct brcmf_pno_net_info_le *)data; + + for (i = 0; i < result_count; i++) { + netinfo = &netinfo_start[i]; + if (!netinfo) { + WL_ERR("Invalid netinfo ptr. index: %d\n", i); + err = -EINVAL; + goto out_err; + } + + WL_SCAN("SSID:%s Channel:%d\n", + netinfo->SSID, netinfo->channel); + memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len); + ssid[i].ssid_len = netinfo->SSID_len; + request->n_ssids++; + + channel_req = netinfo->channel; + if (channel_req <= CH_MAX_2G_CHANNEL) + band = NL80211_BAND_2GHZ; + else + band = NL80211_BAND_5GHZ; + channel[i].center_freq = + ieee80211_channel_to_frequency(channel_req, + band); + channel[i].band = band; + channel[i].flags |= IEEE80211_CHAN_NO_HT40; + request->channels[i] = &channel[i]; + request->n_channels++; + } + + /* assign parsed ssid array */ + if (request->n_ssids) + request->ssids = &ssid[0]; + + if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { + /* Abort any on-going scan */ + brcmf_abort_scanning(cfg_priv); + } + + set_bit(WL_STATUS_SCANNING, &cfg_priv->status); + err = brcmf_do_escan(cfg_priv, wiphy, ndev, request); + if (err) { + clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); + goto out_err; + } + cfg_priv->sched_escan = true; + cfg_priv->scan_request = request; + } else { + WL_ERR("FALSE PNO Event. (pfn_count == 0)\n"); + goto out_err; + } + + kfree(ssid); + kfree(channel); + kfree(request); + return 0; + +out_err: + kfree(ssid); + kfree(channel); + kfree(request); + cfg80211_sched_scan_stopped(wiphy); + return err; +} + +#ifndef CONFIG_BRCMISCAN +static int brcmf_dev_pno_clean(struct net_device *ndev) +{ + char iovbuf[128]; + int ret; + + /* Disable pfn */ + ret = brcmf_dev_intvar_set(ndev, "pfn", 0); + if (ret == 0) { + /* clear pfn */ + ret = brcmf_dev_iovar_setbuf(ndev, "pfnclear", NULL, 0, + iovbuf, sizeof(iovbuf)); + } + if (ret < 0) + WL_ERR("failed code %d\n", ret); + + return ret; +} + +static int brcmf_dev_pno_config(struct net_device *ndev) +{ + struct brcmf_pno_param_le pfn_param; + char iovbuf[128]; + + memset(&pfn_param, 0, sizeof(pfn_param)); + pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION); + + /* set extra pno params */ + pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT); + pfn_param.repeat = BRCMF_PNO_REPEAT; + pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX; + + /* set up pno scan fr */ + pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME); + + return brcmf_dev_iovar_setbuf(ndev, "pfn_set", + &pfn_param, sizeof(pfn_param), + iovbuf, sizeof(iovbuf)); +} + +static int +brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_sched_scan_request *request) +{ + char iovbuf[128]; + struct brcmf_cfg80211_priv *cfg_priv = wiphy_priv(wiphy); + struct brcmf_pno_net_param_le pfn; + int i; + int ret = 0; + + WL_SCAN("Enter n_match_sets:%d n_ssids:%d\n", + request->n_match_sets, request->n_ssids); + if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { + WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status); + return -EAGAIN; + } + + if (!request || !request->n_ssids || !request->n_match_sets) { + WL_ERR("Invalid sched scan req!! n_ssids:%d\n", + request->n_ssids); + return -EINVAL; + } + + if (request->n_ssids > 0) { + for (i = 0; i < request->n_ssids; i++) { + /* Active scan req for ssids */ + WL_SCAN(">>> Active scan req for ssid (%s)\n", + request->ssids[i].ssid); + + /* + * match_set ssids is a supert set of n_ssid list, + * so we need not add these set seperately. + */ + } + } + + if (request->n_match_sets > 0) { + /* clean up everything */ + ret = brcmf_dev_pno_clean(ndev); + if (ret < 0) { + WL_ERR("failed error=%d\n", ret); + return ret; + } + + /* configure pno */ + ret = brcmf_dev_pno_config(ndev); + if (ret < 0) { + WL_ERR("PNO setup failed!! ret=%d\n", ret); + return -EINVAL; + } + + /* configure each match set */ + for (i = 0; i < request->n_match_sets; i++) { + struct cfg80211_ssid *ssid; + u32 ssid_len; + + ssid = &request->match_sets[i].ssid; + ssid_len = ssid->ssid_len; + + if (!ssid_len) { + WL_ERR("skip broadcast ssid\n"); + continue; + } + pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN); + pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY); + pfn.wsec = cpu_to_le32(0); + pfn.infra = cpu_to_le32(1); + pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT); + pfn.ssid.SSID_len = cpu_to_le32(ssid_len); + memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len); + ret = brcmf_dev_iovar_setbuf(ndev, "pfn_add", + &pfn, sizeof(pfn), + iovbuf, sizeof(iovbuf)); + WL_SCAN(">>> PNO filter %s for ssid (%s)\n", + ret == 0 ? "set" : "failed", + ssid->ssid); + } + /* Enable the PNO */ + if (brcmf_dev_intvar_set(ndev, "pfn", 1) < 0) { + WL_ERR("PNO enable failed!! ret=%d\n", ret); + return -EINVAL; + } + } else { + return -EINVAL; + } + + return 0; +} + +static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, + struct net_device *ndev) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + + WL_SCAN("enter\n"); + brcmf_dev_pno_clean(ndev); + if (cfg_priv->sched_escan) + brcmf_notify_escan_complete(cfg_priv, ndev, true, true); + return 0; +} +#endif /* CONFIG_BRCMISCAN */ + #ifdef CONFIG_NL80211_TESTMODE static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) { @@ -3271,6 +3556,11 @@ static struct cfg80211_ops wl_cfg80211_ops = { .set_pmksa = brcmf_cfg80211_set_pmksa, .del_pmksa = brcmf_cfg80211_del_pmksa, .flush_pmksa = brcmf_cfg80211_flush_pmksa, +#ifndef CONFIG_BRCMISCAN + /* scheduled scan need e-scan, which is mutual exclusive with i-scan */ + .sched_scan_start = brcmf_cfg80211_sched_scan_start, + .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, +#endif #ifdef CONFIG_NL80211_TESTMODE .testmode_cmd = brcmf_cfg80211_testmode #endif @@ -3292,6 +3582,17 @@ static s32 brcmf_mode_to_nl80211_iftype(s32 mode) return err; } +static void brcmf_wiphy_pno_params(struct wiphy *wiphy) +{ +#ifndef CONFIG_BRCMFISCAN + /* scheduled scan settings */ + wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; + wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; + wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; + wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; +#endif +} + static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, struct device *ndev) { @@ -3330,6 +3631,7 @@ static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, * save mode * by default */ + brcmf_wiphy_pno_params(wdev->wiphy); err = wiphy_register(wdev->wiphy); if (err < 0) { WL_ERR("Could not register wiphy device (%d)\n", err); @@ -3732,6 +4034,7 @@ static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el) el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status; el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status; el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status; + el->handler[BRCMF_E_PFN_NET_FOUND] = brcmf_notify_sched_scan_results; } static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) @@ -4103,6 +4406,7 @@ static s32 brcmf_dongle_eventmsg(struct net_device *ndev) setbit(eventmask, BRCMF_E_JOIN_START); setbit(eventmask, BRCMF_E_SCAN_COMPLETE); setbit(eventmask, BRCMF_E_ESCAN_RESULT); + setbit(eventmask, BRCMF_E_PFN_NET_FOUND); brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 3b2129738d30..b5c3fd942f59 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -295,6 +295,87 @@ struct escan_info { struct net_device *ndev; }; +/** + * struct brcmf_pno_param_le - PNO scan configuration parameters + * + * @version: PNO parameters version. + * @scan_freq: scan frequency. + * @lost_network_timeout: #sec. to declare discovered network as lost. + * @flags: Bit field to control features of PFN such as sort criteria auto + * enable switch and background scan. + * @rssi_margin: Margin to avoid jitter for choosing a PFN based on RSSI sort + * criteria. + * @bestn: number of best networks in each scan. + * @mscan: number of scans recorded. + * @repeat: minimum number of scan intervals before scan frequency changes + * in adaptive scan. + * @exp: exponent of 2 for maximum scan interval. + * @slow_freq: slow scan period. + */ +struct brcmf_pno_param_le { + __le32 version; + __le32 scan_freq; + __le32 lost_network_timeout; + __le16 flags; + __le16 rssi_margin; + u8 bestn; + u8 mscan; + u8 repeat; + u8 exp; + __le32 slow_freq; +}; + +/** + * struct brcmf_pno_net_param_le - scan parameters per preferred network. + * + * @ssid: ssid name and its length. + * @flags: bit2: hidden. + * @infra: BSS vs IBSS. + * @auth: Open vs Closed. + * @wpa_auth: WPA type. + * @wsec: wsec value. + */ +struct brcmf_pno_net_param_le { + struct brcmf_ssid_le ssid; + __le32 flags; + __le32 infra; + __le32 auth; + __le32 wpa_auth; + __le32 wsec; +}; + +/** + * struct brcmf_pno_net_info_le - information per found network. + * + * @bssid: BSS network identifier. + * @channel: channel number only. + * @SSID_len: length of ssid. + * @SSID: ssid characters. + * @RSSI: receive signal strength (in dBm). + * @timestamp: age in seconds. + */ +struct brcmf_pno_net_info_le { + u8 bssid[ETH_ALEN]; + u8 channel; + u8 SSID_len; + u8 SSID[32]; + __le16 RSSI; + __le16 timestamp; +}; + +/** + * struct brcmf_pno_scanresults_le - result returned in PNO NET FOUND event. + * + * @version: PNO version identifier. + * @status: indicates completion status of PNO scan. + * @count: amount of brcmf_pno_net_info_le entries appended. + */ +struct brcmf_pno_scanresults_le { + __le32 version; + __le32 status; + __le32 count; +}; + /* dongle private data of cfg80211 interface */ struct brcmf_cfg80211_priv { struct wireless_dev *wdev; /* representing wl cfg80211 device */ @@ -325,6 +406,7 @@ struct brcmf_cfg80211_priv { bool iscan_on; /* iscan on/off switch */ bool iscan_kickstart; /* indicate iscan already started */ bool active_scan; /* current scan mode */ + bool sched_escan; /* e-scan for scheduled scan support running */ bool ibss_starter; /* indicates this sta is ibss starter */ bool link_up; /* link/connection up flag */ bool pwr_save; /* indicate whether dongle to support -- cgit v1.2.3 From 30c52bcf5c294d736b2fccdf7afd93b3af7a95bc Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 19 Sep 2012 22:21:09 +0200 Subject: brcmfmac: fix debug printout of event data. Some events result in printing of the buffer when debug is enabled. This printing was not very efficient. Changed to macro so it comes out nice and clean without filling log buffer. Reviewed-by: Arend Van Spriel Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c | 13 ++++--------- drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h | 2 ++ 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index c45270a2a1d9..fbecde73f904 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -433,13 +433,7 @@ brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data) } /* show any appended data */ - if (datalen) { - buf = (unsigned char *) event_data; - brcmf_dbg(EVENT, " data (%d) : ", datalen); - for (i = 0; i < datalen; i++) - brcmf_dbg(EVENT, " 0x%02x ", *buf++); - brcmf_dbg(EVENT, "\n"); - } + brcmf_dbg_hex_dump(datalen, event_data, datalen, "Received data"); } #endif /* DEBUG */ @@ -530,8 +524,9 @@ brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata, } #ifdef DEBUG - brcmf_c_show_host_event(event, event_data); -#endif /* DEBUG */ + if (BRCMF_EVENT_ON()) + brcmf_c_show_host_event(event, event_data); +#endif /* DEBUG */ return 0; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h index b784920532d3..fb508c2256dd 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h @@ -55,6 +55,7 @@ do { \ #define BRCMF_HDRS_ON() (brcmf_msg_level & BRCMF_HDRS_VAL) #define BRCMF_BYTES_ON() (brcmf_msg_level & BRCMF_BYTES_VAL) #define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL) +#define BRCMF_EVENT_ON() (brcmf_msg_level & BRCMF_EVENT_VAL) #else /* (defined DEBUG) || (defined DEBUG) */ @@ -65,6 +66,7 @@ do { \ #define BRCMF_HDRS_ON() 0 #define BRCMF_BYTES_ON() 0 #define BRCMF_GLOM_ON() 0 +#define BRCMF_EVENT_ON() 0 #endif /* defined(DEBUG) */ -- cgit v1.2.3 From 803599d4041812a2e90d7e9dd423b6977c56e1fb Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 19 Sep 2012 22:21:10 +0200 Subject: brcmfmac: store usb fw images in local linked list. For suspend/resume it is necessary to store firmware in memory. In order to support multiple usb dongles at the same time a linked list of firmwares was created. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/usb.c | 64 +++++++++++++++++---------- 1 file changed, 41 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 03f59cd0572a..edb431182d10 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -81,10 +81,12 @@ enum usbdev_suspend_state { }; struct brcmf_usb_image { - void *data; - u32 len; + struct list_head list; + s8 *fwname; + u8 *image; + int image_len; }; -static struct brcmf_usb_image g_image = { NULL, 0 }; +static struct list_head fw_image_list; struct intr_transfer_buf { u32 notification; @@ -1152,10 +1154,6 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo) { brcmf_dbg(TRACE, "devinfo %p\n", devinfo); - /* store the image globally */ - g_image.data = devinfo->image; - g_image.len = devinfo->image_len; - /* free the URBS */ brcmf_usb_free_q(&devinfo->rx_freeq, false); brcmf_usb_free_q(&devinfo->tx_freeq, false); @@ -1207,17 +1205,9 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo) { s8 *fwname; const struct firmware *fw; + struct brcmf_usb_image *fw_image; int err; - devinfo->image = g_image.data; - devinfo->image_len = g_image.len; - - /* - * if we have an image we can leave here. - */ - if (devinfo->image) - return 0; - switch (devinfo->bus_pub.devid) { case 43143: fwname = BRCMF_USB_43143_FW_NAME; @@ -1235,6 +1225,14 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo) break; } + list_for_each_entry(fw_image, &fw_image_list, list) { + if (fw_image->fwname == fwname) { + devinfo->image = fw_image->image; + devinfo->image_len = fw_image->image_len; + return 0; + } + } + /* fw image not yet loaded. Load it now and add to list */ err = request_firmware(&fw, fwname, devinfo->dev); if (!fw) { brcmf_dbg(ERROR, "fail to request firmware %s\n", fwname); @@ -1245,14 +1243,24 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo) return -EINVAL; } - devinfo->image = vmalloc(fw->size); /* plus nvram */ - if (!devinfo->image) + fw_image = kzalloc(sizeof(*fw_image), GFP_ATOMIC); + if (!fw_image) + return -ENOMEM; + INIT_LIST_HEAD(&fw_image->list); + list_add_tail(&fw_image->list, &fw_image_list); + fw_image->fwname = fwname; + fw_image->image = vmalloc(fw->size); + if (!fw_image->image) return -ENOMEM; - memcpy(devinfo->image, fw->data, fw->size); - devinfo->image_len = fw->size; + memcpy(fw_image->image, fw->data, fw->size); + fw_image->image_len = fw->size; release_firmware(fw); + + devinfo->image = fw_image->image; + devinfo->image_len = fw_image->image_len; + return 0; } @@ -1594,15 +1602,25 @@ static struct usb_driver brcmf_usbdrvr = { .disable_hub_initiated_lpm = 1, }; +static void brcmf_release_fw(struct list_head *q) +{ + struct brcmf_usb_image *fw_image, *next; + + list_for_each_entry_safe(fw_image, next, q, list) { + vfree(fw_image->image); + list_del_init(&fw_image->list); + } +} + + void brcmf_usb_exit(void) { usb_deregister(&brcmf_usbdrvr); - vfree(g_image.data); - g_image.data = NULL; - g_image.len = 0; + brcmf_release_fw(&fw_image_list); } void brcmf_usb_init(void) { + INIT_LIST_HEAD(&fw_image_list); usb_register(&brcmf_usbdrvr); } -- cgit v1.2.3 From 4754fceeb9a6cd04e5d51659a8309e9e623a09a6 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Wed, 19 Sep 2012 22:21:11 +0200 Subject: brcmfmac: streamline SDIO read frame routine SDIO read non-glomming frame routine handles first frame and follow up frame read separately. But they share a lot of common code. This patch abstracts a brcmf_sdio_hdparser function and optimize the code flow for better readability and future optimization. Reviewed-by: Arend van Spriel Reviewed-by: Hante Meuleman Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 621 ++++++++------------- 1 file changed, 233 insertions(+), 388 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index ff7e8297830c..3564686add9a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -482,6 +482,15 @@ struct sdpcm_shared_le { __le32 brpt_addr; }; +/* SDIO read frame info */ +struct brcmf_sdio_read { + u8 seq_num; + u8 channel; + u16 len; + u16 len_left; + u16 len_nxtfrm; + u8 dat_offset; +}; /* misc chip info needed by some of the routines */ /* Private data for SDIO bus interaction */ @@ -507,9 +516,11 @@ struct brcmf_sdio { u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN]; u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ - u16 nextlen; /* Next Read Len from last header */ u8 rx_seq; /* Receive sequence number (expected) */ + struct brcmf_sdio_read cur_read; + /* info of current read frame */ bool rxskip; /* Skip receive (awaiting NAK ACK) */ + bool rxpending; /* Data frame pending in dongle */ uint rxbound; /* Rx frames to read before resched */ uint txbound; /* Tx frames to send before resched */ @@ -551,8 +562,6 @@ struct brcmf_sdio { bool rxflow_mode; /* Rx flow control mode */ bool rxflow; /* Is rx flow control on */ bool alp_only; /* Don't use HT clock (ALP only) */ -/* Field to decide if rx of control frames happen in rxbuf or lb-pool */ - bool usebufpool; u8 *ctrl_frame_buf; u32 ctrl_frame_len; @@ -655,15 +664,6 @@ w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset) #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) -/* Packet free applicable unconditionally for sdio and sdspi. - * Conditional if bufpool was present for gspi bus. - */ -static void brcmf_sdbrcm_pktfree2(struct brcmf_sdio *bus, struct sk_buff *pkt) -{ - if (bus->usebufpool) - brcmu_pkt_buf_free_skb(pkt); -} - /* Turn backplane clock on or off */ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok) { @@ -979,7 +979,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) } /* Clear partial in any case */ - bus->nextlen = 0; + bus->cur_read.len = 0; /* If we can't reach the device, signal failure */ if (err) @@ -1031,6 +1031,96 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus) } } +static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, + struct brcmf_sdio_read *rd) +{ + u16 len, checksum; + u8 rx_seq, fc, tx_seq_max; + + /* + * 4 bytes hardware header (frame tag) + * Byte 0~1: Frame length + * Byte 2~3: Checksum, bit-wise inverse of frame length + */ + len = get_unaligned_le16(header); + checksum = get_unaligned_le16(header + sizeof(u16)); + /* All zero means no more to read */ + if (!(len | checksum)) { + bus->rxpending = false; + return false; + } + if ((u16)(~(len ^ checksum))) { + brcmf_dbg(ERROR, "HW header checksum error\n"); + bus->sdcnt.rx_badhdr++; + brcmf_sdbrcm_rxfail(bus, false, false); + return false; + } + if (len < SDPCM_HDRLEN) { + brcmf_dbg(ERROR, "HW header length error\n"); + return false; + } + rd->len = len; + + /* + * 8 bytes hardware header + * Byte 0: Rx sequence number + * Byte 1: 4 MSB Channel number, 4 LSB arbitrary flag + * Byte 2: Length of next data frame + * Byte 3: Data offset + * Byte 4: Flow control bits + * Byte 5: Maximum Sequence number allow for Tx + * Byte 6~7: Reserved + */ + rx_seq = SDPCM_PACKET_SEQUENCE(&header[SDPCM_FRAMETAG_LEN]); + rd->channel = SDPCM_PACKET_CHANNEL(&header[SDPCM_FRAMETAG_LEN]); + if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL) { + brcmf_dbg(ERROR, "HW header length too long\n"); + bus->sdiodev->bus_if->dstats.rx_errors++; + bus->sdcnt.rx_toolong++; + brcmf_sdbrcm_rxfail(bus, false, false); + rd->len = 0; + return false; + } + rd->dat_offset = SDPCM_DOFFSET_VALUE(&header[SDPCM_FRAMETAG_LEN]); + if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) { + brcmf_dbg(ERROR, "seq %d: bad data offset\n", rx_seq); + bus->sdcnt.rx_badhdr++; + brcmf_sdbrcm_rxfail(bus, false, false); + rd->len = 0; + return false; + } + if (rd->seq_num != rx_seq) { + brcmf_dbg(ERROR, "seq %d: sequence number error, expect %d\n", + rx_seq, rd->seq_num); + bus->sdcnt.rx_badseq++; + rd->seq_num = rx_seq; + } + rd->len_nxtfrm = header[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; + if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) { + /* only warm for NON glom packet */ + if (rd->channel != SDPCM_GLOM_CHANNEL) + brcmf_dbg(ERROR, "seq %d: next length error\n", rx_seq); + rd->len_nxtfrm = 0; + } + fc = SDPCM_FCMASK_VALUE(&header[SDPCM_FRAMETAG_LEN]); + if (bus->flowcontrol != fc) { + if (~bus->flowcontrol & fc) + bus->sdcnt.fc_xoff++; + if (bus->flowcontrol & ~fc) + bus->sdcnt.fc_xon++; + bus->sdcnt.fc_rcvd++; + bus->flowcontrol = fc; + } + tx_seq_max = SDPCM_WINDOW_VALUE(&header[SDPCM_FRAMETAG_LEN]); + if ((u8)(tx_seq_max - bus->tx_seq) > 0x40) { + brcmf_dbg(ERROR, "seq %d: max tx seq number error\n", rx_seq); + tx_seq_max = bus->tx_seq + 2; + } + bus->tx_max = tx_seq_max; + + return true; +} + static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) { u16 dlen, totlen; @@ -1045,6 +1135,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) int ifidx = 0; bool usechain = bus->use_rxchain; + u16 next_len; /* If packets, issue read(s) and send up packet chain */ /* Return sequence numbers consumed? */ @@ -1108,10 +1199,10 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) if (pnext) { brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n", totlen, num); - if (BRCMF_GLOM_ON() && bus->nextlen && - totlen != bus->nextlen) { + if (BRCMF_GLOM_ON() && bus->cur_read.len && + totlen != bus->cur_read.len) { brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n", - bus->nextlen, totlen, rxseq); + bus->cur_read.len, totlen, rxseq); } pfirst = pnext = NULL; } else { @@ -1122,7 +1213,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) /* Done with descriptor packet */ brcmu_pkt_buf_free_skb(bus->glomd); bus->glomd = NULL; - bus->nextlen = 0; + bus->cur_read.len = 0; } /* Ok -- either we just generated a packet chain, @@ -1195,12 +1286,13 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); - bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; - if ((bus->nextlen << 4) > MAX_RX_DATASZ) { + next_len = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; + if ((next_len << 4) > MAX_RX_DATASZ) { brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n", - bus->nextlen, seq); - bus->nextlen = 0; + next_len, seq); + next_len = 0; } + bus->cur_read.len = next_len << 4; doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); @@ -1301,7 +1393,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) bus->sdcnt.rxglomfail++; brcmf_sdbrcm_free_glom(bus); } - bus->nextlen = 0; + bus->cur_read.len = 0; return 0; } @@ -1496,422 +1588,166 @@ static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen) } } -static void -brcmf_alloc_pkt_and_read(struct brcmf_sdio *bus, u16 rdlen, - struct sk_buff **pkt, u8 **rxbuf) +static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) { - int sdret; /* Return code from calls */ - - *pkt = brcmu_pkt_buf_get_skb(rdlen + BRCMF_SDALIGN); - if (*pkt == NULL) - return; - - pkt_align(*pkt, rdlen, BRCMF_SDALIGN); - *rxbuf = (u8 *) ((*pkt)->data); - /* Read the entire frame */ - sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, *pkt); - bus->sdcnt.f2rxdata++; - - if (sdret < 0) { - brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n", - rdlen, sdret); - brcmu_pkt_buf_free_skb(*pkt); - bus->sdiodev->bus_if->dstats.rx_errors++; - /* Force retry w/normal header read. - * Don't attempt NAK for - * gSPI - */ - brcmf_sdbrcm_rxfail(bus, true, true); - *pkt = NULL; - } -} - -/* Checks the header */ -static int -brcmf_check_rxbuf(struct brcmf_sdio *bus, struct sk_buff *pkt, u8 *rxbuf, - u8 rxseq, u16 nextlen, u16 *len) -{ - u16 check; - bool len_consistent; /* Result of comparing readahead len and - len from hw-hdr */ - - memcpy(bus->rxhdr, rxbuf, SDPCM_HDRLEN); - - /* Extract hardware header fields */ - *len = get_unaligned_le16(bus->rxhdr); - check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); - - /* All zeros means readahead info was bad */ - if (!(*len | check)) { - brcmf_dbg(INFO, "(nextlen): read zeros in HW header???\n"); - goto fail; - } - - /* Validate check bytes */ - if ((u16)~(*len ^ check)) { - brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n", - nextlen, *len, check); - bus->sdcnt.rx_badhdr++; - brcmf_sdbrcm_rxfail(bus, false, false); - goto fail; - } - - /* Validate frame length */ - if (*len < SDPCM_HDRLEN) { - brcmf_dbg(ERROR, "(nextlen): HW hdr length invalid: %d\n", - *len); - goto fail; - } - - /* Check for consistency with readahead info */ - len_consistent = (nextlen != (roundup(*len, 16) >> 4)); - if (len_consistent) { - /* Mismatch, force retry w/normal - header (may be >4K) */ - brcmf_dbg(ERROR, "(nextlen): mismatch, nextlen %d len %d rnd %d; expected rxseq %d\n", - nextlen, *len, roundup(*len, 16), - rxseq); - brcmf_sdbrcm_rxfail(bus, true, true); - goto fail; - } - - return 0; - -fail: - brcmf_sdbrcm_pktfree2(bus, pkt); - return -EINVAL; -} - -/* Return true if there may be more frames to read */ -static uint -brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) -{ - u16 len, check; /* Extracted hardware header fields */ - u8 chan, seq, doff; /* Extracted software header fields */ - u8 fcbits; /* Extracted fcbits from software header */ - struct sk_buff *pkt; /* Packet for event or data frames */ u16 pad; /* Number of pad bytes to read */ - u16 rdlen; /* Total number of bytes to read */ - u8 rxseq; /* Next sequence number to expect */ uint rxleft = 0; /* Remaining number of frames allowed */ int sdret; /* Return code from calls */ - u8 txmax; /* Maximum tx sequence offered */ - u8 *rxbuf; int ifidx = 0; uint rxcount = 0; /* Total frames read */ + struct brcmf_sdio_read *rd = &bus->cur_read, rd_new; + u8 head_read = 0; brcmf_dbg(TRACE, "Enter\n"); /* Not finished unless we encounter no more frames indication */ - *finished = false; + bus->rxpending = true; - for (rxseq = bus->rx_seq, rxleft = maxframes; + for (rd->seq_num = bus->rx_seq, rxleft = maxframes; !bus->rxskip && rxleft && bus->sdiodev->bus_if->state != BRCMF_BUS_DOWN; - rxseq++, rxleft--) { + rd->seq_num++, rxleft--) { /* Handle glomming separately */ if (bus->glomd || !skb_queue_empty(&bus->glom)) { u8 cnt; brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n", bus->glomd, skb_peek(&bus->glom)); - cnt = brcmf_sdbrcm_rxglom(bus, rxseq); + cnt = brcmf_sdbrcm_rxglom(bus, rd->seq_num); brcmf_dbg(GLOM, "rxglom returned %d\n", cnt); - rxseq += cnt - 1; + rd->seq_num += cnt - 1; rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; continue; } - /* Try doing single read if we can */ - if (bus->nextlen) { - u16 nextlen = bus->nextlen; - bus->nextlen = 0; - - rdlen = len = nextlen << 4; - brcmf_pad(bus, &pad, &rdlen); - - /* - * After the frame is received we have to - * distinguish whether it is data - * or non-data frame. - */ - brcmf_alloc_pkt_and_read(bus, rdlen, &pkt, &rxbuf); - if (pkt == NULL) { - /* Give up on data, request rtx of events */ - brcmf_dbg(ERROR, "(nextlen): brcmf_alloc_pkt_and_read failed: len %d rdlen %d expected rxseq %d\n", - len, rdlen, rxseq); - continue; - } - - if (brcmf_check_rxbuf(bus, pkt, rxbuf, rxseq, nextlen, - &len) < 0) + rd->len_left = rd->len; + /* read header first for unknow frame length */ + if (!rd->len) { + sdret = brcmf_sdcard_recv_buf(bus->sdiodev, + bus->sdiodev->sbwad, + SDIO_FUNC_2, F2SYNC, + bus->rxhdr, + BRCMF_FIRSTREAD); + bus->sdcnt.f2rxhdrs++; + if (sdret < 0) { + brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", + sdret); + bus->sdcnt.rx_hdrfail++; + brcmf_sdbrcm_rxfail(bus, true, true); continue; - - /* Extract software header fields */ - chan = SDPCM_PACKET_CHANNEL( - &bus->rxhdr[SDPCM_FRAMETAG_LEN]); - seq = SDPCM_PACKET_SEQUENCE( - &bus->rxhdr[SDPCM_FRAMETAG_LEN]); - doff = SDPCM_DOFFSET_VALUE( - &bus->rxhdr[SDPCM_FRAMETAG_LEN]); - txmax = SDPCM_WINDOW_VALUE( - &bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - bus->nextlen = - bus->rxhdr[SDPCM_FRAMETAG_LEN + - SDPCM_NEXTLEN_OFFSET]; - if ((bus->nextlen << 4) > MAX_RX_DATASZ) { - brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n", - bus->nextlen, seq); - bus->nextlen = 0; } - bus->sdcnt.rx_readahead_cnt++; - - /* Handle Flow Control */ - fcbits = SDPCM_FCMASK_VALUE( - &bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - if (bus->flowcontrol != fcbits) { - if (~bus->flowcontrol & fcbits) - bus->sdcnt.fc_xoff++; - - if (bus->flowcontrol & ~fcbits) - bus->sdcnt.fc_xon++; - - bus->sdcnt.fc_rcvd++; - bus->flowcontrol = fcbits; - } - - /* Check and update sequence number */ - if (rxseq != seq) { - brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n", - seq, rxseq); - bus->sdcnt.rx_badseq++; - rxseq = seq; - } - - /* Check window for sanity */ - if ((u8) (txmax - bus->tx_seq) > 0x40) { - brcmf_dbg(ERROR, "got unlikely tx max %d with tx_seq %d\n", - txmax, bus->tx_seq); - txmax = bus->tx_seq + 2; - } - bus->tx_max = txmax; - - brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), - rxbuf, len, "Rx Data:\n"); - brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && - BRCMF_DATA_ON()) && - BRCMF_HDRS_ON(), + brcmf_dbg_hex_dump(BRCMF_BYTES_ON() || BRCMF_HDRS_ON(), bus->rxhdr, SDPCM_HDRLEN, "RxHdr:\n"); - if (chan == SDPCM_CONTROL_CHANNEL) { - brcmf_dbg(ERROR, "(nextlen): readahead on control packet %d?\n", - seq); - /* Force retry w/normal header read */ - bus->nextlen = 0; - brcmf_sdbrcm_rxfail(bus, false, true); - brcmf_sdbrcm_pktfree2(bus, pkt); - continue; + if (!brcmf_sdio_hdparser(bus, bus->rxhdr, rd)) { + if (!bus->rxpending) + break; + else + continue; } - /* Validate data offset */ - if ((doff < SDPCM_HDRLEN) || (doff > len)) { - brcmf_dbg(ERROR, "(nextlen): bad data offset %d: HW len %d min %d\n", - doff, len, SDPCM_HDRLEN); - brcmf_sdbrcm_rxfail(bus, false, false); - brcmf_sdbrcm_pktfree2(bus, pkt); + if (rd->channel == SDPCM_CONTROL_CHANNEL) { + brcmf_sdbrcm_read_control(bus, bus->rxhdr, + rd->len, + rd->dat_offset); + /* prepare the descriptor for the next read */ + rd->len = rd->len_nxtfrm << 4; + rd->len_nxtfrm = 0; + /* treat all packet as event if we don't know */ + rd->channel = SDPCM_EVENT_CHANNEL; continue; } - - /* All done with this one -- now deliver the packet */ - goto deliver; - } - - /* Read frame header (hardware and software) */ - sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, bus->rxhdr, - BRCMF_FIRSTREAD); - bus->sdcnt.f2rxhdrs++; - - if (sdret < 0) { - brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret); - bus->sdcnt.rx_hdrfail++; - brcmf_sdbrcm_rxfail(bus, true, true); - continue; - } - brcmf_dbg_hex_dump(BRCMF_BYTES_ON() || BRCMF_HDRS_ON(), - bus->rxhdr, SDPCM_HDRLEN, "RxHdr:\n"); - - - /* Extract hardware header fields */ - len = get_unaligned_le16(bus->rxhdr); - check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); - - /* All zeros means no more frames */ - if (!(len | check)) { - *finished = true; - break; - } - - /* Validate check bytes */ - if ((u16) ~(len ^ check)) { - brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n", - len, check); - bus->sdcnt.rx_badhdr++; - brcmf_sdbrcm_rxfail(bus, false, false); - continue; - } - - /* Validate frame length */ - if (len < SDPCM_HDRLEN) { - brcmf_dbg(ERROR, "HW hdr length invalid: %d\n", len); - continue; - } - - /* Extract software header fields */ - chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - /* Validate data offset */ - if ((doff < SDPCM_HDRLEN) || (doff > len)) { - brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n", - doff, len, SDPCM_HDRLEN, seq); - bus->sdcnt.rx_badhdr++; - brcmf_sdbrcm_rxfail(bus, false, false); - continue; - } - - /* Save the readahead length if there is one */ - bus->nextlen = - bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; - if ((bus->nextlen << 4) > MAX_RX_DATASZ) { - brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n", - bus->nextlen, seq); - bus->nextlen = 0; - } - - /* Handle Flow Control */ - fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - if (bus->flowcontrol != fcbits) { - if (~bus->flowcontrol & fcbits) - bus->sdcnt.fc_xoff++; - - if (bus->flowcontrol & ~fcbits) - bus->sdcnt.fc_xon++; - - bus->sdcnt.fc_rcvd++; - bus->flowcontrol = fcbits; - } - - /* Check and update sequence number */ - if (rxseq != seq) { - brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq); - bus->sdcnt.rx_badseq++; - rxseq = seq; + rd->len_left = rd->len > BRCMF_FIRSTREAD ? + rd->len - BRCMF_FIRSTREAD : 0; + head_read = BRCMF_FIRSTREAD; } - /* Check window for sanity */ - if ((u8) (txmax - bus->tx_seq) > 0x40) { - brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n", - txmax, bus->tx_seq); - txmax = bus->tx_seq + 2; - } - bus->tx_max = txmax; + brcmf_pad(bus, &pad, &rd->len_left); - /* Call a separate function for control frames */ - if (chan == SDPCM_CONTROL_CHANNEL) { - brcmf_sdbrcm_read_control(bus, bus->rxhdr, len, doff); - continue; - } - - /* precondition: chan is either SDPCM_DATA_CHANNEL, - SDPCM_EVENT_CHANNEL, SDPCM_TEST_CHANNEL or - SDPCM_GLOM_CHANNEL */ - - /* Length to read */ - rdlen = (len > BRCMF_FIRSTREAD) ? (len - BRCMF_FIRSTREAD) : 0; - - /* May pad read to blocksize for efficiency */ - if (bus->roundup && bus->blocksize && - (rdlen > bus->blocksize)) { - pad = bus->blocksize - (rdlen % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize) && - ((rdlen + pad + BRCMF_FIRSTREAD) < MAX_RX_DATASZ)) - rdlen += pad; - } else if (rdlen % BRCMF_SDALIGN) { - rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); - } - - /* Satisfy length-alignment requirements */ - if (rdlen & (ALIGNMENT - 1)) - rdlen = roundup(rdlen, ALIGNMENT); - - if ((rdlen + BRCMF_FIRSTREAD) > MAX_RX_DATASZ) { - /* Too long -- skip this frame */ - brcmf_dbg(ERROR, "too long: len %d rdlen %d\n", - len, rdlen); - bus->sdiodev->bus_if->dstats.rx_errors++; - bus->sdcnt.rx_toolong++; - brcmf_sdbrcm_rxfail(bus, false, false); - continue; - } - - pkt = brcmu_pkt_buf_get_skb(rdlen + - BRCMF_FIRSTREAD + BRCMF_SDALIGN); + pkt = brcmu_pkt_buf_get_skb(rd->len_left + head_read + + BRCMF_SDALIGN); if (!pkt) { /* Give up on data, request rtx of events */ - brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: rdlen %d chan %d\n", - rdlen, chan); + brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed\n"); bus->sdiodev->bus_if->dstats.rx_dropped++; - brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(chan)); + brcmf_sdbrcm_rxfail(bus, false, + RETRYCHAN(rd->channel)); continue; } + skb_pull(pkt, head_read); + pkt_align(pkt, rd->len_left, BRCMF_SDALIGN); - /* Leave room for what we already read, and align remainder */ - skb_pull(pkt, BRCMF_FIRSTREAD); - pkt_align(pkt, rdlen, BRCMF_SDALIGN); - - /* Read the remaining frame data */ sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, pkt); bus->sdcnt.f2rxdata++; if (sdret < 0) { - brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen, - ((chan == SDPCM_EVENT_CHANNEL) ? "event" - : ((chan == SDPCM_DATA_CHANNEL) ? "data" - : "test")), sdret); + brcmf_dbg(ERROR, "read %d bytes from channel %d failed: %d\n", + rd->len, rd->channel, sdret); brcmu_pkt_buf_free_skb(pkt); bus->sdiodev->bus_if->dstats.rx_errors++; - brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(chan)); + brcmf_sdbrcm_rxfail(bus, true, + RETRYCHAN(rd->channel)); continue; } - /* Copy the already-read portion */ - skb_push(pkt, BRCMF_FIRSTREAD); - memcpy(pkt->data, bus->rxhdr, BRCMF_FIRSTREAD); + if (head_read) { + skb_push(pkt, head_read); + memcpy(pkt->data, bus->rxhdr, head_read); + head_read = 0; + } else { + memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN); + rd_new.seq_num = rd->seq_num; + if (!brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new)) { + rd->len = 0; + brcmu_pkt_buf_free_skb(pkt); + } + bus->sdcnt.rx_readahead_cnt++; + if (rd->len != roundup(rd_new.len, 16)) { + brcmf_dbg(ERROR, "frame length mismatch:read %d, should be %d\n", + rd->len, + roundup(rd_new.len, 16) >> 4); + rd->len = 0; + brcmf_sdbrcm_rxfail(bus, true, true); + brcmu_pkt_buf_free_skb(pkt); + continue; + } + rd->len_nxtfrm = rd_new.len_nxtfrm; + rd->channel = rd_new.channel; + rd->dat_offset = rd_new.dat_offset; + + brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && + BRCMF_DATA_ON()) && + BRCMF_HDRS_ON(), + bus->rxhdr, SDPCM_HDRLEN, + "RxHdr:\n"); + + if (rd_new.channel == SDPCM_CONTROL_CHANNEL) { + brcmf_dbg(ERROR, "readahead on control packet %d?\n", + rd_new.seq_num); + /* Force retry w/normal header read */ + rd->len = 0; + brcmf_sdbrcm_rxfail(bus, false, true); + brcmu_pkt_buf_free_skb(pkt); + continue; + } + } brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), - pkt->data, len, "Rx Data:\n"); + pkt->data, rd->len, "Rx Data:\n"); -deliver: /* Save superframe descriptor and allocate packet frame */ - if (chan == SDPCM_GLOM_CHANNEL) { + if (rd->channel == SDPCM_GLOM_CHANNEL) { if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n", - len); + rd->len); brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), - pkt->data, len, + pkt->data, rd->len, "Glom Data:\n"); - __skb_trim(pkt, len); + __skb_trim(pkt, rd->len); skb_pull(pkt, SDPCM_HDRLEN); bus->glomd = pkt; } else { @@ -1919,12 +1755,23 @@ deliver: "descriptor!\n", __func__); brcmf_sdbrcm_rxfail(bus, false, false); } + /* prepare the descriptor for the next read */ + rd->len = rd->len_nxtfrm << 4; + rd->len_nxtfrm = 0; + /* treat all packet as event if we don't know */ + rd->channel = SDPCM_EVENT_CHANNEL; continue; } /* Fill in packet len and prio, deliver upward */ - __skb_trim(pkt, len); - skb_pull(pkt, doff); + __skb_trim(pkt, rd->len); + skb_pull(pkt, rd->dat_offset); + + /* prepare the descriptor for the next read */ + rd->len = rd->len_nxtfrm << 4; + rd->len_nxtfrm = 0; + /* treat all packet as event if we don't know */ + rd->channel = SDPCM_EVENT_CHANNEL; if (pkt->len == 0) { brcmu_pkt_buf_free_skb(pkt); @@ -1942,17 +1789,17 @@ deliver: brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt); down(&bus->sdsem); } + rxcount = maxframes - rxleft; /* Message if we hit the limit */ if (!rxleft) - brcmf_dbg(DATA, "hit rx limit of %d frames\n", - maxframes); + brcmf_dbg(DATA, "hit rx limit of %d frames\n", maxframes); else brcmf_dbg(DATA, "processed %d frames\n", rxcount); /* Back off rxseq if awaiting rtx, update rx_seq */ if (bus->rxskip) - rxseq--; - bus->rx_seq = rxseq; + rd->seq_num--; + bus->rx_seq = rd->seq_num; return rxcount; } @@ -2313,7 +2160,6 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) uint rxlimit = bus->rxbound; /* Rx frames to read before resched */ uint txlimit = bus->txbound; /* Tx frames to send before resched */ uint framecnt = 0; /* Temporary counter of tx/rx frames */ - bool rxdone = true; /* Flag for no more read data */ int err = 0, n; brcmf_dbg(TRACE, "Enter\n"); @@ -2431,8 +2277,8 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) /* On frame indication, read available frames */ if (PKT_AVAILABLE() && bus->clkstate == CLK_AVAIL) { - framecnt = brcmf_sdbrcm_readframes(bus, rxlimit, &rxdone); - if (rxdone || bus->rxskip) + framecnt = brcmf_sdio_readframes(bus, rxlimit); + if (!bus->rxpending) intstatus &= ~I_HMB_FRAME_IND; rxlimit -= min(framecnt, rxlimit); } @@ -2489,7 +2335,8 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) else if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && data_ok(bus)) { - framecnt = rxdone ? txlimit : min(txlimit, bus->txminmax); + framecnt = bus->rxpending ? min(txlimit, bus->txminmax) : + txlimit; framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt); txlimit -= framecnt; } @@ -4056,8 +3903,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) bus->rxbound = BRCMF_RXBOUND; bus->txminmax = BRCMF_TXMINMAX; bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; - bus->usebufpool = false; /* Use bufpool if allocated, - else use locally malloced rxbuf */ /* attempt to attach to the dongle */ if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) { -- cgit v1.2.3 From 95f59e8cbdf17aa5ba4db3fae3662c74640eed1b Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 19 Sep 2012 22:21:12 +0200 Subject: brcmfmac: remove unused function. clean up code. Reviewed-by: Arend Van Spriel Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index daaac4e2658d..83e29ff78724 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -4706,20 +4706,3 @@ s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev) return err; } -static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv, - u8 t, u8 l, u8 *v) -{ - struct brcmf_cfg80211_ie *ie = &cfg_priv->ie; - s32 err = 0; - - if (ie->offset + l + 2 > WL_TLV_INFO_MAX) { - WL_ERR("ei crosses buffer boundary\n"); - return -ENOSPC; - } - ie->buf[ie->offset] = t; - ie->buf[ie->offset + 1] = l; - memcpy(&ie->buf[ie->offset + 2], v, l); - ie->offset += l + 2; - - return err; -} -- cgit v1.2.3 From 3ba8137676eb3ca5db2df6cebc1125dd4d584292 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 19 Sep 2012 22:21:13 +0200 Subject: brcmfmac: fix bug in determining phy bands. This patch fixes a bug in routine where phy bands are determined. Reviewed-by: Arend Van Spriel Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 83e29ff78724..078e293c05ed 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -4539,7 +4539,7 @@ static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv) return err; } - phy = ((char *)&phy_list)[1]; + phy = ((char *)&phy_list)[0]; WL_INFO("%c phy\n", phy); if (phy == 'n' || phy == 'a') { wiphy = cfg_to_wiphy(cfg_priv); -- cgit v1.2.3 From 816432922bbbf67dec511711158738bfdaccb2e9 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 19 Sep 2012 22:21:14 +0200 Subject: brcmfmac: remove unused usb bmac model code. clean up code. Reviewed-by: Arend Van Spriel Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/usb.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index edb431182d10..246d06bb573a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -134,8 +134,6 @@ struct brcmf_usbdev_info { wait_queue_head_t ctrl_wait; ulong ctl_op; - bool rxctl_deferrespok; - struct urb *bulk_urb; /* used for FW download */ struct urb *intr_urb; /* URB for interrupt endpoint */ int intr_size; /* Size of interrupt message */ @@ -301,17 +299,9 @@ brcmf_usb_recv_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len) devinfo->ctl_read.wLength = cpu_to_le16p(&size); devinfo->ctl_urb->transfer_buffer_length = size; - if (devinfo->rxctl_deferrespok) { - /* BMAC model */ - devinfo->ctl_read.bRequestType = USB_DIR_IN - | USB_TYPE_VENDOR | USB_RECIP_INTERFACE; - devinfo->ctl_read.bRequest = DL_DEFER_RESP_OK; - } else { - /* full dongle model */ - devinfo->ctl_read.bRequestType = USB_DIR_IN - | USB_TYPE_CLASS | USB_RECIP_INTERFACE; - devinfo->ctl_read.bRequest = 1; - } + devinfo->ctl_read.bRequestType = USB_DIR_IN + | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + devinfo->ctl_read.bRequest = 1; usb_fill_control_urb(devinfo->ctl_urb, devinfo->usbdev, @@ -1312,8 +1302,6 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo, brcmf_dbg(ERROR, "usb_alloc_urb (ctl) failed\n"); goto error; } - devinfo->rxctl_deferrespok = 0; - devinfo->bulk_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!devinfo->bulk_urb) { brcmf_dbg(ERROR, "usb_alloc_urb (bulk) failed\n"); -- cgit v1.2.3 From 82d8eba358badb466a4e988ecabf0668a8d92e9c Mon Sep 17 00:00:00 2001 From: Piotr Haber Date: Wed, 19 Sep 2012 22:21:15 +0200 Subject: brcmsmac: don't start device when RfKill is engaged This patch fixes a bug when device is being started while RfKill switch is engaged, leading to hang due to partial initialization of hardware. Tested-by: Reviewed-by: Arend van Spriel Reviewed-by: Hante Meuleman Signed-off-by: Piotr Haber Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 718da8d6d658..a744ea5a9559 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -304,7 +304,10 @@ static int brcms_ops_start(struct ieee80211_hw *hw) wl->mute_tx = true; if (!wl->pub->up) - err = brcms_up(wl); + if (!blocked) + err = brcms_up(wl); + else + err = -ERFKILL; else err = -ENODEV; spin_unlock_bh(&wl->lock); -- cgit v1.2.3 From 6385df2db76c48d04530395a67c16b03afcc4095 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 19 Sep 2012 22:21:16 +0200 Subject: brcmfmac: clear control lock on usb error. On a usb error the lock bit should be cleared. Reviewed-by: Arend Van Spriel Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 246d06bb573a..5fe6ec7f838e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -337,6 +337,7 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len) err = brcmf_usb_send_ctl(devinfo, buf, len); if (err) { brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len); + clear_bit(0, &devinfo->ctl_op); return err; } @@ -367,6 +368,7 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len) err = brcmf_usb_recv_ctl(devinfo, buf, len); if (err) { brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len); + clear_bit(0, &devinfo->ctl_op); return err; } devinfo->ctl_completed = false; -- cgit v1.2.3 From 02030eb61d2737c7e6a2b75506b57608d86199c5 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 19 Sep 2012 22:21:17 +0200 Subject: brcmfmac: change struct brcmf_cfg80211_priv comments to kernel-doc Small step to fix structure commenting using kernel-doc syntax. Reviewed-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | 118 ++++++++++++++------- 1 file changed, 77 insertions(+), 41 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index b5c3fd942f59..a2138c185c65 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -376,51 +376,87 @@ struct brcmf_pno_scanresults_le { __le32 count; }; -/* dongle private data of cfg80211 interface */ +/** + * struct brcmf_cfg80211_priv - dongle private data of cfg80211 interface + * + * @wdev: representing wl cfg80211 device. + * @conf: dongle configuration. + * @scan_request: cfg80211 scan request object. + * @el: main event loop. + * @evt_q_list: used for event queue. + * @evt_q_lock: for event queue synchronization. + * @usr_sync: mainly for dongle up/down synchronization. + * @bss_list: bss_list holding scanned ap information. + * @scan_results: results of the last scan. + * @scan_req_int: internal scan request object. + * @bss_info: bss information for cfg80211 layer. + * @ie: information element object for internal purpose. + * @profile: holding dongle profile. + * @iscan: iscan controller information. + * @conn_info: association info. + * @pmk_list: wpa2 pmk list. + * @event_work: event handler work struct. + * @status: current dongle status. + * @pub: common driver information. + * @channel: current channel. + * @iscan_on: iscan on/off switch. + * @iscan_kickstart: indicate iscan already started. + * @active_scan: current scan mode. + * @sched_escan: e-scan for scheduled scan support running. + * @ibss_starter: indicates this sta is ibss starter. + * @link_up: link/connection up flag. + * @pwr_save: indicate whether dongle to support power save mode. + * @dongle_up: indicate whether dongle up or not. + * @roam_on: on/off switch for dongle self-roaming. + * @scan_tried: indicates if first scan attempted. + * @dcmd_buf: dcmd buffer. + * @extra_buf: mainly to grab assoc information. + * @debugfsdir: debugfs folder for this device. + * @escan_on: escan on/off switch. + * @escan_info: escan information. + * @escan_timeout: Timer for catch scan timeout. + * @escan_timeout_work: scan timeout worker. + * @escan_ioctl_buf: dongle command buffer for escan commands. + * @ci: used to link this structure to netdev private data. + */ struct brcmf_cfg80211_priv { - struct wireless_dev *wdev; /* representing wl cfg80211 device */ - struct brcmf_cfg80211_conf *conf; /* dongle configuration */ - struct cfg80211_scan_request *scan_request; /* scan request - object */ - struct brcmf_cfg80211_event_loop el; /* main event loop */ - struct list_head evt_q_list; /* used for event queue */ - spinlock_t evt_q_lock; /* for event queue synchronization */ - struct mutex usr_sync; /* maily for dongle up/down synchronization */ - struct brcmf_scan_results *bss_list; /* bss_list holding scanned - ap information */ + struct wireless_dev *wdev; + struct brcmf_cfg80211_conf *conf; + struct cfg80211_scan_request *scan_request; + struct brcmf_cfg80211_event_loop el; + struct list_head evt_q_list; + spinlock_t evt_q_lock; + struct mutex usr_sync; + struct brcmf_scan_results *bss_list; struct brcmf_scan_results *scan_results; - struct brcmf_cfg80211_scan_req *scan_req_int; /* scan request object - for internal purpose */ - struct wl_cfg80211_bss_info *bss_info; /* bss information for - cfg80211 layer */ - struct brcmf_cfg80211_ie ie; /* information element object for - internal purpose */ - struct brcmf_cfg80211_profile *profile; /* holding dongle profile */ - struct brcmf_cfg80211_iscan_ctrl *iscan; /* iscan controller */ - struct brcmf_cfg80211_connect_info conn_info; /* association info */ - struct brcmf_cfg80211_pmk_list *pmk_list; /* wpa2 pmk list */ - struct work_struct event_work; /* event handler work struct */ - unsigned long status; /* current dongle status */ + struct brcmf_cfg80211_scan_req *scan_req_int; + struct wl_cfg80211_bss_info *bss_info; + struct brcmf_cfg80211_ie ie; + struct brcmf_cfg80211_profile *profile; + struct brcmf_cfg80211_iscan_ctrl *iscan; + struct brcmf_cfg80211_connect_info conn_info; + struct brcmf_cfg80211_pmk_list *pmk_list; + struct work_struct event_work; + unsigned long status; void *pub; - u32 channel; /* current channel */ - bool iscan_on; /* iscan on/off switch */ - bool iscan_kickstart; /* indicate iscan already started */ - bool active_scan; /* current scan mode */ - bool sched_escan; /* e-scan for scheduled scan support running */ - bool ibss_starter; /* indicates this sta is ibss starter */ - bool link_up; /* link/connection up flag */ - bool pwr_save; /* indicate whether dongle to support - power save mode */ - bool dongle_up; /* indicate whether dongle up or not */ - bool roam_on; /* on/off switch for dongle self-roaming */ - bool scan_tried; /* indicates if first scan attempted */ - u8 *dcmd_buf; /* dcmd buffer */ - u8 *extra_buf; /* maily to grab assoc information */ + u32 channel; + bool iscan_on; + bool iscan_kickstart; + bool active_scan; + bool sched_escan; + bool ibss_starter; + bool link_up; + bool pwr_save; + bool dongle_up; + bool roam_on; + bool scan_tried; + u8 *dcmd_buf; + u8 *extra_buf; struct dentry *debugfsdir; - bool escan_on; /* escan on/off switch */ - struct escan_info escan_info; /* escan information */ - struct timer_list escan_timeout; /* Timer for catch scan timeout */ - struct work_struct escan_timeout_work; /* scan timeout worker */ + bool escan_on; + struct escan_info escan_info; + struct timer_list escan_timeout; + struct work_struct escan_timeout_work; u8 *escan_ioctl_buf; u8 ci[0] __aligned(NETDEV_ALIGN); }; -- cgit v1.2.3 From ee928381ec9ec089c4ac35e7aeaaeb5bc4ccd938 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 19 Sep 2012 22:21:18 +0200 Subject: brcmfmac: get rid of void pointer in struct brcmf_cfg80211_priv Field 'pub' in struct brcmf_cfg80211_priv was types as void pointer and filled with parameter passed in brcmf_cfg80211_attach(). This patch makes the type specific, ie. struct brcmf_pub. Reviewed-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 4 ++-- drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 078e293c05ed..e40cfe846a48 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -4266,7 +4266,7 @@ static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv) struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, struct device *busdev, - void *data) + struct brcmf_pub *drvr) { struct wireless_dev *wdev; struct brcmf_cfg80211_priv *cfg_priv; @@ -4291,7 +4291,7 @@ struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS); cfg_priv = wdev_to_cfg(wdev); cfg_priv->wdev = wdev; - cfg_priv->pub = data; + cfg_priv->pub = drvr; ci = (struct brcmf_cfg80211_iface *)&cfg_priv->ci; ci->cfg_priv = cfg_priv; ndev->ieee80211_ptr = wdev; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index a2138c185c65..52e408ed6f41 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -438,7 +438,7 @@ struct brcmf_cfg80211_priv { struct brcmf_cfg80211_pmk_list *pmk_list; struct work_struct event_work; unsigned long status; - void *pub; + struct brcmf_pub *pub; u32 channel; bool iscan_on; bool iscan_kickstart; @@ -497,7 +497,7 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_priv *cfg) extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, struct device *busdev, - void *data); + struct brcmf_pub *drvr); extern void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg); /* event handler from dongle */ -- cgit v1.2.3 From 22c22d2710ab828ea36487abd1d7f94f79a86a68 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 20 Sep 2012 20:23:17 -0700 Subject: mwifiex: disconnect the device before entering suspend state By default, device is disconnected before entering suspend state. User can keep the connection alive by using module parameter "disconect_on_suspend=0". Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sta_ioctl.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index d7ad2d4a069f..731562f026f5 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -26,6 +26,9 @@ #include "11n.h" #include "cfg80211.h" +static int disconnect_on_suspend = 1; +module_param(disconnect_on_suspend, int, 0644); + /* * Copies the multicast address list from device to driver. * @@ -448,6 +451,16 @@ EXPORT_SYMBOL_GPL(mwifiex_cancel_hs); int mwifiex_enable_hs(struct mwifiex_adapter *adapter) { struct mwifiex_ds_hs_cfg hscfg; + struct mwifiex_private *priv; + int i; + + if (disconnect_on_suspend) { + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv) + mwifiex_deauthenticate(priv, NULL); + } + } if (adapter->hs_activated) { dev_dbg(adapter->dev, "cmd: HS Already actived\n"); -- cgit v1.2.3 From de09364eca2fc79f8585d4d476a60c6730664098 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 20 Sep 2012 20:23:18 -0700 Subject: mwifiex: block scan request during heavy Tx traffic Currently scan operation is delayed/aborted based on Tx traffic consistency. This decision is taken after receiving scan response of first scan command from FW. But when heavy traffic is running, we can not even afford to send first scan command and go off channel for 30msec. We will block scan request in this case. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 6 ++++++ drivers/net/wireless/mwifiex/main.h | 2 ++ 2 files changed, 8 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index b9f7b3e6912d..aa619186d9b6 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1502,6 +1502,12 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); + if (atomic_read(&priv->wmm.tx_pkts_queued) >= + MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN) { + dev_dbg(priv->adapter->dev, "scan rejected due to traffic\n"); + return -EBUSY; + } + priv->scan_request = request; priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 12ceea47b4b4..92e57f653a3b 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -91,6 +91,8 @@ enum { #define MWIFIEX_MAX_EMPTY_TX_Q_CNT 10 #define MWIFIEX_SCAN_DELAY_MSEC 20 +#define MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN 2 + #define RSN_GTK_OUI_OFFSET 2 #define MWIFIEX_OUI_NOT_PRESENT 0 -- cgit v1.2.3 From 3fc7bc8ea792b4c55f53fccb589749d05c31569c Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Fri, 21 Sep 2012 12:02:02 +0200 Subject: ipw2x00: silence GCC warning for unused variable 'dev' Building the libipw component without CONFIG_LIBIPW_DEBUG set triggers this GCC warning: drivers/net/wireless/ipw2x00/libipw_wx.c:526:21: warning: unused variable 'dev' [-Wunused-variable] The cause of this warning is that, without CONFIG_LIBIPW_DEBUG set, LIBIPW_DEBUG_WX compiles away. Fix it by substituting ieee->dev for (its equivalent) dev. Signed-off-by: Paul Bolle Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/libipw_wx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c index 1571505b1a38..54aba4744438 100644 --- a/drivers/net/wireless/ipw2x00/libipw_wx.c +++ b/drivers/net/wireless/ipw2x00/libipw_wx.c @@ -675,7 +675,7 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee, } done: if (ieee->set_security) - ieee->set_security(ieee->dev, &sec); + ieee->set_security(dev, &sec); return ret; } -- cgit v1.2.3 From 742e7a932273bbb7f7a206c2c22faa3794262132 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Sep 2012 11:57:17 +0200 Subject: iwlegacy: use eth_broadcast_addr Instead of copying from a constant array (which is still needed for other purposes) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index eb9987520d61..318ed3c9fe74 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -1586,9 +1586,9 @@ il_fill_probe_req(struct il_priv *il, struct ieee80211_mgmt *frame, return 0; frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - memcpy(frame->da, il_bcast_addr, ETH_ALEN); + eth_broadcast_addr(frame->da); memcpy(frame->sa, ta, ETH_ALEN); - memcpy(frame->bssid, il_bcast_addr, ETH_ALEN); + eth_broadcast_addr(frame->bssid); frame->seq_ctrl = 0; len += 24; -- cgit v1.2.3 From 960334a7d33ecd54ba5337275dc4ea701d1dbf5e Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 8 Sep 2012 01:48:19 +0200 Subject: p54: connect to 11w protected networks Previously, it was not possible to connect to networks which requires 11w to be supported by the stations. Note: As all current (and old) firmwares corrupt incoming, protected management frames, the decryption offloading needs to be disabled. This will be done automatically if needed. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 2969d5321ca6..aadda99989c0 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -515,6 +515,17 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, if (modparam_nohwcrypt) return -EOPNOTSUPP; + if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) { + /* + * Unfortunately most/all firmwares are trying to decrypt + * incoming management frames if a suitable key can be found. + * However, in doing so the data in these frames gets + * corrupted. So, we can't have firmware supported crypto + * offload in this case. + */ + return -EOPNOTSUPP; + } + mutex_lock(&priv->conf_mutex); if (cmd == SET_KEY) { switch (key->cipher) { @@ -738,6 +749,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | + IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_REPORTS_TX_ACK_STATUS; dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | -- cgit v1.2.3 From e37b674156b9d5cd87025f0b4719d60e4ac6060c Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 2 Sep 2012 14:25:50 +0200 Subject: carl9170: connect to 11w protected networks Previously, it was not possible to connect to networks which requires 11w to be supported by the stations. While the documentation hints that there's some hardware support for offloading MFP "decryption", this simple implementation relies on the mac80211 stack to do the actual crypto operations. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/mac.c | 3 ++- drivers/net/wireless/ath/carl9170/main.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c index f8676280dc36..e3b1b6e87760 100644 --- a/drivers/net/wireless/ath/carl9170/mac.c +++ b/drivers/net/wireless/ath/carl9170/mac.c @@ -304,7 +304,8 @@ int carl9170_set_operating_mode(struct ar9170 *ar) struct ath_common *common = &ar->common; u8 *mac_addr, *bssid; u32 cam_mode = AR9170_MAC_CAM_DEFAULTS; - u32 enc_mode = AR9170_MAC_ENCRYPTION_DEFAULTS; + u32 enc_mode = AR9170_MAC_ENCRYPTION_DEFAULTS | + AR9170_MAC_ENCRYPTION_MGMT_RX_SOFTWARE; u32 rx_ctrl = AR9170_MAC_RX_CTRL_DEAGG | AR9170_MAC_RX_CTRL_SHORT_FILTER; u32 sniffer = AR9170_MAC_SNIFFER_DEFAULTS; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 18554ab76733..67997b39aba7 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1149,6 +1149,7 @@ static int carl9170_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, break; case WLAN_CIPHER_SUITE_CCMP: ktype = AR9170_ENC_ALG_AESCCMP; + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; break; default: return -EOPNOTSUPP; @@ -1780,6 +1781,7 @@ void *carl9170_alloc(size_t priv_size) hw->wiphy->interface_modes = 0; hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | -- cgit v1.2.3 From 90e6274d2ecf3bcb44e3727a395e56b7ef467218 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Fri, 14 Sep 2012 18:26:11 +0800 Subject: ath5k: disable HW crypto in management frame Hardware support for MFP is not available in ath5k. Thus, this implementation allows the mac80211 stack to do the actuall crypto operation. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 1 + drivers/net/wireless/ath/ath5k/mac80211-ops.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index a0a202de1109..9fd6d9a9942e 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2446,6 +2446,7 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_REPORTS_TX_ACK_STATUS; hw->wiphy->interface_modes = diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 4e6b39be43ff..7a28538e6e05 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -489,6 +489,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (ath5k_modparam_nohwcrypt) return -EOPNOTSUPP; + if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) + return -EOPNOTSUPP; + if (vif->type == NL80211_IFTYPE_ADHOC && (key->cipher == WLAN_CIPHER_SUITE_TKIP || key->cipher == WLAN_CIPHER_SUITE_CCMP) && -- cgit v1.2.3 From 046b6802c8d3c8a57448485513bf7291633e0fa3 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 22 Sep 2012 00:14:28 +0530 Subject: ath9k: Disable ASPM only for AR9285 Currently, ASPM is disabled for all WLAN+BT combo chipsets when BTCOEX is enabled. This is incorrect since the workaround is required only for WB195, which is a AR9285+AR3011 combo solution. Fix this by checking for the HW version when enabling the workaround. Cc: stable@vger.kernel.org Signed-off-by: Sujith Manoharan Tested-by: Paul Stewart Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index a8f6126f6b2d..c0c599673eeb 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -128,8 +128,9 @@ static void ath_pci_aspm_init(struct ath_common *common) if (!parent) return; - if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { - /* Bluetooth coexistance requires disabling ASPM. */ + if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) && + (AR_SREV_9285(ah))) { + /* Bluetooth coexistance requires disabling ASPM for AR9285. */ pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &aspm); aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); pci_write_config_byte(pdev, pos + PCI_EXP_LNKCTL, aspm); -- cgit v1.2.3 From fd0fc5218dc31d446fd108a6a571702a7c9bec29 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 23 Sep 2012 19:33:00 +0300 Subject: mwifiex: potential corruption in mwifiex_update_uap_custom_ie() ap_custom_ie is a struct mwifiex_ie_list which is quite different and also larger than struct mwifiex_ie. It's a difference between 4196 bytes and 262. Signed-off-by: Dan Carpenter Tested-by: Stone Piao Acked-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/ie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index 1d8dd003e396..fa3a80fb8c01 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -160,7 +160,7 @@ mwifiex_update_uap_custom_ie(struct mwifiex_private *priv, u16 len; int ret; - ap_custom_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); + ap_custom_ie = kzalloc(sizeof(*ap_custom_ie), GFP_KERNEL); if (!ap_custom_ie) return -ENOMEM; -- cgit v1.2.3 From 3e4c4151e56ff367fb1487ea79134eea74104077 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sun, 23 Sep 2012 20:22:53 +0200 Subject: rt2x00: Deprecate max_sta_intf field of struct rt2x00_ops. All drivers set this value to 1, so there is no need (currently) to let drivers set this. Therefor, remove the field; we can always add it back when it is needed. Inspired by an earlier patch from Paul Fertser. Signed-off-by: Gertjan van Wingerde Cc: Paul Fertser Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 1 - drivers/net/wireless/rt2x00/rt2500pci.c | 1 - drivers/net/wireless/rt2x00/rt2500usb.c | 1 - drivers/net/wireless/rt2x00/rt2800pci.c | 1 - drivers/net/wireless/rt2x00/rt2800usb.c | 1 - drivers/net/wireless/rt2x00/rt2x00.h | 1 - drivers/net/wireless/rt2x00/rt2x00mac.c | 5 ++--- drivers/net/wireless/rt2x00/rt61pci.c | 1 - drivers/net/wireless/rt2x00/rt73usb.c | 1 - 9 files changed, 2 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 6458ab87717b..e3a2d9070cf6 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1789,7 +1789,6 @@ static const struct data_queue_desc rt2400pci_queue_atim = { static const struct rt2x00_ops rt2400pci_ops = { .name = KBUILD_MODNAME, - .max_sta_intf = 1, .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 68bca1456cda..479d756e275b 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -2081,7 +2081,6 @@ static const struct data_queue_desc rt2500pci_queue_atim = { static const struct rt2x00_ops rt2500pci_ops = { .name = KBUILD_MODNAME, - .max_sta_intf = 1, .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index f95b5516c50a..a12e84f892be 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1896,7 +1896,6 @@ static const struct data_queue_desc rt2500usb_queue_atim = { static const struct rt2x00_ops rt2500usb_ops = { .name = KBUILD_MODNAME, - .max_sta_intf = 1, .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 391e08fa054b..27829e1e2e38 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1088,7 +1088,6 @@ static const struct data_queue_desc rt2800pci_queue_bcn = { static const struct rt2x00_ops rt2800pci_ops = { .name = KBUILD_MODNAME, .drv_data_size = sizeof(struct rt2800_drv_data), - .max_sta_intf = 1, .max_ap_intf = 8, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 603b65d6f28b..c9e9370eb789 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -870,7 +870,6 @@ static const struct data_queue_desc rt2800usb_queue_bcn = { static const struct rt2x00_ops rt2800usb_ops = { .name = KBUILD_MODNAME, .drv_data_size = sizeof(struct rt2800_drv_data), - .max_sta_intf = 1, .max_ap_intf = 8, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 49375c86c334..09bf01ce65f4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -656,7 +656,6 @@ struct rt2x00lib_ops { struct rt2x00_ops { const char *name; const unsigned int drv_data_size; - const unsigned int max_sta_intf; const unsigned int max_ap_intf; const unsigned int eeprom_size; const unsigned int rf_size; diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c3d0f2f87b69..2f98d3d4a979 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -243,10 +243,9 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, return -ENOBUFS; /* - * Check if we exceeded the maximum amount - * of supported interfaces. + * We don't support multiple STA interfaces. */ - if (rt2x00dev->intf_sta_count >= rt2x00dev->ops->max_sta_intf) + if (rt2x00dev->intf_sta_count) return -ENOBUFS; break; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 2673e058caaf..d6582a2fa353 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -3045,7 +3045,6 @@ static const struct data_queue_desc rt61pci_queue_bcn = { static const struct rt2x00_ops rt61pci_ops = { .name = KBUILD_MODNAME, - .max_sta_intf = 1, .max_ap_intf = 4, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index cfa9f37cccc2..e5eb43b3eee7 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2382,7 +2382,6 @@ static const struct data_queue_desc rt73usb_queue_bcn = { static const struct rt2x00_ops rt73usb_ops = { .name = KBUILD_MODNAME, - .max_sta_intf = 1, .max_ap_intf = 4, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, -- cgit v1.2.3 From 55d2e9da744ba11eae900b4bfc2da72eace3c1e1 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sun, 23 Sep 2012 20:22:54 +0200 Subject: rt2x00: Replace open coded interface checking with interface combinations. Mac80211 has formal infrastructure to specify which interface combinations are supported. Make use of this facility in favor of open coding it ourselves. So far we only have to specify we can support multiple AP interfaces, no other combinations are supported. Inspired by an earlier patch from Paul Fertser. Signed-off-by: Gertjan van Wingerde Cc: Paul Fertser Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 14 ++++++++++++ drivers/net/wireless/rt2x00/rt2x00dev.c | 33 ++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00mac.c | 39 --------------------------------- 3 files changed, 47 insertions(+), 39 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 09bf01ce65f4..0751b35ef6dc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -740,6 +740,14 @@ enum rt2x00_capability_flags { CAPABILITY_VCO_RECALIBRATION, }; +/* + * Interface combinations + */ +enum { + IF_COMB_AP = 0, + NUM_IF_COMB, +}; + /* * rt2x00 device structure. */ @@ -866,6 +874,12 @@ struct rt2x00_dev { unsigned int intf_associated; unsigned int intf_beaconing; + /* + * Interface combinations + */ + struct ieee80211_iface_limit if_limits_ap; + struct ieee80211_iface_combination if_combinations[NUM_IF_COMB]; + /* * Link quality */ diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 10cf67267775..69097d1faeb6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1118,6 +1118,34 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) rt2x00dev->intf_associated = 0; } +static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev) +{ + struct ieee80211_iface_limit *if_limit; + struct ieee80211_iface_combination *if_combination; + + /* + * Build up AP interface limits structure. + */ + if_limit = &rt2x00dev->if_limits_ap; + if_limit->max = rt2x00dev->ops->max_ap_intf; + if_limit->types = BIT(NL80211_IFTYPE_AP); + + /* + * Build up AP interface combinations structure. + */ + if_combination = &rt2x00dev->if_combinations[IF_COMB_AP]; + if_combination->limits = if_limit; + if_combination->n_limits = 1; + if_combination->max_interfaces = if_limit->max; + if_combination->num_different_channels = 1; + + /* + * Finally, specify the possible combinations to mac80211. + */ + rt2x00dev->hw->wiphy->iface_combinations = rt2x00dev->if_combinations; + rt2x00dev->hw->wiphy->n_iface_combinations = 1; +} + /* * driver allocation handlers. */ @@ -1125,6 +1153,11 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) { int retval = -ENOMEM; + /* + * Set possible interface combinations. + */ + rt2x00lib_set_if_combinations(rt2x00dev); + /* * Allocate the driver data memory, if necessary. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 2f98d3d4a979..98a9e48f8e4a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -214,45 +214,6 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return -ENODEV; - switch (vif->type) { - case NL80211_IFTYPE_AP: - /* - * We don't support mixed combinations of - * sta and ap interfaces. - */ - if (rt2x00dev->intf_sta_count) - return -ENOBUFS; - - /* - * Check if we exceeded the maximum amount - * of supported interfaces. - */ - if (rt2x00dev->intf_ap_count >= rt2x00dev->ops->max_ap_intf) - return -ENOBUFS; - - break; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_WDS: - /* - * We don't support mixed combinations of - * sta and ap interfaces. - */ - if (rt2x00dev->intf_ap_count) - return -ENOBUFS; - - /* - * We don't support multiple STA interfaces. - */ - if (rt2x00dev->intf_sta_count) - return -ENOBUFS; - - break; - default: - return -EINVAL; - } - /* * Loop through all beacon queues to find a free * entry. Since there are as much beacon entries -- cgit v1.2.3 From a50d1fd4525162732b45db7a372e868933746a4e Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 24 Sep 2012 14:04:24 +0530 Subject: ath9k_hw: fix BT sleep state on chip wakeup Whenever both WLAN and BT in/out sleep mode, sometimes WLAN is not able to take back the shared LNA control after resumes from sleep mode. The idea is that for WLAN to check if BT owns LNA control and BT is in sleep mode when WLAN just resumes from sleep mode. If the condition is true, do a BTCOEX_RC_WARM_RESET for WLAN to take back the control of shared LNA. Now the issue is the BT sleep value read from MCI register is overlooked by assigning u32 into u8. Hence the above condition never be met so that WLAN used to report beacon losses and frequent connection drops. Signed-off-by: Rajkumar Manoharan Tested-by: Paul Stewart Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 8d8df4b2c386..8dbb60b53f1a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -1289,7 +1289,7 @@ void ar9003_mci_set_power_awake(struct ath_hw *ah) } REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18))); lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3; - bt_sleep = REG_READ(ah, AR_MCI_RX_STATUS) & AR_MCI_RX_REMOTE_SLEEP; + bt_sleep = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_REMOTE_SLEEP); REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2); REG_WRITE(ah, AR_DIAG_SW, diag_sw); -- cgit v1.2.3 From 944f8a1a6f5ff8b503f3544811d0aa4ac27dd2aa Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 24 Sep 2012 14:30:19 -0400 Subject: ath5k: add missing breaks in ath5k_hw_set_spur_mitigation_filter https://bugzilla.kernel.org/show_bug.cgi?id=47681 Reported-by: David Binderman Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/phy.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 01c90ed58453..ab363f34b4df 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1975,11 +1975,13 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, spur_delta_phase = (spur_offset << 18) / 25; spur_freq_sigma_delta = (spur_delta_phase >> 10); symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 2; + break; case AR5K_BWMODE_5MHZ: /* Both sample_freq and chip_freq are 10MHz (?) */ spur_delta_phase = (spur_offset << 19) / 25; spur_freq_sigma_delta = (spur_delta_phase >> 10); symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4; + break; default: if (channel->band == IEEE80211_BAND_5GHZ) { /* Both sample_freq and chip_freq are 40MHz */ -- cgit v1.2.3