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') 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') 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 9712ba0bec83579ae63e4d61f79e18c7d0d9d3fd Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 7 Aug 2012 10:37:45 +0530 Subject: Bluetooth: Use module_platform_driver() in btwilink.c file module_platform_driver() makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btwilink.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c index 4ad7b35cfc0e..60abf596f60e 100644 --- a/drivers/bluetooth/btwilink.c +++ b/drivers/bluetooth/btwilink.c @@ -358,21 +358,7 @@ static struct platform_driver btwilink_driver = { }, }; -/* ------- Module Init/Exit interfaces ------ */ -static int __init btwilink_init(void) -{ - BT_INFO("Bluetooth Driver for TI WiLink - Version %s", VERSION); - - return platform_driver_register(&btwilink_driver); -} - -static void __exit btwilink_exit(void) -{ - platform_driver_unregister(&btwilink_driver); -} - -module_init(btwilink_init); -module_exit(btwilink_exit); +module_platform_driver(btwilink_driver); /* ------ Module Info ------ */ -- cgit v1.2.3 From 7923296f3f9eebbe3d7bb4c99d73bd7a226e0146 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 28 Aug 2012 21:12:48 +0800 Subject: Bluetooth: btmrvl: remove pointless conditional before kfree_skb() Remove pointless conditional before kfree_skb(). Signed-off-by: Wei Yongjun Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btmrvl_sdio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 03b3acba6143..3f4bfc814dc7 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -600,8 +600,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) exit: if (ret) { hdev->stat.err_rx++; - if (skb) - kfree_skb(skb); + kfree_skb(skb); } return ret; -- 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') 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') 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') 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') 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') 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') 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') 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 ce9b0048e167da5d0fe7c36518af427fbdec655d Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Fri, 7 Sep 2012 17:24:40 +0200 Subject: Bluetooth: bluecard_cs.c: removes unnecessary semicolon removes unnecessary semicolon Found by Coccinelle: http://coccinelle.lip6.fr/ Signed-off-by: Peter Senna Tschudin Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- drivers/bluetooth/bluecard_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 0c0838d9b56c..0d26851d6e49 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -681,7 +681,7 @@ static int bluecard_hci_send_frame(struct sk_buff *skb) case HCI_SCODATA_PKT: hdev->stat.sco_tx++; break; - }; + } /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); -- cgit v1.2.3 From a20890d079aa3130ca3f4e10da207cab9df4a2bb Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Fri, 7 Sep 2012 17:24:39 +0200 Subject: Bluetooth: hci_ldisc.c: removes unnecessary semicolon removes unnecessary semicolon Found by Coccinelle: http://coccinelle.lip6.fr/ Signed-off-by: Peter Senna Tschudin Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_ldisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 74e0966b3ead..c8abce3d2d9c 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -531,7 +531,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, default: err = n_tty_ioctl_helper(tty, file, cmd, arg); break; - }; + } return err; } -- cgit v1.2.3 From d650ccae2d6f82a7f5dc33aea6c55b4e25692190 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Fri, 7 Sep 2012 17:24:42 +0200 Subject: Bluetooth: hci_ll.c: removes unnecessary semicolon removes unnecessary semicolon Found by Coccinelle: http://coccinelle.lip6.fr/ Signed-off-by: Peter Senna Tschudin Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_ll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index ff6d589c34a5..cfc767938589 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -481,7 +481,7 @@ static int ll_recv(struct hci_uart *hu, void *data, int count) hu->hdev->stat.err_rx++; ptr++; count--; continue; - }; + } ptr++; count--; -- cgit v1.2.3 From 2c24d454060ae76d7fe2aed267944723001faeff Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Fri, 7 Sep 2012 17:24:47 +0200 Subject: Bluetooth: hci_vhci.c: removes unnecessary semicolon removes unnecessary semicolon Found by Coccinelle: http://coccinelle.lip6.fr/ Signed-off-by: Peter Senna Tschudin Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_vhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 3f72595a6017..d8b7aed6e4a9 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -156,7 +156,7 @@ static inline ssize_t vhci_put_user(struct vhci_data *data, case HCI_SCODATA_PKT: data->hdev->stat.sco_tx++; break; - }; + } return total; } -- cgit v1.2.3 From 5ad777958621524b48d1bdf4aaf3b26a363d4553 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Fri, 7 Sep 2012 17:24:48 +0200 Subject: Bluetooth: btuart_cs.c: removes unnecessary semicolon removes unnecessary semicolon Found by Coccinelle: http://coccinelle.lip6.fr/ Signed-off-by: Peter Senna Tschudin Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btuart_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 2f510a87b28f..35a553a90616 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -446,7 +446,7 @@ static int btuart_hci_send_frame(struct sk_buff *skb) case HCI_SCODATA_PKT: hdev->stat.sco_tx++; break; - }; + } /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); -- cgit v1.2.3 From ee66401bb94b1f2ce51089c341dcdd25d26ae631 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 15 Aug 2012 01:38:11 -0300 Subject: Bluetooth: Add USB_VENDOR_AND_INTERFACE_INFO() for Broadcom/Foxconn Foxconn devices has a vendor specific class of device, we will match them differently now. Cc: stable@vger.kernel.org Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index f637c2550016..f077f4d28ac9 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -101,7 +101,7 @@ static struct usb_device_id btusb_table[] = { { USB_DEVICE(0x413c, 0x8197) }, /* Foxconn - Hon Hai */ - { USB_DEVICE(0x0489, 0xe033) }, + { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) }, { } /* Terminating entry */ }; -- cgit v1.2.3 From 0c1abbd1aa0416258881c303a88e618cbca0759c Mon Sep 17 00:00:00 2001 From: Jaroslav Resler Date: Tue, 11 Sep 2012 17:25:32 +0800 Subject: Bluetooth: Add support for BCM20702A0 [04ca, 2003] Add another vendor specific ID for BCM20702A0. output of usb-devices: T: Bus=01 Lev=02 Prnt=02 Port=03 Cnt=02 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=04ca ProdID=2003 Rev= 1.12 S: Manufacturer=Broadcom Corp S: Product=BCM20702A0 S: SerialNumber=446D57861623 C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) Signed-off-by: Cho, Yu-Chen Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index f077f4d28ac9..75943c397ad7 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -93,6 +93,7 @@ static struct usb_device_id btusb_table[] = { { USB_DEVICE(0x0c10, 0x0000) }, /* Broadcom BCM20702A0 */ + { USB_DEVICE(0x04ca, 0x2003) }, { USB_DEVICE(0x0489, 0xe042) }, { USB_DEVICE(0x0a5c, 0x21e3) }, { USB_DEVICE(0x0a5c, 0x21e6) }, -- 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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 646e0827df85f1305eeebf2108e9daafeabe0e0d Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Fri, 21 Sep 2012 08:38:38 +0200 Subject: bcma: handle BCM43227 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Tested-by: Jack Signed-off-by: John W. Linville --- drivers/bcma/host_pci.c | 1 + drivers/bcma/sprom.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index f7b0af7100cd..b6b4b5ebd4c2 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -273,6 +273,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, { 0, }, diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 9ea4627dc0c2..0d546b64be34 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -507,7 +507,9 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus) /* for these chips OTP is always available */ present = true; break; + case BCMA_CHIP_ID_BCM43227: case BCMA_CHIP_ID_BCM43228: + case BCMA_CHIP_ID_BCM43428: present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT; break; default: -- 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') 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') 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') 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') 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') 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 5d50b364e61e85eb41938d25770db3aab5e07d82 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 17 Aug 2012 23:47:54 +0200 Subject: NFC: Queue pn533 commands Instead of returning EBUSY when getting a command while another one is running, we queue them. Upon completion of the pending command, the next one is processed. Besides the fact that it simplifies the pn533 locking scheme, it also comes with the nice side effect of fixing the following warning: [ 82.274297] ===================================== [ 82.274297] [ BUG: bad unlock balance detected! ] [ 82.274298] 3.5.0-rc1+ #1 Not tainted [ 82.274299] ------------------------------------- [ 82.274300] kworker/u:1/16 is trying to release lock (&dev->cmd_lock) at: [ 82.274305] [] mutex_unlock+0x9/0xb [ 82.274305] but there are no more locks to release! [ 82.274306] [ 82.274306] other info that might help us debug this: [ 82.274306] 2 locks held by kworker/u:1/16: [ 82.274311] #0: (pn533){.+.+..}, at: [] +process_one_work+0x145/0x2e2 [ 82.274314] #1: ((&dev->cmd_work)){+.+...}, at: [] +process_one_work+0x145/0x2e2 [ 82.274314] [ 82.274314] stack backtrace: [ 82.274315] Pid: 16, comm: kworker/u:1 Not tainted 3.5.0-rc1+ #1 [ 82.274315] Call Trace: [ 82.274317] [] ? mutex_unlock+0x9/0xb [ 82.274321] [] print_unlock_inbalance_bug+0xda/0xe4 [ 82.274323] [] lock_release_non_nested+0xb2/0x232 [ 82.274325] [] ? mark_held_locks+0x6d/0x95 [ 82.274326] [] ? mutex_unlock+0x9/0xb [ 82.274328] [] ? _raw_spin_unlock_irqrestore+0x40/0x5c [ 82.274329] [] ? mutex_unlock+0x9/0xb [ 82.274330] [] lock_release+0x176/0x1ac [ 82.274333] [] ? pn533_send_complete+0xa8/0xa8 [ 82.274334] [] __mutex_unlock_slowpath+0xb0/0x117 [ 82.274336] [] mutex_unlock+0x9/0xb [ 82.274337] [] pn533_wq_cmd_complete+0x51/0x55 [ 82.274338] [] process_one_work+0x1a3/0x2e2 [ 82.274340] [] ? process_one_work+0x145/0x2e2 [ 82.274341] [] worker_thread+0xcf/0x153 [ 82.274343] [] ? manage_workers.isra.22+0x16b/0x16b [ 82.274344] [] ? manage_workers.isra.22+0x16b/0x16b [ 82.274346] [] kthread+0x95/0x9d [ 82.274348] [] kernel_thread_helper+0x4/0x10 [ 82.274351] [] ? finish_task_switch+0x45/0xc3 [ 82.274352] [] ? retint_restore_args+0x13/0x13 [ 82.274353] [] ? __init_kthread_worker+0x55/0x55 [ 82.274354] [] ? gs_change+0x13/0x13 Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 102 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 85 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index d606f52fec84..7ceea111439b 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -356,6 +356,7 @@ struct pn533 { struct workqueue_struct *wq; struct work_struct cmd_work; + struct work_struct cmd_complete_work; struct work_struct poll_work; struct work_struct mi_work; struct work_struct tg_work; @@ -383,6 +384,19 @@ struct pn533 { u8 tgt_mode; u32 device_type; + + struct list_head cmd_queue; + u8 cmd_pending; +}; + +struct pn533_cmd { + struct list_head queue; + struct pn533_frame *out_frame; + struct pn533_frame *in_frame; + int in_frame_len; + pn533_cmd_complete_t cmd_complete; + void *arg; + gfp_t flags; }; struct pn533_frame { @@ -487,7 +501,7 @@ static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd) static void pn533_wq_cmd_complete(struct work_struct *work) { - struct pn533 *dev = container_of(work, struct pn533, cmd_work); + struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work); struct pn533_frame *in_frame; int rc; @@ -502,7 +516,7 @@ static void pn533_wq_cmd_complete(struct work_struct *work) PN533_FRAME_CMD_PARAMS_LEN(in_frame)); if (rc != -EINPROGRESS) - mutex_unlock(&dev->cmd_lock); + queue_work(dev->wq, &dev->cmd_work); } static void pn533_recv_response(struct urb *urb) @@ -550,7 +564,7 @@ static void pn533_recv_response(struct urb *urb) dev->wq_in_frame = in_frame; sched_wq: - queue_work(dev->wq, &dev->cmd_work); + queue_work(dev->wq, &dev->cmd_complete_work); } static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags) @@ -606,7 +620,7 @@ static void pn533_recv_ack(struct urb *urb) sched_wq: dev->wq_in_frame = NULL; - queue_work(dev->wq, &dev->cmd_work); + queue_work(dev->wq, &dev->cmd_complete_work); } static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags) @@ -669,6 +683,31 @@ error: return rc; } +static void pn533_wq_cmd(struct work_struct *work) +{ + struct pn533 *dev = container_of(work, struct pn533, cmd_work); + struct pn533_cmd *cmd; + + mutex_lock(&dev->cmd_lock); + + if (list_empty(&dev->cmd_queue)) { + dev->cmd_pending = 0; + mutex_unlock(&dev->cmd_lock); + return; + } + + cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue); + + mutex_unlock(&dev->cmd_lock); + + __pn533_send_cmd_frame_async(dev, cmd->out_frame, cmd->in_frame, + cmd->in_frame_len, cmd->cmd_complete, + cmd->arg, cmd->flags); + + list_del(&cmd->queue); + kfree(cmd); +} + static int pn533_send_cmd_frame_async(struct pn533 *dev, struct pn533_frame *out_frame, struct pn533_frame *in_frame, @@ -676,22 +715,44 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev, pn533_cmd_complete_t cmd_complete, void *arg, gfp_t flags) { + struct pn533_cmd *cmd; int rc; nfc_dev_dbg(&dev->interface->dev, "%s", __func__); - if (!mutex_trylock(&dev->cmd_lock)) - return -EBUSY; + mutex_lock(&dev->cmd_lock); - rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame, - in_frame_len, cmd_complete, arg, flags); - if (rc) - goto error; + if (!dev->cmd_pending) { + rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame, + in_frame_len, cmd_complete, + arg, flags); + if (!rc) + dev->cmd_pending = 1; + + mutex_unlock(&dev->cmd_lock); + + return rc; + } + + nfc_dev_dbg(&dev->interface->dev, "%s Queueing command", __func__); + + cmd = kzalloc(sizeof(struct pn533_cmd), flags); + if (!cmd) + return -ENOMEM; + + INIT_LIST_HEAD(&cmd->queue); + cmd->out_frame = out_frame; + cmd->in_frame = in_frame; + cmd->in_frame_len = in_frame_len; + cmd->cmd_complete = cmd_complete; + cmd->arg = arg; + cmd->flags = flags; + + list_add_tail(&cmd->queue, &dev->cmd_queue); - return 0; -error: mutex_unlock(&dev->cmd_lock); - return rc; + + return 0; } struct pn533_sync_cmd_response { @@ -1305,8 +1366,6 @@ static void pn533_listen_mode_timer(unsigned long data) dev->cancel_listen = 1; - mutex_unlock(&dev->cmd_lock); - pn533_poll_next_mod(dev); queue_work(dev->wq, &dev->poll_work); @@ -2131,7 +2190,7 @@ error_cmd: kfree(arg); - mutex_unlock(&dev->cmd_lock); + queue_work(dev->wq, &dev->cmd_work); } static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, @@ -2330,7 +2389,8 @@ static int pn533_probe(struct usb_interface *interface, NULL, 0, pn533_send_complete, dev); - INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete); + INIT_WORK(&dev->cmd_work, pn533_wq_cmd); + INIT_WORK(&dev->cmd_complete_work, pn533_wq_cmd_complete); INIT_WORK(&dev->mi_work, pn533_wq_mi_recv); INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data); INIT_WORK(&dev->poll_work, pn533_wq_poll); @@ -2346,6 +2406,8 @@ static int pn533_probe(struct usb_interface *interface, skb_queue_head_init(&dev->resp_q); + INIT_LIST_HEAD(&dev->cmd_queue); + usb_set_intfdata(interface, dev); pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION); @@ -2417,6 +2479,7 @@ error: static void pn533_disconnect(struct usb_interface *interface) { struct pn533 *dev; + struct pn533_cmd *cmd, *n; dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); @@ -2433,6 +2496,11 @@ static void pn533_disconnect(struct usb_interface *interface) del_timer(&dev->listen_timer); + list_for_each_entry_safe(cmd, n, &dev->cmd_queue, queue) { + list_del(&cmd->queue); + kfree(cmd); + } + kfree(dev->in_frame); usb_free_urb(dev->in_urb); kfree(dev->out_frame); -- cgit v1.2.3 From 058576ddfb31762bfce70086a3c12678a97c4d75 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Wed, 15 Aug 2012 14:04:10 +0530 Subject: NFC: Use module_platform_driver macro for nfcwilink.c Simplify the code by make use of module_platform_driver macro. Signed-off-by: Syam Sidhardhan Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcwilink.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c index e7fd4938f9bc..827f039ceaf5 100644 --- a/drivers/nfc/nfcwilink.c +++ b/drivers/nfc/nfcwilink.c @@ -604,21 +604,7 @@ static struct platform_driver nfcwilink_driver = { }, }; -/* ------- Module Init/Exit interfaces ------ */ -static int __init nfcwilink_init(void) -{ - printk(KERN_INFO "NFC Driver for TI WiLink"); - - return platform_driver_register(&nfcwilink_driver); -} - -static void __exit nfcwilink_exit(void) -{ - platform_driver_unregister(&nfcwilink_driver); -} - -module_init(nfcwilink_init); -module_exit(nfcwilink_exit); +module_platform_driver(nfcwilink_driver); /* ------ Module Info ------ */ -- cgit v1.2.3 From 58637c9b65300cbdf9fb7c037978daadd136be86 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 22 Aug 2012 16:28:46 -0700 Subject: NFC: Don't use WQ_MEM_RECLAIM for pn533 NFC driver doesn't sit in memory reclaim path and has no reason to use WQ_MEM_RECLAIM. Drop WQ_MEM_RECLAIM from pn533->wq and use alloc_ordered_workqueue() instead of WQ_UNBOUND w/ max_active == 1. Signed-off-by: Tejun Heo Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 7ceea111439b..d123444404c8 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -2394,9 +2394,7 @@ static int pn533_probe(struct usb_interface *interface, INIT_WORK(&dev->mi_work, pn533_wq_mi_recv); INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data); INIT_WORK(&dev->poll_work, pn533_wq_poll); - dev->wq = alloc_workqueue("pn533", - WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, - 1); + dev->wq = alloc_ordered_workqueue("pn533", 0); if (dev->wq == NULL) goto error; -- cgit v1.2.3 From f2ce39828abd556814366c2483191a7213c764f2 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Sat, 25 Aug 2012 00:40:16 +0200 Subject: NFC: Set the IRQF_ONESHOT flag from the pn544_hci IRQ handler request As we don't have a primary handler but only a threaded one, __setup_irq() ends up failing if we don't set this flag. Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544_hci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c index aa71807189ba..9458d53cdb59 100644 --- a/drivers/nfc/pn544_hci.c +++ b/drivers/nfc/pn544_hci.c @@ -848,8 +848,8 @@ static int __devinit pn544_hci_probe(struct i2c_client *client, pn544_hci_platform_init(info); r = request_threaded_irq(client->irq, NULL, pn544_hci_irq_thread_fn, - IRQF_TRIGGER_RISING, PN544_HCI_DRIVER_NAME, - info); + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + PN544_HCI_DRIVER_NAME, info); if (r < 0) { dev_err(&client->dev, "Unable to register IRQ handler\n"); goto err_rti; -- cgit v1.2.3 From ade672082dd35aaaf7c8630d16c9f795c30459c4 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Fri, 7 Sep 2012 11:08:29 +0200 Subject: NFC: Remove crc generation from shdlc layer Checksum is specific for a chip spcification and it varies (in size and type) between different hardware. It should be handled in the driver then. Moreover, shdlc spec doesn't mention crc as a part of the frame. Update pn544_hci driver as well. Signed-off-by: Waldemar Rymarkiewicz Acked-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544_hci.c | 32 ++++++++++++++++++++++++++++++-- net/nfc/hci/shdlc.c | 27 ++------------------------- 2 files changed, 32 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c index 9458d53cdb59..d90aecfce739 100644 --- a/drivers/nfc/pn544_hci.c +++ b/drivers/nfc/pn544_hci.c @@ -128,6 +128,8 @@ static struct nfc_hci_gate pn544_gates[] = { /* Largest headroom needed for outgoing custom commands */ #define PN544_CMDS_HEADROOM 2 +#define PN544_FRAME_HEADROOM 1 +#define PN544_FRAME_TAILROOM 2 struct pn544_hci_info { struct i2c_client *i2c_dev; @@ -576,15 +578,40 @@ static int pn544_hci_ready(struct nfc_shdlc *shdlc) return 0; } +static void pn544_hci_add_len_crc(struct sk_buff *skb) +{ + u16 crc; + int len; + + len = skb->len + 2; + *skb_push(skb, 1) = len; + + crc = crc_ccitt(0xffff, skb->data, skb->len); + crc = ~crc; + *skb_put(skb, 1) = crc & 0xff; + *skb_put(skb, 1) = crc >> 8; +} + +static void pn544_hci_remove_len_crc(struct sk_buff *skb) +{ + skb_pull(skb, PN544_FRAME_HEADROOM); + skb_trim(skb, PN544_FRAME_TAILROOM); +} + static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb) { struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); struct i2c_client *client = info->i2c_dev; + int r; if (info->hard_fault != 0) return info->hard_fault; - return pn544_hci_i2c_write(client, skb->data, skb->len); + pn544_hci_add_len_crc(skb); + r = pn544_hci_i2c_write(client, skb->data, skb->len); + pn544_hci_remove_len_crc(skb); + + return r; } static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, @@ -874,7 +901,8 @@ static int __devinit pn544_hci_probe(struct i2c_client *client, info->shdlc = nfc_shdlc_allocate(&pn544_shdlc_ops, &init_data, protocols, - PN544_CMDS_HEADROOM, 0, + PN544_FRAME_HEADROOM + PN544_CMDS_HEADROOM, + PN544_FRAME_TAILROOM, PN544_HCI_LLC_MAX_PAYLOAD, dev_name(&client->dev)); if (!info->shdlc) { diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c index 824fb09384ed..ed8796b78f39 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/shdlc.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -30,7 +29,6 @@ #include #define SHDLC_LLC_HEAD_ROOM 2 -#define SHDLC_LLC_TAIL_ROOM 2 #define SHDLC_MAX_WINDOW 4 #define SHDLC_SREJ_SUPPORT false @@ -94,28 +92,13 @@ static struct sk_buff *nfc_shdlc_alloc_skb(struct nfc_shdlc *shdlc, struct sk_buff *skb; skb = alloc_skb(shdlc->client_headroom + SHDLC_LLC_HEAD_ROOM + - shdlc->client_tailroom + SHDLC_LLC_TAIL_ROOM + - payload_len, GFP_KERNEL); + shdlc->client_tailroom + payload_len, GFP_KERNEL); if (skb) skb_reserve(skb, shdlc->client_headroom + SHDLC_LLC_HEAD_ROOM); return skb; } -static void nfc_shdlc_add_len_crc(struct sk_buff *skb) -{ - u16 crc; - int len; - - len = skb->len + 2; - *skb_push(skb, 1) = len; - - crc = crc_ccitt(0xffff, skb->data, skb->len); - crc = ~crc; - *skb_put(skb, 1) = crc & 0xff; - *skb_put(skb, 1) = crc >> 8; -} - /* immediately sends an S frame. */ static int nfc_shdlc_send_s_frame(struct nfc_shdlc *shdlc, enum sframe_type sframe_type, int nr) @@ -131,8 +114,6 @@ static int nfc_shdlc_send_s_frame(struct nfc_shdlc *shdlc, *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_S | (sframe_type << 3) | nr; - nfc_shdlc_add_len_crc(skb); - r = shdlc->ops->xmit(shdlc, skb); kfree_skb(skb); @@ -151,8 +132,6 @@ static int nfc_shdlc_send_u_frame(struct nfc_shdlc *shdlc, *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_U | uframe_modifier; - nfc_shdlc_add_len_crc(skb); - r = shdlc->ops->xmit(shdlc, skb); kfree_skb(skb); @@ -509,8 +488,6 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) shdlc->nr); /* SHDLC_DUMP_SKB("shdlc frame written", skb); */ - nfc_shdlc_add_len_crc(skb); - r = shdlc->ops->xmit(shdlc, skb); if (r < 0) { shdlc->hard_fault = r; @@ -880,7 +857,7 @@ struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops, shdlc->hdev = nfc_hci_allocate_device(&shdlc_ops, init_data, protocols, tx_headroom + SHDLC_LLC_HEAD_ROOM, - tx_tailroom + SHDLC_LLC_TAIL_ROOM, + tx_tailroom, max_link_payload); if (shdlc->hdev == NULL) goto err_allocdev; -- cgit v1.2.3 From f3e8fb552789f4845e60b11c47b676d14b9488e5 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Tue, 11 Sep 2012 10:43:50 +0200 Subject: NFC: Modified hci_transceive to become an asynchronous operation This enables the completion callback to be called from a different context, preventing a possible deadlock if the callback resulted in the invocation of a nested call to the currently locked nfc_dev. This is also more in line with the im_transceive nfc_ops for NFC Core or NCI drivers which already behave asynchronously. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544_hci.c | 57 ++++++++++++++++++++++++++++++++++++------------- include/net/nfc/hci.h | 8 +++++-- include/net/nfc/shdlc.h | 4 ++-- net/nfc/hci/core.c | 57 +++++++++++++++++++++++++++++++++---------------- net/nfc/hci/shdlc.c | 5 +++-- 5 files changed, 92 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c index d90aecfce739..a176d1f7bbf3 100644 --- a/drivers/nfc/pn544_hci.c +++ b/drivers/nfc/pn544_hci.c @@ -148,6 +148,9 @@ struct pn544_hci_info { * < 0 if hardware error occured (e.g. i2c err) * and prevents normal operation. */ + int async_cb_type; + data_exchange_cb_t async_cb; + void *async_cb_context; }; static void pn544_hci_platform_init(struct pn544_hci_info *info) @@ -731,6 +734,26 @@ static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc, return r; } +#define PN544_CB_TYPE_READER_F 1 + +static void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb, + int err) +{ + struct pn544_hci_info *info = context; + + switch (info->async_cb_type) { + case PN544_CB_TYPE_READER_F: + if (err == 0) + skb_pull(skb, 1); + info->async_cb(info->async_cb_context, skb, err); + break; + default: + if (err == 0) + kfree_skb(skb); + break; + } +} + #define MIFARE_CMD_AUTH_KEY_A 0x60 #define MIFARE_CMD_AUTH_KEY_B 0x61 #define MIFARE_CMD_HEADER 2 @@ -744,11 +767,11 @@ static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc, */ static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc, struct nfc_target *target, - struct sk_buff *skb, - struct sk_buff **res_skb) + struct sk_buff *skb, data_exchange_cb_t cb, + void *cb_context) { + struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); - int r; pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__, target->hci_reader_gate); @@ -773,25 +796,29 @@ static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc, memcpy(data, uid, MIFARE_UID_LEN); } - return nfc_hci_send_cmd(hdev, target->hci_reader_gate, - PN544_MIFARE_CMD, - skb->data, skb->len, res_skb); + return nfc_hci_send_cmd_async(hdev, + target->hci_reader_gate, + PN544_MIFARE_CMD, + skb->data, skb->len, + cb, cb_context); } else return 1; case PN544_RF_READER_F_GATE: *skb_push(skb, 1) = 0; *skb_push(skb, 1) = 0; - r = nfc_hci_send_cmd(hdev, target->hci_reader_gate, - PN544_FELICA_RAW, - skb->data, skb->len, res_skb); - if (r == 0) - skb_pull(*res_skb, 1); - return r; + info->async_cb_type = PN544_CB_TYPE_READER_F; + info->async_cb = cb; + info->async_cb_context = cb_context; + + return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, + PN544_FELICA_RAW, skb->data, + skb->len, + pn544_hci_data_exchange_cb, info); case PN544_RF_READER_JEWEL_GATE: - return nfc_hci_send_cmd(hdev, target->hci_reader_gate, - PN544_JEWEL_RAW_CMD, - skb->data, skb->len, res_skb); + return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, + PN544_JEWEL_RAW_CMD, skb->data, + skb->len, cb, cb_context); default: return 1; } diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 54ba2caab4a6..6cee6e21fc46 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -38,8 +38,8 @@ struct nfc_hci_ops { int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate, struct nfc_target *target); int (*data_exchange) (struct nfc_hci_dev *hdev, - struct nfc_target *target, - struct sk_buff *skb, struct sk_buff **res_skb); + struct nfc_target *target, struct sk_buff *skb, + data_exchange_cb_t cb, void *cb_context); int (*check_presence)(struct nfc_hci_dev *hdev, struct nfc_target *target); }; @@ -103,6 +103,10 @@ struct nfc_hci_dev { u8 hw_mpw; u8 hw_software; u8 hw_bsid; + + int async_cb_type; + data_exchange_cb_t async_cb; + void *async_cb_context; }; /* hci device allocation */ diff --git a/include/net/nfc/shdlc.h b/include/net/nfc/shdlc.h index 342427362989..fe5e19829352 100644 --- a/include/net/nfc/shdlc.h +++ b/include/net/nfc/shdlc.h @@ -34,8 +34,8 @@ struct nfc_shdlc_ops { int (*complete_target_discovered) (struct nfc_shdlc *shdlc, u8 gate, struct nfc_target *target); int (*data_exchange) (struct nfc_shdlc *shdlc, - struct nfc_target *target, - struct sk_buff *skb, struct sk_buff **res_skb); + struct nfc_target *target, struct sk_buff *skb, + data_exchange_cb_t cb, void *cb_context); int (*check_presence)(struct nfc_shdlc *shdlc, struct nfc_target *target); }; diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index e387c86e0cc7..dc57e3dc15a4 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -537,13 +537,37 @@ static void hci_deactivate_target(struct nfc_dev *nfc_dev, { } +#define HCI_CB_TYPE_TRANSCEIVE 1 + +static void hci_transceive_cb(void *context, struct sk_buff *skb, int err) +{ + struct nfc_hci_dev *hdev = context; + + switch (hdev->async_cb_type) { + case HCI_CB_TYPE_TRANSCEIVE: + /* + * TODO: Check RF Error indicator to make sure data is valid. + * It seems that HCI cmd can complete without error, but data + * can be invalid if an RF error occured? Ignore for now. + */ + if (err == 0) + skb_trim(skb, skb->len - 1); /* RF Err ind */ + + hdev->async_cb(hdev->async_cb_context, skb, err); + break; + default: + if (err == 0) + kfree_skb(skb); + break; + } +} + static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, struct sk_buff *skb, data_exchange_cb_t cb, void *cb_context) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); int r; - struct sk_buff *res_skb = NULL; pr_debug("target_idx=%d\n", target->idx); @@ -551,40 +575,37 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, case NFC_HCI_RF_READER_A_GATE: case NFC_HCI_RF_READER_B_GATE: if (hdev->ops->data_exchange) { - r = hdev->ops->data_exchange(hdev, target, skb, - &res_skb); + r = hdev->ops->data_exchange(hdev, target, skb, cb, + cb_context); if (r <= 0) /* handled */ break; } *skb_push(skb, 1) = 0; /* CTR, see spec:10.2.2.1 */ - r = nfc_hci_send_cmd(hdev, target->hci_reader_gate, - NFC_HCI_WR_XCHG_DATA, - skb->data, skb->len, &res_skb); - /* - * TODO: Check RF Error indicator to make sure data is valid. - * It seems that HCI cmd can complete without error, but data - * can be invalid if an RF error occured? Ignore for now. - */ - if (r == 0) - skb_trim(res_skb, res_skb->len - 1); /* RF Err ind */ + + hdev->async_cb_type = HCI_CB_TYPE_TRANSCEIVE; + hdev->async_cb = cb; + hdev->async_cb_context = cb_context; + + r = nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, + NFC_HCI_WR_XCHG_DATA, skb->data, + skb->len, hci_transceive_cb, hdev); break; default: if (hdev->ops->data_exchange) { - r = hdev->ops->data_exchange(hdev, target, skb, - &res_skb); + r = hdev->ops->data_exchange(hdev, target, skb, cb, + cb_context); if (r == 1) r = -ENOTSUPP; } else r = -ENOTSUPP; + break; } kfree_skb(skb); - cb(cb_context, res_skb, r); - - return 0; + return r; } static int hci_check_presence(struct nfc_dev *nfc_dev, diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c index 9357ba7362f6..c63af7d3e859 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/shdlc.c @@ -777,12 +777,13 @@ static int nfc_shdlc_complete_target_discovered(struct nfc_hci_dev *hdev, static int nfc_shdlc_data_exchange(struct nfc_hci_dev *hdev, struct nfc_target *target, struct sk_buff *skb, - struct sk_buff **res_skb) + data_exchange_cb_t cb, void *cb_context) { struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); if (shdlc->ops->data_exchange) - return shdlc->ops->data_exchange(shdlc, target, skb, res_skb); + return shdlc->ops->data_exchange(shdlc, target, skb, cb, + cb_context); return -EPERM; } -- cgit v1.2.3 From 412fda538f4b1317ecd0fbe6e5bc9124792bea88 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Tue, 18 Sep 2012 19:45:48 +0200 Subject: NFC: Changed HCI and PN544 HCI driver to use the new HCI LLC Core The previous shdlc HCI driver and its header are removed from the tree. PN544 now registers directly with HCI and passes the name of the llc it requires (shdlc). HCI instantiation now allocates the required llc instance. The llc is started when the HCI device is brought up. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- drivers/nfc/Kconfig | 2 +- drivers/nfc/pn544_hci.c | 73 ++-- include/net/nfc/hci.h | 3 + include/net/nfc/shdlc.h | 106 ------ net/nfc/hci/Makefile | 2 +- net/nfc/hci/core.c | 210 ++++++----- net/nfc/hci/llc_shdlc.c | 2 +- net/nfc/hci/shdlc.c | 918 ------------------------------------------------ 8 files changed, 164 insertions(+), 1152 deletions(-) delete mode 100644 include/net/nfc/shdlc.h delete mode 100644 net/nfc/hci/shdlc.c (limited to 'drivers') diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 3b20b73ee649..89c57d1a7cad 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -19,7 +19,7 @@ config PN544_NFC config PN544_HCI_NFC tristate "HCI PN544 NFC driver" - depends on I2C && NFC_SHDLC + depends on I2C && NFC_HCI && NFC_SHDLC select CRC_CCITT default n ---help--- diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c index a176d1f7bbf3..e681da2e3413 100644 --- a/drivers/nfc/pn544_hci.c +++ b/drivers/nfc/pn544_hci.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include @@ -133,7 +133,7 @@ static struct nfc_hci_gate pn544_gates[] = { struct pn544_hci_info { struct i2c_client *i2c_dev; - struct nfc_shdlc *shdlc; + struct nfc_hci_dev *hdev; enum pn544_state state; @@ -362,21 +362,21 @@ static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id) if (r == -EREMOTEIO) { info->hard_fault = r; - nfc_shdlc_recv_frame(info->shdlc, NULL); + nfc_hci_recv_frame(info->hdev, NULL); return IRQ_HANDLED; } else if ((r == -ENOMEM) || (r == -EBADMSG)) { return IRQ_HANDLED; } - nfc_shdlc_recv_frame(info->shdlc, skb); + nfc_hci_recv_frame(info->hdev, skb); return IRQ_HANDLED; } -static int pn544_hci_open(struct nfc_shdlc *shdlc) +static int pn544_hci_open(struct nfc_hci_dev *hdev) { - struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); + struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); int r = 0; mutex_lock(&info->info_lock); @@ -396,9 +396,9 @@ out: return r; } -static void pn544_hci_close(struct nfc_shdlc *shdlc) +static void pn544_hci_close(struct nfc_hci_dev *hdev) { - struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); + struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); mutex_lock(&info->info_lock); @@ -413,9 +413,8 @@ out: mutex_unlock(&info->info_lock); } -static int pn544_hci_ready(struct nfc_shdlc *shdlc) +static int pn544_hci_ready(struct nfc_hci_dev *hdev) { - struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); struct sk_buff *skb; static struct hw_config { u8 adr[2]; @@ -601,9 +600,9 @@ static void pn544_hci_remove_len_crc(struct sk_buff *skb) skb_trim(skb, PN544_FRAME_TAILROOM); } -static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb) +static int pn544_hci_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb) { - struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); + struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); struct i2c_client *client = info->i2c_dev; int r; @@ -617,10 +616,9 @@ static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb) return r; } -static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, +static int pn544_hci_start_poll(struct nfc_hci_dev *hdev, u32 im_protocols, u32 tm_protocols) { - struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); u8 phases = 0; int r; u8 duration[2]; @@ -671,7 +669,7 @@ static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, return r; } -static int pn544_hci_target_from_gate(struct nfc_shdlc *shdlc, u8 gate, +static int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate, struct nfc_target *target) { switch (gate) { @@ -689,11 +687,10 @@ static int pn544_hci_target_from_gate(struct nfc_shdlc *shdlc, u8 gate, return 0; } -static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc, +static int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev, u8 gate, struct nfc_target *target) { - struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); struct sk_buff *uid_skb; int r = 0; @@ -765,13 +762,12 @@ static void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb, * <= 0: driver handled the data exchange * 1: driver doesn't especially handle, please do standard processing */ -static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc, +static int pn544_hci_data_exchange(struct nfc_hci_dev *hdev, struct nfc_target *target, struct sk_buff *skb, data_exchange_cb_t cb, void *cb_context) { - struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); - struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__, target->hci_reader_gate); @@ -824,17 +820,15 @@ static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc, } } -static int pn544_hci_check_presence(struct nfc_shdlc *shdlc, +static int pn544_hci_check_presence(struct nfc_hci_dev *hdev, struct nfc_target *target) { - struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); - return nfc_hci_send_cmd(hdev, target->hci_reader_gate, PN544_RF_READER_CMD_PRESENCE_CHECK, NULL, 0, NULL); } -static struct nfc_shdlc_ops pn544_shdlc_ops = { +static struct nfc_hci_ops pn544_hci_ops = { .open = pn544_hci_open, .close = pn544_hci_close, .hci_ready = pn544_hci_ready, @@ -926,23 +920,30 @@ static int __devinit pn544_hci_probe(struct i2c_client *client, NFC_PROTO_ISO14443_B_MASK | NFC_PROTO_NFC_DEP_MASK; - info->shdlc = nfc_shdlc_allocate(&pn544_shdlc_ops, - &init_data, protocols, - PN544_FRAME_HEADROOM + PN544_CMDS_HEADROOM, - PN544_FRAME_TAILROOM, - PN544_HCI_LLC_MAX_PAYLOAD, - dev_name(&client->dev)); - if (!info->shdlc) { - dev_err(&client->dev, "Cannot allocate nfc shdlc.\n"); + info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, + protocols, LLC_SHDLC_NAME, + PN544_FRAME_HEADROOM + + PN544_CMDS_HEADROOM, + PN544_FRAME_TAILROOM, + PN544_HCI_LLC_MAX_PAYLOAD); + if (!info->hdev) { + dev_err(&client->dev, "Cannot allocate nfc hdev.\n"); r = -ENOMEM; - goto err_allocshdlc; + goto err_alloc_hdev; } - nfc_shdlc_set_clientdata(info->shdlc, info); + nfc_hci_set_clientdata(info->hdev, info); + + r = nfc_hci_register_device(info->hdev); + if (r) + goto err_regdev; return 0; -err_allocshdlc: +err_regdev: + nfc_hci_free_device(info->hdev); + +err_alloc_hdev: free_irq(client->irq, info); err_rti: @@ -963,7 +964,7 @@ static __devexit int pn544_hci_remove(struct i2c_client *client) dev_dbg(&client->dev, "%s\n", __func__); - nfc_shdlc_free(info->shdlc); + nfc_hci_free_device(info->hdev); if (info->state != PN544_ST_COLD) { if (pdata->disable) diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 6cee6e21fc46..9b5ed2d94d60 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -87,6 +87,8 @@ struct nfc_hci_dev { struct nfc_hci_ops *ops; + struct nfc_llc *llc; + struct nfc_hci_init_data init_data; void *clientdata; @@ -113,6 +115,7 @@ struct nfc_hci_dev { struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, struct nfc_hci_init_data *init_data, u32 protocols, + const char *llc_name, int tx_headroom, int tx_tailroom, int max_link_payload); diff --git a/include/net/nfc/shdlc.h b/include/net/nfc/shdlc.h deleted file mode 100644 index fe5e19829352..000000000000 --- a/include/net/nfc/shdlc.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __NFC_SHDLC_H -#define __NFC_SHDLC_H - -struct nfc_shdlc; - -struct nfc_shdlc_ops { - int (*open) (struct nfc_shdlc *shdlc); - void (*close) (struct nfc_shdlc *shdlc); - int (*hci_ready) (struct nfc_shdlc *shdlc); - int (*xmit) (struct nfc_shdlc *shdlc, struct sk_buff *skb); - int (*start_poll) (struct nfc_shdlc *shdlc, - u32 im_protocols, u32 tm_protocols); - int (*target_from_gate) (struct nfc_shdlc *shdlc, u8 gate, - struct nfc_target *target); - int (*complete_target_discovered) (struct nfc_shdlc *shdlc, u8 gate, - struct nfc_target *target); - int (*data_exchange) (struct nfc_shdlc *shdlc, - struct nfc_target *target, struct sk_buff *skb, - data_exchange_cb_t cb, void *cb_context); - int (*check_presence)(struct nfc_shdlc *shdlc, - struct nfc_target *target); -}; - -enum shdlc_state { - SHDLC_DISCONNECTED = 0, - SHDLC_CONNECTING = 1, - SHDLC_NEGOCIATING = 2, - SHDLC_CONNECTED = 3 -}; - -struct nfc_shdlc { - struct mutex state_mutex; - enum shdlc_state state; - int hard_fault; - - struct nfc_hci_dev *hdev; - - wait_queue_head_t *connect_wq; - int connect_tries; - int connect_result; - struct timer_list connect_timer;/* aka T3 in spec 10.6.1 */ - - u8 w; /* window size */ - bool srej_support; - - struct timer_list t1_timer; /* send ack timeout */ - bool t1_active; - - struct timer_list t2_timer; /* guard/retransmit timeout */ - bool t2_active; - - int ns; /* next seq num for send */ - int nr; /* next expected seq num for receive */ - int dnr; /* oldest sent unacked seq num */ - - struct sk_buff_head rcv_q; - - struct sk_buff_head send_q; - bool rnr; /* other side is not ready to receive */ - - struct sk_buff_head ack_pending_q; - - struct work_struct sm_work; - - struct nfc_shdlc_ops *ops; - - int client_headroom; - int client_tailroom; - - void *clientdata; -}; - -void nfc_shdlc_recv_frame(struct nfc_shdlc *shdlc, struct sk_buff *skb); - -struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops, - struct nfc_hci_init_data *init_data, - u32 protocols, - int tx_headroom, int tx_tailroom, - int max_link_payload, const char *devname); - -void nfc_shdlc_free(struct nfc_shdlc *shdlc); - -void nfc_shdlc_set_clientdata(struct nfc_shdlc *shdlc, void *clientdata); -void *nfc_shdlc_get_clientdata(struct nfc_shdlc *shdlc); -struct nfc_hci_dev *nfc_shdlc_get_hci_dev(struct nfc_shdlc *shdlc); - -#endif /* __NFC_SHDLC_H */ diff --git a/net/nfc/hci/Makefile b/net/nfc/hci/Makefile index c4d65479629b..c5dbb6891b24 100644 --- a/net/nfc/hci/Makefile +++ b/net/nfc/hci/Makefile @@ -5,4 +5,4 @@ obj-$(CONFIG_NFC_HCI) += hci.o hci-y := core.o hcp.o command.o llc.o llc_nop.o -hci-$(CONFIG_NFC_SHDLC) += shdlc.o llc_shdlc.o +hci-$(CONFIG_NFC_SHDLC) += llc_shdlc.o diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 069e2d6056e5..c1129c22d835 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -78,7 +78,7 @@ next_msg: pr_debug("msg_tx_queue has a cmd to send\n"); while ((skb = skb_dequeue(&msg->msg_frags)) != NULL) { - r = hdev->ops->xmit(hdev, skb); + r = nfc_llc_xmit_from_hci(hdev->llc, skb); if (r < 0) { kfree_skb(skb); skb_queue_purge(&msg->msg_frags); @@ -469,29 +469,38 @@ static int hci_dev_up(struct nfc_dev *nfc_dev) return r; } + r = nfc_llc_start(hdev->llc); + if (r < 0) + goto exit_close; + r = hci_dev_session_init(hdev); if (r < 0) - goto exit; + goto exit_llc; r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, NFC_HCI_EVT_END_OPERATION, NULL, 0); if (r < 0) - goto exit; + goto exit_llc; if (hdev->ops->hci_ready) { r = hdev->ops->hci_ready(hdev); if (r < 0) - goto exit; + goto exit_llc; } r = hci_dev_version(hdev); if (r < 0) - goto exit; + goto exit_llc; + + return 0; + +exit_llc: + nfc_llc_stop(hdev->llc); + +exit_close: + if (hdev->ops->close) + hdev->ops->close(hdev); -exit: - if (r < 0) - if (hdev->ops->close) - hdev->ops->close(hdev); return r; } @@ -499,6 +508,8 @@ static int hci_dev_down(struct nfc_dev *nfc_dev) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); + nfc_llc_stop(hdev->llc); + if (hdev->ops->close) hdev->ops->close(hdev); @@ -620,6 +631,93 @@ static int hci_check_presence(struct nfc_dev *nfc_dev, return 0; } +static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) +{ + mutex_lock(&hdev->msg_tx_mutex); + + if (hdev->cmd_pending_msg == NULL) { + nfc_driver_failure(hdev->ndev, err); + goto exit; + } + + __nfc_hci_cmd_completion(hdev, err, NULL); + +exit: + mutex_unlock(&hdev->msg_tx_mutex); +} + +static void nfc_hci_llc_failure(struct nfc_hci_dev *hdev, int err) +{ + nfc_hci_failure(hdev, err); +} + +static void nfc_hci_recv_from_llc(struct nfc_hci_dev *hdev, struct sk_buff *skb) +{ + struct hcp_packet *packet; + u8 type; + u8 instruction; + struct sk_buff *hcp_skb; + u8 pipe; + struct sk_buff *frag_skb; + int msg_len; + + packet = (struct hcp_packet *)skb->data; + if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { + skb_queue_tail(&hdev->rx_hcp_frags, skb); + return; + } + + /* it's the last fragment. Does it need re-aggregation? */ + if (skb_queue_len(&hdev->rx_hcp_frags)) { + pipe = packet->header & NFC_HCI_FRAGMENT; + skb_queue_tail(&hdev->rx_hcp_frags, skb); + + msg_len = 0; + skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { + msg_len += (frag_skb->len - + NFC_HCI_HCP_PACKET_HEADER_LEN); + } + + hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + + msg_len, GFP_KERNEL); + if (hcp_skb == NULL) { + nfc_hci_failure(hdev, -ENOMEM); + return; + } + + *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; + + skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { + msg_len = frag_skb->len - NFC_HCI_HCP_PACKET_HEADER_LEN; + memcpy(skb_put(hcp_skb, msg_len), + frag_skb->data + NFC_HCI_HCP_PACKET_HEADER_LEN, + msg_len); + } + + skb_queue_purge(&hdev->rx_hcp_frags); + } else { + packet->header &= NFC_HCI_FRAGMENT; + hcp_skb = skb; + } + + /* if this is a response, dispatch immediately to + * unblock waiting cmd context. Otherwise, enqueue to dispatch + * in separate context where handler can also execute command. + */ + packet = (struct hcp_packet *)hcp_skb->data; + type = HCP_MSG_GET_TYPE(packet->message.header); + if (type == NFC_HCI_HCP_RESPONSE) { + pipe = packet->header; + instruction = HCP_MSG_GET_CMD(packet->message.header); + skb_pull(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN + + NFC_HCI_HCP_MESSAGE_HEADER_LEN); + nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, hcp_skb); + } else { + skb_queue_tail(&hdev->msg_rx_queue, hcp_skb); + queue_work(system_nrt_wq, &hdev->msg_rx_work); + } +} + static struct nfc_ops hci_nfc_ops = { .dev_up = hci_dev_up, .dev_down = hci_dev_down, @@ -634,6 +732,7 @@ static struct nfc_ops hci_nfc_ops = { struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, struct nfc_hci_init_data *init_data, u32 protocols, + const char *llc_name, int tx_headroom, int tx_tailroom, int max_link_payload) @@ -650,10 +749,19 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, if (hdev == NULL) return NULL; + hdev->llc = nfc_llc_allocate(llc_name, hdev, ops->xmit, + nfc_hci_recv_from_llc, tx_headroom, + tx_tailroom, nfc_hci_llc_failure); + if (hdev->llc == NULL) { + kfree(hdev); + return NULL; + } + hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols, tx_headroom + HCI_CMDS_HEADROOM, tx_tailroom); if (!hdev->ndev) { + nfc_llc_free(hdev->llc); kfree(hdev); return NULL; } @@ -673,6 +781,7 @@ EXPORT_SYMBOL(nfc_hci_allocate_device); void nfc_hci_free_device(struct nfc_hci_dev *hdev) { nfc_free_device(hdev->ndev); + nfc_llc_free(hdev->llc); kfree(hdev); } EXPORT_SYMBOL(nfc_hci_free_device); @@ -733,92 +842,15 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev) } EXPORT_SYMBOL(nfc_hci_get_clientdata); -static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) -{ - mutex_lock(&hdev->msg_tx_mutex); - - if (hdev->cmd_pending_msg == NULL) { - nfc_driver_failure(hdev->ndev, err); - goto exit; - } - - __nfc_hci_cmd_completion(hdev, err, NULL); - -exit: - mutex_unlock(&hdev->msg_tx_mutex); -} - void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) { nfc_hci_failure(hdev, err); } EXPORT_SYMBOL(nfc_hci_driver_failure); -void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) +void inline nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) { - struct hcp_packet *packet; - u8 type; - u8 instruction; - struct sk_buff *hcp_skb; - u8 pipe; - struct sk_buff *frag_skb; - int msg_len; - - packet = (struct hcp_packet *)skb->data; - if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { - skb_queue_tail(&hdev->rx_hcp_frags, skb); - return; - } - - /* it's the last fragment. Does it need re-aggregation? */ - if (skb_queue_len(&hdev->rx_hcp_frags)) { - pipe = packet->header & NFC_HCI_FRAGMENT; - skb_queue_tail(&hdev->rx_hcp_frags, skb); - - msg_len = 0; - skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { - msg_len += (frag_skb->len - - NFC_HCI_HCP_PACKET_HEADER_LEN); - } - - hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + - msg_len, GFP_KERNEL); - if (hcp_skb == NULL) { - nfc_hci_failure(hdev, -ENOMEM); - return; - } - - *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; - - skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { - msg_len = frag_skb->len - NFC_HCI_HCP_PACKET_HEADER_LEN; - memcpy(skb_put(hcp_skb, msg_len), - frag_skb->data + NFC_HCI_HCP_PACKET_HEADER_LEN, - msg_len); - } - - skb_queue_purge(&hdev->rx_hcp_frags); - } else { - packet->header &= NFC_HCI_FRAGMENT; - hcp_skb = skb; - } - - /* if this is a response, dispatch immediately to - * unblock waiting cmd context. Otherwise, enqueue to dispatch - * in separate context where handler can also execute command. - */ - packet = (struct hcp_packet *)hcp_skb->data; - type = HCP_MSG_GET_TYPE(packet->message.header); - if (type == NFC_HCI_HCP_RESPONSE) { - pipe = packet->header; - instruction = HCP_MSG_GET_CMD(packet->message.header); - skb_pull(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN + - NFC_HCI_HCP_MESSAGE_HEADER_LEN); - nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, hcp_skb); - } else { - skb_queue_tail(&hdev->msg_rx_queue, hcp_skb); - queue_work(system_nrt_wq, &hdev->msg_rx_work); - } + nfc_llc_rcv_from_drv(hdev->llc, skb); } EXPORT_SYMBOL(nfc_hci_recv_frame); @@ -832,7 +864,7 @@ static void __exit nfc_hci_exit(void) nfc_llc_exit(); } -module_init(nfc_hci_init); +subsys_initcall(nfc_hci_init); module_exit(nfc_hci_exit); MODULE_LICENSE("GPL"); diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c index bb191100ee96..fad6cd18d613 100644 --- a/net/nfc/hci/llc_shdlc.c +++ b/net/nfc/hci/llc_shdlc.c @@ -535,7 +535,7 @@ static void llc_shdlc_handle_send_queue(struct llc_shdlc *shdlc) pr_debug("Sending I-Frame %d, waiting to rcv %d\n", shdlc->ns, shdlc->nr); - /* SHDLC_DUMP_SKB("shdlc frame written", skb); */ + SHDLC_DUMP_SKB("shdlc frame written", skb); r = shdlc->xmit_to_drv(shdlc->hdev, skb); if (r < 0) { diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c deleted file mode 100644 index c63af7d3e859..000000000000 --- a/net/nfc/hci/shdlc.c +++ /dev/null @@ -1,918 +0,0 @@ -/* - * Copyright (C) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#define pr_fmt(fmt) "shdlc: %s: " fmt, __func__ - -#include -#include -#include -#include -#include - -#include -#include - -#define SHDLC_LLC_HEAD_ROOM 2 - -#define SHDLC_MAX_WINDOW 4 -#define SHDLC_SREJ_SUPPORT false - -#define SHDLC_CONTROL_HEAD_MASK 0xe0 -#define SHDLC_CONTROL_HEAD_I 0x80 -#define SHDLC_CONTROL_HEAD_I2 0xa0 -#define SHDLC_CONTROL_HEAD_S 0xc0 -#define SHDLC_CONTROL_HEAD_U 0xe0 - -#define SHDLC_CONTROL_NS_MASK 0x38 -#define SHDLC_CONTROL_NR_MASK 0x07 -#define SHDLC_CONTROL_TYPE_MASK 0x18 - -#define SHDLC_CONTROL_M_MASK 0x1f - -enum sframe_type { - S_FRAME_RR = 0x00, - S_FRAME_REJ = 0x01, - S_FRAME_RNR = 0x02, - S_FRAME_SREJ = 0x03 -}; - -enum uframe_modifier { - U_FRAME_UA = 0x06, - U_FRAME_RSET = 0x19 -}; - -#define SHDLC_CONNECT_VALUE_MS 5 -#define SHDLC_T1_VALUE_MS(w) ((5 * w) / 4) -#define SHDLC_T2_VALUE_MS 300 - -#define SHDLC_DUMP_SKB(info, skb) \ -do { \ - pr_debug("%s:\n", info); \ - print_hex_dump(KERN_DEBUG, "shdlc: ", DUMP_PREFIX_OFFSET, \ - 16, 1, skb->data, skb->len, 0); \ -} while (0) - -/* checks x < y <= z modulo 8 */ -static bool nfc_shdlc_x_lt_y_lteq_z(int x, int y, int z) -{ - if (x < z) - return ((x < y) && (y <= z)) ? true : false; - else - return ((y > x) || (y <= z)) ? true : false; -} - -/* checks x <= y < z modulo 8 */ -static bool nfc_shdlc_x_lteq_y_lt_z(int x, int y, int z) -{ - if (x <= z) - return ((x <= y) && (y < z)) ? true : false; - else /* x > z -> z+8 > x */ - return ((y >= x) || (y < z)) ? true : false; -} - -static struct sk_buff *nfc_shdlc_alloc_skb(struct nfc_shdlc *shdlc, - int payload_len) -{ - struct sk_buff *skb; - - skb = alloc_skb(shdlc->client_headroom + SHDLC_LLC_HEAD_ROOM + - shdlc->client_tailroom + payload_len, GFP_KERNEL); - if (skb) - skb_reserve(skb, shdlc->client_headroom + SHDLC_LLC_HEAD_ROOM); - - return skb; -} - -/* immediately sends an S frame. */ -static int nfc_shdlc_send_s_frame(struct nfc_shdlc *shdlc, - enum sframe_type sframe_type, int nr) -{ - int r; - struct sk_buff *skb; - - pr_debug("sframe_type=%d nr=%d\n", sframe_type, nr); - - skb = nfc_shdlc_alloc_skb(shdlc, 0); - if (skb == NULL) - return -ENOMEM; - - *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_S | (sframe_type << 3) | nr; - - r = shdlc->ops->xmit(shdlc, skb); - - kfree_skb(skb); - - return r; -} - -/* immediately sends an U frame. skb may contain optional payload */ -static int nfc_shdlc_send_u_frame(struct nfc_shdlc *shdlc, - struct sk_buff *skb, - enum uframe_modifier uframe_modifier) -{ - int r; - - pr_debug("uframe_modifier=%d\n", uframe_modifier); - - *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_U | uframe_modifier; - - r = shdlc->ops->xmit(shdlc, skb); - - kfree_skb(skb); - - return r; -} - -/* - * Free ack_pending frames until y_nr - 1, and reset t2 according to - * the remaining oldest ack_pending frame sent time - */ -static void nfc_shdlc_reset_t2(struct nfc_shdlc *shdlc, int y_nr) -{ - struct sk_buff *skb; - int dnr = shdlc->dnr; /* MUST initially be < y_nr */ - - pr_debug("release ack pending up to frame %d excluded\n", y_nr); - - while (dnr != y_nr) { - pr_debug("release ack pending frame %d\n", dnr); - - skb = skb_dequeue(&shdlc->ack_pending_q); - kfree_skb(skb); - - dnr = (dnr + 1) % 8; - } - - if (skb_queue_empty(&shdlc->ack_pending_q)) { - if (shdlc->t2_active) { - del_timer_sync(&shdlc->t2_timer); - shdlc->t2_active = false; - - pr_debug - ("All sent frames acked. Stopped T2(retransmit)\n"); - } - } else { - skb = skb_peek(&shdlc->ack_pending_q); - - mod_timer(&shdlc->t2_timer, *(unsigned long *)skb->cb + - msecs_to_jiffies(SHDLC_T2_VALUE_MS)); - shdlc->t2_active = true; - - pr_debug - ("Start T2(retransmit) for remaining unacked sent frames\n"); - } -} - -/* - * Receive validated frames from lower layer. skb contains HCI payload only. - * Handle according to algorithm at spec:10.8.2 - */ -static void nfc_shdlc_rcv_i_frame(struct nfc_shdlc *shdlc, - struct sk_buff *skb, int ns, int nr) -{ - int x_ns = ns; - int y_nr = nr; - - pr_debug("recvd I-frame %d, remote waiting frame %d\n", ns, nr); - - if (shdlc->state != SHDLC_CONNECTED) - goto exit; - - if (x_ns != shdlc->nr) { - nfc_shdlc_send_s_frame(shdlc, S_FRAME_REJ, shdlc->nr); - goto exit; - } - - if (shdlc->t1_active == false) { - shdlc->t1_active = true; - mod_timer(&shdlc->t1_timer, - msecs_to_jiffies(SHDLC_T1_VALUE_MS(shdlc->w))); - pr_debug("(re)Start T1(send ack)\n"); - } - - if (skb->len) { - nfc_hci_recv_frame(shdlc->hdev, skb); - skb = NULL; - } - - shdlc->nr = (shdlc->nr + 1) % 8; - - if (nfc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { - nfc_shdlc_reset_t2(shdlc, y_nr); - - shdlc->dnr = y_nr; - } - -exit: - kfree_skb(skb); -} - -static void nfc_shdlc_rcv_ack(struct nfc_shdlc *shdlc, int y_nr) -{ - pr_debug("remote acked up to frame %d excluded\n", y_nr); - - if (nfc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { - nfc_shdlc_reset_t2(shdlc, y_nr); - shdlc->dnr = y_nr; - } -} - -static void nfc_shdlc_requeue_ack_pending(struct nfc_shdlc *shdlc) -{ - struct sk_buff *skb; - - pr_debug("ns reset to %d\n", shdlc->dnr); - - while ((skb = skb_dequeue_tail(&shdlc->ack_pending_q))) { - skb_pull(skb, 1); /* remove control field */ - skb_queue_head(&shdlc->send_q, skb); - } - shdlc->ns = shdlc->dnr; -} - -static void nfc_shdlc_rcv_rej(struct nfc_shdlc *shdlc, int y_nr) -{ - struct sk_buff *skb; - - pr_debug("remote asks retransmition from frame %d\n", y_nr); - - if (nfc_shdlc_x_lteq_y_lt_z(shdlc->dnr, y_nr, shdlc->ns)) { - if (shdlc->t2_active) { - del_timer_sync(&shdlc->t2_timer); - shdlc->t2_active = false; - pr_debug("Stopped T2(retransmit)\n"); - } - - if (shdlc->dnr != y_nr) { - while ((shdlc->dnr = ((shdlc->dnr + 1) % 8)) != y_nr) { - skb = skb_dequeue(&shdlc->ack_pending_q); - kfree_skb(skb); - } - } - - nfc_shdlc_requeue_ack_pending(shdlc); - } -} - -/* See spec RR:10.8.3 REJ:10.8.4 */ -static void nfc_shdlc_rcv_s_frame(struct nfc_shdlc *shdlc, - enum sframe_type s_frame_type, int nr) -{ - struct sk_buff *skb; - - if (shdlc->state != SHDLC_CONNECTED) - return; - - switch (s_frame_type) { - case S_FRAME_RR: - nfc_shdlc_rcv_ack(shdlc, nr); - if (shdlc->rnr == true) { /* see SHDLC 10.7.7 */ - shdlc->rnr = false; - if (shdlc->send_q.qlen == 0) { - skb = nfc_shdlc_alloc_skb(shdlc, 0); - if (skb) - skb_queue_tail(&shdlc->send_q, skb); - } - } - break; - case S_FRAME_REJ: - nfc_shdlc_rcv_rej(shdlc, nr); - break; - case S_FRAME_RNR: - nfc_shdlc_rcv_ack(shdlc, nr); - shdlc->rnr = true; - break; - default: - break; - } -} - -static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) -{ - pr_debug("result=%d\n", r); - - del_timer_sync(&shdlc->connect_timer); - - if (r == 0) { - shdlc->ns = 0; - shdlc->nr = 0; - shdlc->dnr = 0; - - shdlc->state = SHDLC_CONNECTED; - } else { - shdlc->state = SHDLC_DISCONNECTED; - } - - shdlc->connect_result = r; - - wake_up(shdlc->connect_wq); -} - -static int nfc_shdlc_connect_initiate(struct nfc_shdlc *shdlc) -{ - struct sk_buff *skb; - - pr_debug("\n"); - - skb = nfc_shdlc_alloc_skb(shdlc, 2); - if (skb == NULL) - return -ENOMEM; - - *skb_put(skb, 1) = SHDLC_MAX_WINDOW; - *skb_put(skb, 1) = SHDLC_SREJ_SUPPORT ? 1 : 0; - - return nfc_shdlc_send_u_frame(shdlc, skb, U_FRAME_RSET); -} - -static int nfc_shdlc_connect_send_ua(struct nfc_shdlc *shdlc) -{ - struct sk_buff *skb; - - pr_debug("\n"); - - skb = nfc_shdlc_alloc_skb(shdlc, 0); - if (skb == NULL) - return -ENOMEM; - - return nfc_shdlc_send_u_frame(shdlc, skb, U_FRAME_UA); -} - -static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, - struct sk_buff *skb, - enum uframe_modifier u_frame_modifier) -{ - u8 w = SHDLC_MAX_WINDOW; - bool srej_support = SHDLC_SREJ_SUPPORT; - int r; - - pr_debug("u_frame_modifier=%d\n", u_frame_modifier); - - switch (u_frame_modifier) { - case U_FRAME_RSET: - if (shdlc->state == SHDLC_NEGOCIATING) { - /* we sent RSET, but chip wants to negociate */ - if (skb->len > 0) - w = skb->data[0]; - - if (skb->len > 1) - srej_support = skb->data[1] & 0x01 ? true : - false; - - if ((w <= SHDLC_MAX_WINDOW) && - (SHDLC_SREJ_SUPPORT || (srej_support == false))) { - shdlc->w = w; - shdlc->srej_support = srej_support; - r = nfc_shdlc_connect_send_ua(shdlc); - nfc_shdlc_connect_complete(shdlc, r); - } - } else if (shdlc->state == SHDLC_CONNECTED) { - /* - * Chip wants to reset link. This is unexpected and - * unsupported. - */ - shdlc->hard_fault = -ECONNRESET; - } - break; - case U_FRAME_UA: - if ((shdlc->state == SHDLC_CONNECTING && - shdlc->connect_tries > 0) || - (shdlc->state == SHDLC_NEGOCIATING)) - nfc_shdlc_connect_complete(shdlc, 0); - break; - default: - break; - } - - kfree_skb(skb); -} - -static void nfc_shdlc_handle_rcv_queue(struct nfc_shdlc *shdlc) -{ - struct sk_buff *skb; - u8 control; - int nr; - int ns; - enum sframe_type s_frame_type; - enum uframe_modifier u_frame_modifier; - - if (shdlc->rcv_q.qlen) - pr_debug("rcvQlen=%d\n", shdlc->rcv_q.qlen); - - while ((skb = skb_dequeue(&shdlc->rcv_q)) != NULL) { - control = skb->data[0]; - skb_pull(skb, 1); - switch (control & SHDLC_CONTROL_HEAD_MASK) { - case SHDLC_CONTROL_HEAD_I: - case SHDLC_CONTROL_HEAD_I2: - ns = (control & SHDLC_CONTROL_NS_MASK) >> 3; - nr = control & SHDLC_CONTROL_NR_MASK; - nfc_shdlc_rcv_i_frame(shdlc, skb, ns, nr); - break; - case SHDLC_CONTROL_HEAD_S: - s_frame_type = (control & SHDLC_CONTROL_TYPE_MASK) >> 3; - nr = control & SHDLC_CONTROL_NR_MASK; - nfc_shdlc_rcv_s_frame(shdlc, s_frame_type, nr); - kfree_skb(skb); - break; - case SHDLC_CONTROL_HEAD_U: - u_frame_modifier = control & SHDLC_CONTROL_M_MASK; - nfc_shdlc_rcv_u_frame(shdlc, skb, u_frame_modifier); - break; - default: - pr_err("UNKNOWN Control=%d\n", control); - kfree_skb(skb); - break; - } - } -} - -static int nfc_shdlc_w_used(int ns, int dnr) -{ - int unack_count; - - if (dnr <= ns) - unack_count = ns - dnr; - else - unack_count = 8 - dnr + ns; - - return unack_count; -} - -/* Send frames according to algorithm at spec:10.8.1 */ -static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) -{ - struct sk_buff *skb; - int r; - unsigned long time_sent; - - if (shdlc->send_q.qlen) - pr_debug - ("sendQlen=%d ns=%d dnr=%d rnr=%s w_room=%d unackQlen=%d\n", - shdlc->send_q.qlen, shdlc->ns, shdlc->dnr, - shdlc->rnr == false ? "false" : "true", - shdlc->w - nfc_shdlc_w_used(shdlc->ns, shdlc->dnr), - shdlc->ack_pending_q.qlen); - - while (shdlc->send_q.qlen && shdlc->ack_pending_q.qlen < shdlc->w && - (shdlc->rnr == false)) { - - if (shdlc->t1_active) { - del_timer_sync(&shdlc->t1_timer); - shdlc->t1_active = false; - pr_debug("Stopped T1(send ack)\n"); - } - - skb = skb_dequeue(&shdlc->send_q); - - *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_I | (shdlc->ns << 3) | - shdlc->nr; - - pr_debug("Sending I-Frame %d, waiting to rcv %d\n", shdlc->ns, - shdlc->nr); - /* SHDLC_DUMP_SKB("shdlc frame written", skb); */ - - r = shdlc->ops->xmit(shdlc, skb); - if (r < 0) { - shdlc->hard_fault = r; - break; - } - - shdlc->ns = (shdlc->ns + 1) % 8; - - time_sent = jiffies; - *(unsigned long *)skb->cb = time_sent; - - skb_queue_tail(&shdlc->ack_pending_q, skb); - - if (shdlc->t2_active == false) { - shdlc->t2_active = true; - mod_timer(&shdlc->t2_timer, time_sent + - msecs_to_jiffies(SHDLC_T2_VALUE_MS)); - pr_debug("Started T2 (retransmit)\n"); - } - } -} - -static void nfc_shdlc_connect_timeout(unsigned long data) -{ - struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data; - - pr_debug("\n"); - - queue_work(system_nrt_wq, &shdlc->sm_work); -} - -static void nfc_shdlc_t1_timeout(unsigned long data) -{ - struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data; - - pr_debug("SoftIRQ: need to send ack\n"); - - queue_work(system_nrt_wq, &shdlc->sm_work); -} - -static void nfc_shdlc_t2_timeout(unsigned long data) -{ - struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data; - - pr_debug("SoftIRQ: need to retransmit\n"); - - queue_work(system_nrt_wq, &shdlc->sm_work); -} - -static void nfc_shdlc_sm_work(struct work_struct *work) -{ - struct nfc_shdlc *shdlc = container_of(work, struct nfc_shdlc, sm_work); - int r; - - pr_debug("\n"); - - mutex_lock(&shdlc->state_mutex); - - switch (shdlc->state) { - case SHDLC_DISCONNECTED: - skb_queue_purge(&shdlc->rcv_q); - skb_queue_purge(&shdlc->send_q); - skb_queue_purge(&shdlc->ack_pending_q); - break; - case SHDLC_CONNECTING: - if (shdlc->hard_fault) { - nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); - break; - } - - if (shdlc->connect_tries++ < 5) - r = nfc_shdlc_connect_initiate(shdlc); - else - r = -ETIME; - if (r < 0) - nfc_shdlc_connect_complete(shdlc, r); - else { - mod_timer(&shdlc->connect_timer, jiffies + - msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS)); - - shdlc->state = SHDLC_NEGOCIATING; - } - break; - case SHDLC_NEGOCIATING: - if (timer_pending(&shdlc->connect_timer) == 0) { - shdlc->state = SHDLC_CONNECTING; - queue_work(system_nrt_wq, &shdlc->sm_work); - } - - nfc_shdlc_handle_rcv_queue(shdlc); - - if (shdlc->hard_fault) { - nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); - break; - } - break; - case SHDLC_CONNECTED: - nfc_shdlc_handle_rcv_queue(shdlc); - nfc_shdlc_handle_send_queue(shdlc); - - if (shdlc->t1_active && timer_pending(&shdlc->t1_timer) == 0) { - pr_debug - ("Handle T1(send ack) elapsed (T1 now inactive)\n"); - - shdlc->t1_active = false; - r = nfc_shdlc_send_s_frame(shdlc, S_FRAME_RR, - shdlc->nr); - if (r < 0) - shdlc->hard_fault = r; - } - - if (shdlc->t2_active && timer_pending(&shdlc->t2_timer) == 0) { - pr_debug - ("Handle T2(retransmit) elapsed (T2 inactive)\n"); - - shdlc->t2_active = false; - - nfc_shdlc_requeue_ack_pending(shdlc); - nfc_shdlc_handle_send_queue(shdlc); - } - - if (shdlc->hard_fault) { - nfc_hci_driver_failure(shdlc->hdev, shdlc->hard_fault); - } - break; - default: - break; - } - mutex_unlock(&shdlc->state_mutex); -} - -/* - * Called from syscall context to establish shdlc link. Sleeps until - * link is ready or failure. - */ -static int nfc_shdlc_connect(struct nfc_shdlc *shdlc) -{ - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(connect_wq); - - pr_debug("\n"); - - mutex_lock(&shdlc->state_mutex); - - shdlc->state = SHDLC_CONNECTING; - shdlc->connect_wq = &connect_wq; - shdlc->connect_tries = 0; - shdlc->connect_result = 1; - - mutex_unlock(&shdlc->state_mutex); - - queue_work(system_nrt_wq, &shdlc->sm_work); - - wait_event(connect_wq, shdlc->connect_result != 1); - - return shdlc->connect_result; -} - -static void nfc_shdlc_disconnect(struct nfc_shdlc *shdlc) -{ - pr_debug("\n"); - - mutex_lock(&shdlc->state_mutex); - - shdlc->state = SHDLC_DISCONNECTED; - - mutex_unlock(&shdlc->state_mutex); - - queue_work(system_nrt_wq, &shdlc->sm_work); -} - -/* - * Receive an incoming shdlc frame. Frame has already been crc-validated. - * skb contains only LLC header and payload. - * If skb == NULL, it is a notification that the link below is dead. - */ -void nfc_shdlc_recv_frame(struct nfc_shdlc *shdlc, struct sk_buff *skb) -{ - if (skb == NULL) { - pr_err("NULL Frame -> link is dead\n"); - shdlc->hard_fault = -EREMOTEIO; - } else { - SHDLC_DUMP_SKB("incoming frame", skb); - skb_queue_tail(&shdlc->rcv_q, skb); - } - - queue_work(system_nrt_wq, &shdlc->sm_work); -} -EXPORT_SYMBOL(nfc_shdlc_recv_frame); - -static int nfc_shdlc_open(struct nfc_hci_dev *hdev) -{ - struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); - int r; - - pr_debug("\n"); - - if (shdlc->ops->open) { - r = shdlc->ops->open(shdlc); - if (r < 0) - return r; - } - - r = nfc_shdlc_connect(shdlc); - if (r < 0 && shdlc->ops->close) - shdlc->ops->close(shdlc); - - return r; -} - -static void nfc_shdlc_close(struct nfc_hci_dev *hdev) -{ - struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); - - pr_debug("\n"); - - nfc_shdlc_disconnect(shdlc); - - if (shdlc->ops->close) - shdlc->ops->close(shdlc); -} - -static int nfc_shdlc_hci_ready(struct nfc_hci_dev *hdev) -{ - struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); - int r = 0; - - pr_debug("\n"); - - if (shdlc->ops->hci_ready) - r = shdlc->ops->hci_ready(shdlc); - - return r; -} - -static int nfc_shdlc_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb) -{ - struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); - - SHDLC_DUMP_SKB("queuing HCP packet to shdlc", skb); - - skb_queue_tail(&shdlc->send_q, skb); - - queue_work(system_nrt_wq, &shdlc->sm_work); - - return 0; -} - -static int nfc_shdlc_start_poll(struct nfc_hci_dev *hdev, - u32 im_protocols, u32 tm_protocols) -{ - struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); - - pr_debug("\n"); - - if (shdlc->ops->start_poll) - return shdlc->ops->start_poll(shdlc, - im_protocols, tm_protocols); - - return 0; -} - -static int nfc_shdlc_target_from_gate(struct nfc_hci_dev *hdev, u8 gate, - struct nfc_target *target) -{ - struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); - - if (shdlc->ops->target_from_gate) - return shdlc->ops->target_from_gate(shdlc, gate, target); - - return -EPERM; -} - -static int nfc_shdlc_complete_target_discovered(struct nfc_hci_dev *hdev, - u8 gate, - struct nfc_target *target) -{ - struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); - - pr_debug("\n"); - - if (shdlc->ops->complete_target_discovered) - return shdlc->ops->complete_target_discovered(shdlc, gate, - target); - - return 0; -} - -static int nfc_shdlc_data_exchange(struct nfc_hci_dev *hdev, - struct nfc_target *target, - struct sk_buff *skb, - data_exchange_cb_t cb, void *cb_context) -{ - struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); - - if (shdlc->ops->data_exchange) - return shdlc->ops->data_exchange(shdlc, target, skb, cb, - cb_context); - - return -EPERM; -} - -static int nfc_shdlc_check_presence(struct nfc_hci_dev *hdev, - struct nfc_target *target) -{ - struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); - - if (shdlc->ops->check_presence) - return shdlc->ops->check_presence(shdlc, target); - - return 0; -} - -static struct nfc_hci_ops shdlc_ops = { - .open = nfc_shdlc_open, - .close = nfc_shdlc_close, - .hci_ready = nfc_shdlc_hci_ready, - .xmit = nfc_shdlc_xmit, - .start_poll = nfc_shdlc_start_poll, - .target_from_gate = nfc_shdlc_target_from_gate, - .complete_target_discovered = nfc_shdlc_complete_target_discovered, - .data_exchange = nfc_shdlc_data_exchange, - .check_presence = nfc_shdlc_check_presence, -}; - -struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops, - struct nfc_hci_init_data *init_data, - u32 protocols, - int tx_headroom, int tx_tailroom, - int max_link_payload, const char *devname) -{ - struct nfc_shdlc *shdlc; - int r; - - if (ops->xmit == NULL) - return NULL; - - shdlc = kzalloc(sizeof(struct nfc_shdlc), GFP_KERNEL); - if (shdlc == NULL) - return NULL; - - mutex_init(&shdlc->state_mutex); - shdlc->ops = ops; - shdlc->state = SHDLC_DISCONNECTED; - - init_timer(&shdlc->connect_timer); - shdlc->connect_timer.data = (unsigned long)shdlc; - shdlc->connect_timer.function = nfc_shdlc_connect_timeout; - - init_timer(&shdlc->t1_timer); - shdlc->t1_timer.data = (unsigned long)shdlc; - shdlc->t1_timer.function = nfc_shdlc_t1_timeout; - - init_timer(&shdlc->t2_timer); - shdlc->t2_timer.data = (unsigned long)shdlc; - shdlc->t2_timer.function = nfc_shdlc_t2_timeout; - - shdlc->w = SHDLC_MAX_WINDOW; - shdlc->srej_support = SHDLC_SREJ_SUPPORT; - - skb_queue_head_init(&shdlc->rcv_q); - skb_queue_head_init(&shdlc->send_q); - skb_queue_head_init(&shdlc->ack_pending_q); - - INIT_WORK(&shdlc->sm_work, nfc_shdlc_sm_work); - - shdlc->client_headroom = tx_headroom; - shdlc->client_tailroom = tx_tailroom; - - shdlc->hdev = nfc_hci_allocate_device(&shdlc_ops, init_data, protocols, - tx_headroom + SHDLC_LLC_HEAD_ROOM, - tx_tailroom, - max_link_payload); - if (shdlc->hdev == NULL) - goto err_allocdev; - - nfc_hci_set_clientdata(shdlc->hdev, shdlc); - - r = nfc_hci_register_device(shdlc->hdev); - if (r < 0) - goto err_regdev; - - return shdlc; - -err_regdev: - nfc_hci_free_device(shdlc->hdev); - -err_allocdev: - kfree(shdlc); - - return NULL; -} -EXPORT_SYMBOL(nfc_shdlc_allocate); - -void nfc_shdlc_free(struct nfc_shdlc *shdlc) -{ - pr_debug("\n"); - - nfc_hci_unregister_device(shdlc->hdev); - nfc_hci_free_device(shdlc->hdev); - - cancel_work_sync(&shdlc->sm_work); - - skb_queue_purge(&shdlc->rcv_q); - skb_queue_purge(&shdlc->send_q); - skb_queue_purge(&shdlc->ack_pending_q); - - kfree(shdlc); -} -EXPORT_SYMBOL(nfc_shdlc_free); - -void nfc_shdlc_set_clientdata(struct nfc_shdlc *shdlc, void *clientdata) -{ - pr_debug("\n"); - - shdlc->clientdata = clientdata; -} -EXPORT_SYMBOL(nfc_shdlc_set_clientdata); - -void *nfc_shdlc_get_clientdata(struct nfc_shdlc *shdlc) -{ - return shdlc->clientdata; -} -EXPORT_SYMBOL(nfc_shdlc_get_clientdata); - -struct nfc_hci_dev *nfc_shdlc_get_hci_dev(struct nfc_shdlc *shdlc) -{ - return shdlc->hdev; -} -EXPORT_SYMBOL(nfc_shdlc_get_hci_dev); -- cgit v1.2.3 From d6650a2ccfdcf536841c2f880a1a6f19fce2e3a1 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 8 Sep 2012 09:53:22 +0800 Subject: NFC: Move the nfcwilink dereference below the NULL test spatch with a semantic match is used to found this. (http://coccinelle.lip6.fr/) Signed-off-by: Wei Yongjun Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcwilink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c index 827f039ceaf5..50b1ee41afc6 100644 --- a/drivers/nfc/nfcwilink.c +++ b/drivers/nfc/nfcwilink.c @@ -352,8 +352,6 @@ static long nfcwilink_receive(void *priv_data, struct sk_buff *skb) struct nfcwilink *drv = priv_data; int rc; - nfc_dev_dbg(&drv->pdev->dev, "receive entry, len %d", skb->len); - if (!skb) return -EFAULT; @@ -362,6 +360,8 @@ static long nfcwilink_receive(void *priv_data, struct sk_buff *skb) return -EFAULT; } + nfc_dev_dbg(&drv->pdev->dev, "receive entry, len %d", skb->len); + /* strip the ST header (apart for the chnl byte, which is not received in the hdr) */ skb_pull(skb, (NFCWILINK_HDR_LEN-1)); -- cgit v1.2.3 From c51ad34e542606854d0545533329e916689599ba Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 8 Sep 2012 21:19:44 +0800 Subject: NFC: Move the pn544_hci dereference below the NULL test The dereference should be moved below the NULL test. spatch with a semantic match is used to found this. (http://coccinelle.lip6.fr/) Signed-off-by: Wei Yongjun Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544_hci.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c index e681da2e3413..7b0c2176e89b 100644 --- a/drivers/nfc/pn544_hci.c +++ b/drivers/nfc/pn544_hci.c @@ -346,13 +346,16 @@ flush: static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id) { struct pn544_hci_info *info = dev_id; - struct i2c_client *client = info->i2c_dev; + struct i2c_client *client; struct sk_buff *skb = NULL; int r; - BUG_ON(!info); - BUG_ON(irq != info->i2c_dev->irq); + if (!info || irq != info->i2c_dev->irq) { + WARN_ON_ONCE(1); + return IRQ_NONE; + } + client = info->i2c_dev; dev_dbg(&client->dev, "IRQ\n"); if (info->hard_fault != 0) -- cgit v1.2.3 From 7b55279f6a454771d06e8ddf4a7114d17ae9a741 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Tue, 18 Sep 2012 19:31:58 +0200 Subject: NFC: Remove the pn544 raw driver This was scheduled for 3.6, we're late. Signed-off-by: Cong Wang Acked-by: Marcel Holtmann Signed-off-by: Samuel Ortiz --- Documentation/feature-removal-schedule.txt | 12 - drivers/nfc/Kconfig | 12 - drivers/nfc/Makefile | 1 - drivers/nfc/pn544.c | 893 ----------------------------- 4 files changed, 918 deletions(-) delete mode 100644 drivers/nfc/pn544.c (limited to 'drivers') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index afaff312bf41..2cbbac8019c8 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -516,18 +516,6 @@ Who: Kees Cook ---------------------------- -What: Removing the pn544 raw driver. -When: 3.6 -Why: With the introduction of the NFC HCI and SHDL kernel layers, pn544.c - is being replaced by pn544_hci.c which is accessible through the netlink - and socket NFC APIs. Moreover, pn544.c is outdated and does not seem to - work properly with the latest Android stacks. - Having 2 drivers for the same hardware is confusing and as such we - should only keep the one following the kernel NFC APIs. -Who: Samuel Ortiz - ----------------------------- - What: setitimer accepts user NULL pointer (value) When: 3.6 Why: setitimer is not returning -EFAULT if user pointer is NULL. This diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 89c57d1a7cad..ec857676c39f 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -5,18 +5,6 @@ menu "Near Field Communication (NFC) devices" depends on NFC -config PN544_NFC - tristate "PN544 NFC driver" - depends on I2C - select CRC_CCITT - default n - ---help--- - Say yes if you want PN544 Near Field Communication driver. - This is for i2c connected version. If unsure, say N here. - - To compile this driver as a module, choose m here. The module will - be called pn544. - config PN544_HCI_NFC tristate "HCI PN544 NFC driver" depends on I2C && NFC_HCI && NFC_SHDLC diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index 473e44cef612..bf05831fdf09 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -2,7 +2,6 @@ # Makefile for nfc devices # -obj-$(CONFIG_PN544_NFC) += pn544.o obj-$(CONFIG_PN544_HCI_NFC) += pn544_hci.o obj-$(CONFIG_NFC_PN533) += pn533.o obj-$(CONFIG_NFC_WILINK) += nfcwilink.o diff --git a/drivers/nfc/pn544.c b/drivers/nfc/pn544.c deleted file mode 100644 index 724f65d8f9e4..000000000000 --- a/drivers/nfc/pn544.c +++ /dev/null @@ -1,893 +0,0 @@ -/* - * Driver for the PN544 NFC chip. - * - * Copyright (C) Nokia Corporation - * - * Author: Jari Vanhala - * Contact: Matti Aaltonen - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for TCGETS */ -#include - -#define DRIVER_CARD "PN544 NFC" -#define DRIVER_DESC "NFC driver for PN544" - -static struct i2c_device_id pn544_id_table[] = { - { PN544_DRIVER_NAME, 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, pn544_id_table); - -#define HCI_MODE 0 -#define FW_MODE 1 - -enum pn544_state { - PN544_ST_COLD, - PN544_ST_FW_READY, - PN544_ST_READY, -}; - -enum pn544_irq { - PN544_NONE, - PN544_INT, -}; - -struct pn544_info { - struct miscdevice miscdev; - struct i2c_client *i2c_dev; - struct regulator_bulk_data regs[3]; - - enum pn544_state state; - wait_queue_head_t read_wait; - loff_t read_offset; - enum pn544_irq read_irq; - struct mutex read_mutex; /* Serialize read_irq access */ - struct mutex mutex; /* Serialize info struct access */ - u8 *buf; - size_t buflen; -}; - -static const char reg_vdd_io[] = "Vdd_IO"; -static const char reg_vbat[] = "VBat"; -static const char reg_vsim[] = "VSim"; - -/* sysfs interface */ -static ssize_t pn544_test(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct pn544_info *info = dev_get_drvdata(dev); - struct i2c_client *client = info->i2c_dev; - struct pn544_nfc_platform_data *pdata = client->dev.platform_data; - - return snprintf(buf, PAGE_SIZE, "%d\n", pdata->test()); -} - -static int pn544_enable(struct pn544_info *info, int mode) -{ - struct pn544_nfc_platform_data *pdata; - struct i2c_client *client = info->i2c_dev; - - int r; - - r = regulator_bulk_enable(ARRAY_SIZE(info->regs), info->regs); - if (r < 0) - return r; - - pdata = client->dev.platform_data; - info->read_irq = PN544_NONE; - if (pdata->enable) - pdata->enable(mode); - - if (mode) { - info->state = PN544_ST_FW_READY; - dev_dbg(&client->dev, "now in FW-mode\n"); - } else { - info->state = PN544_ST_READY; - dev_dbg(&client->dev, "now in HCI-mode\n"); - } - - usleep_range(10000, 15000); - - return 0; -} - -static void pn544_disable(struct pn544_info *info) -{ - struct pn544_nfc_platform_data *pdata; - struct i2c_client *client = info->i2c_dev; - - pdata = client->dev.platform_data; - if (pdata->disable) - pdata->disable(); - - info->state = PN544_ST_COLD; - - dev_dbg(&client->dev, "Now in OFF-mode\n"); - - msleep(PN544_RESETVEN_TIME); - - info->read_irq = PN544_NONE; - regulator_bulk_disable(ARRAY_SIZE(info->regs), info->regs); -} - -static int check_crc(u8 *buf, int buflen) -{ - u8 len; - u16 crc; - - len = buf[0] + 1; - if (len < 4 || len != buflen || len > PN544_MSG_MAX_SIZE) { - pr_err(PN544_DRIVER_NAME - ": CRC; corrupt packet len %u (%d)\n", len, buflen); - print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, - 16, 2, buf, buflen, false); - return -EPERM; - } - crc = crc_ccitt(0xffff, buf, len - 2); - crc = ~crc; - - if (buf[len-2] != (crc & 0xff) || buf[len-1] != (crc >> 8)) { - pr_err(PN544_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n", - crc, buf[len-1], buf[len-2]); - - print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, - 16, 2, buf, buflen, false); - return -EPERM; - } - return 0; -} - -static int pn544_i2c_write(struct i2c_client *client, u8 *buf, int len) -{ - int r; - - if (len < 4 || len != (buf[0] + 1)) { - dev_err(&client->dev, "%s: Illegal message length: %d\n", - __func__, len); - return -EINVAL; - } - - if (check_crc(buf, len)) - return -EINVAL; - - usleep_range(3000, 6000); - - r = i2c_master_send(client, buf, len); - dev_dbg(&client->dev, "send: %d\n", r); - - if (r == -EREMOTEIO) { /* Retry, chip was in standby */ - usleep_range(6000, 10000); - r = i2c_master_send(client, buf, len); - dev_dbg(&client->dev, "send2: %d\n", r); - } - - if (r != len) - return -EREMOTEIO; - - return r; -} - -static int pn544_i2c_read(struct i2c_client *client, u8 *buf, int buflen) -{ - int r; - u8 len; - - /* - * You could read a packet in one go, but then you'd need to read - * max size and rest would be 0xff fill, so we do split reads. - */ - r = i2c_master_recv(client, &len, 1); - dev_dbg(&client->dev, "recv1: %d\n", r); - - if (r != 1) - return -EREMOTEIO; - - if (len < PN544_LLC_HCI_OVERHEAD) - len = PN544_LLC_HCI_OVERHEAD; - else if (len > (PN544_MSG_MAX_SIZE - 1)) - len = PN544_MSG_MAX_SIZE - 1; - - if (1 + len > buflen) /* len+(data+crc16) */ - return -EMSGSIZE; - - buf[0] = len; - - r = i2c_master_recv(client, buf + 1, len); - dev_dbg(&client->dev, "recv2: %d\n", r); - - if (r != len) - return -EREMOTEIO; - - usleep_range(3000, 6000); - - return r + 1; -} - -static int pn544_fw_write(struct i2c_client *client, u8 *buf, int len) -{ - int r; - - dev_dbg(&client->dev, "%s\n", __func__); - - if (len < PN544_FW_HEADER_SIZE || - (PN544_FW_HEADER_SIZE + (buf[1] << 8) + buf[2]) != len) - return -EINVAL; - - r = i2c_master_send(client, buf, len); - dev_dbg(&client->dev, "fw send: %d\n", r); - - if (r == -EREMOTEIO) { /* Retry, chip was in standby */ - usleep_range(6000, 10000); - r = i2c_master_send(client, buf, len); - dev_dbg(&client->dev, "fw send2: %d\n", r); - } - - if (r != len) - return -EREMOTEIO; - - return r; -} - -static int pn544_fw_read(struct i2c_client *client, u8 *buf, int buflen) -{ - int r, len; - - if (buflen < PN544_FW_HEADER_SIZE) - return -EINVAL; - - r = i2c_master_recv(client, buf, PN544_FW_HEADER_SIZE); - dev_dbg(&client->dev, "FW recv1: %d\n", r); - - if (r < 0) - return r; - - if (r < PN544_FW_HEADER_SIZE) - return -EINVAL; - - len = (buf[1] << 8) + buf[2]; - if (len == 0) /* just header, no additional data */ - return r; - - if (len > buflen - PN544_FW_HEADER_SIZE) - return -EMSGSIZE; - - r = i2c_master_recv(client, buf + PN544_FW_HEADER_SIZE, len); - dev_dbg(&client->dev, "fw recv2: %d\n", r); - - if (r != len) - return -EINVAL; - - return r + PN544_FW_HEADER_SIZE; -} - -static irqreturn_t pn544_irq_thread_fn(int irq, void *dev_id) -{ - struct pn544_info *info = dev_id; - struct i2c_client *client = info->i2c_dev; - - BUG_ON(!info); - BUG_ON(irq != info->i2c_dev->irq); - - dev_dbg(&client->dev, "IRQ\n"); - - mutex_lock(&info->read_mutex); - info->read_irq = PN544_INT; - mutex_unlock(&info->read_mutex); - - wake_up_interruptible(&info->read_wait); - - return IRQ_HANDLED; -} - -static enum pn544_irq pn544_irq_state(struct pn544_info *info) -{ - enum pn544_irq irq; - - mutex_lock(&info->read_mutex); - irq = info->read_irq; - mutex_unlock(&info->read_mutex); - /* - * XXX: should we check GPIO-line status directly? - * return pdata->irq_status() ? PN544_INT : PN544_NONE; - */ - - return irq; -} - -static ssize_t pn544_read(struct file *file, char __user *buf, - size_t count, loff_t *offset) -{ - struct pn544_info *info = container_of(file->private_data, - struct pn544_info, miscdev); - struct i2c_client *client = info->i2c_dev; - enum pn544_irq irq; - size_t len; - int r = 0; - - dev_dbg(&client->dev, "%s: info: %p, count: %zu\n", __func__, - info, count); - - mutex_lock(&info->mutex); - - if (info->state == PN544_ST_COLD) { - r = -ENODEV; - goto out; - } - - irq = pn544_irq_state(info); - if (irq == PN544_NONE) { - if (file->f_flags & O_NONBLOCK) { - r = -EAGAIN; - goto out; - } - - if (wait_event_interruptible(info->read_wait, - (info->read_irq == PN544_INT))) { - r = -ERESTARTSYS; - goto out; - } - } - - if (info->state == PN544_ST_FW_READY) { - len = min(count, info->buflen); - - mutex_lock(&info->read_mutex); - r = pn544_fw_read(info->i2c_dev, info->buf, len); - info->read_irq = PN544_NONE; - mutex_unlock(&info->read_mutex); - - if (r < 0) { - dev_err(&info->i2c_dev->dev, "FW read failed: %d\n", r); - goto out; - } - - print_hex_dump(KERN_DEBUG, "FW read: ", DUMP_PREFIX_NONE, - 16, 2, info->buf, r, false); - - *offset += r; - if (copy_to_user(buf, info->buf, r)) { - r = -EFAULT; - goto out; - } - } else { - len = min(count, info->buflen); - - mutex_lock(&info->read_mutex); - r = pn544_i2c_read(info->i2c_dev, info->buf, len); - info->read_irq = PN544_NONE; - mutex_unlock(&info->read_mutex); - - if (r < 0) { - dev_err(&info->i2c_dev->dev, "read failed (%d)\n", r); - goto out; - } - print_hex_dump(KERN_DEBUG, "read: ", DUMP_PREFIX_NONE, - 16, 2, info->buf, r, false); - - *offset += r; - if (copy_to_user(buf, info->buf, r)) { - r = -EFAULT; - goto out; - } - } - -out: - mutex_unlock(&info->mutex); - - return r; -} - -static unsigned int pn544_poll(struct file *file, poll_table *wait) -{ - struct pn544_info *info = container_of(file->private_data, - struct pn544_info, miscdev); - struct i2c_client *client = info->i2c_dev; - int r = 0; - - dev_dbg(&client->dev, "%s: info: %p\n", __func__, info); - - mutex_lock(&info->mutex); - - if (info->state == PN544_ST_COLD) { - r = -ENODEV; - goto out; - } - - poll_wait(file, &info->read_wait, wait); - - if (pn544_irq_state(info) == PN544_INT) { - r = POLLIN | POLLRDNORM; - goto out; - } -out: - mutex_unlock(&info->mutex); - - return r; -} - -static ssize_t pn544_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct pn544_info *info = container_of(file->private_data, - struct pn544_info, miscdev); - struct i2c_client *client = info->i2c_dev; - ssize_t len; - int r; - - dev_dbg(&client->dev, "%s: info: %p, count %zu\n", __func__, - info, count); - - mutex_lock(&info->mutex); - - if (info->state == PN544_ST_COLD) { - r = -ENODEV; - goto out; - } - - /* - * XXX: should we detect rset-writes and clean possible - * read_irq state - */ - if (info->state == PN544_ST_FW_READY) { - size_t fw_len; - - if (count < PN544_FW_HEADER_SIZE) { - r = -EINVAL; - goto out; - } - - len = min(count, info->buflen); - if (copy_from_user(info->buf, buf, len)) { - r = -EFAULT; - goto out; - } - - print_hex_dump(KERN_DEBUG, "FW write: ", DUMP_PREFIX_NONE, - 16, 2, info->buf, len, false); - - fw_len = PN544_FW_HEADER_SIZE + (info->buf[1] << 8) + - info->buf[2]; - - if (len > fw_len) /* 1 msg at a time */ - len = fw_len; - - r = pn544_fw_write(info->i2c_dev, info->buf, len); - } else { - if (count < PN544_LLC_MIN_SIZE) { - r = -EINVAL; - goto out; - } - - len = min(count, info->buflen); - if (copy_from_user(info->buf, buf, len)) { - r = -EFAULT; - goto out; - } - - print_hex_dump(KERN_DEBUG, "write: ", DUMP_PREFIX_NONE, - 16, 2, info->buf, len, false); - - if (len > (info->buf[0] + 1)) /* 1 msg at a time */ - len = info->buf[0] + 1; - - r = pn544_i2c_write(info->i2c_dev, info->buf, len); - } -out: - mutex_unlock(&info->mutex); - - return r; - -} - -static long pn544_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct pn544_info *info = container_of(file->private_data, - struct pn544_info, miscdev); - struct i2c_client *client = info->i2c_dev; - struct pn544_nfc_platform_data *pdata; - unsigned int val; - int r = 0; - - dev_dbg(&client->dev, "%s: info: %p, cmd: 0x%x\n", __func__, info, cmd); - - mutex_lock(&info->mutex); - - if (info->state == PN544_ST_COLD) { - r = -ENODEV; - goto out; - } - - pdata = info->i2c_dev->dev.platform_data; - switch (cmd) { - case PN544_GET_FW_MODE: - dev_dbg(&client->dev, "%s: PN544_GET_FW_MODE\n", __func__); - - val = (info->state == PN544_ST_FW_READY); - if (copy_to_user((void __user *)arg, &val, sizeof(val))) { - r = -EFAULT; - goto out; - } - - break; - - case PN544_SET_FW_MODE: - dev_dbg(&client->dev, "%s: PN544_SET_FW_MODE\n", __func__); - - if (copy_from_user(&val, (void __user *)arg, sizeof(val))) { - r = -EFAULT; - goto out; - } - - if (val) { - if (info->state == PN544_ST_FW_READY) - break; - - pn544_disable(info); - r = pn544_enable(info, FW_MODE); - if (r < 0) - goto out; - } else { - if (info->state == PN544_ST_READY) - break; - pn544_disable(info); - r = pn544_enable(info, HCI_MODE); - if (r < 0) - goto out; - } - file->f_pos = info->read_offset; - break; - - case TCGETS: - dev_dbg(&client->dev, "%s: TCGETS\n", __func__); - - r = -ENOIOCTLCMD; - break; - - default: - dev_err(&client->dev, "Unknown ioctl 0x%x\n", cmd); - r = -ENOIOCTLCMD; - break; - } - -out: - mutex_unlock(&info->mutex); - - return r; -} - -static int pn544_open(struct inode *inode, struct file *file) -{ - struct pn544_info *info = container_of(file->private_data, - struct pn544_info, miscdev); - struct i2c_client *client = info->i2c_dev; - int r = 0; - - dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__, - info, info->i2c_dev); - - mutex_lock(&info->mutex); - - /* - * Only 1 at a time. - * XXX: maybe user (counter) would work better - */ - if (info->state != PN544_ST_COLD) { - r = -EBUSY; - goto out; - } - - file->f_pos = info->read_offset; - r = pn544_enable(info, HCI_MODE); - -out: - mutex_unlock(&info->mutex); - return r; -} - -static int pn544_close(struct inode *inode, struct file *file) -{ - struct pn544_info *info = container_of(file->private_data, - struct pn544_info, miscdev); - struct i2c_client *client = info->i2c_dev; - - dev_dbg(&client->dev, "%s: info: %p, client %p\n", - __func__, info, info->i2c_dev); - - mutex_lock(&info->mutex); - pn544_disable(info); - mutex_unlock(&info->mutex); - - return 0; -} - -static const struct file_operations pn544_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = pn544_read, - .write = pn544_write, - .poll = pn544_poll, - .open = pn544_open, - .release = pn544_close, - .unlocked_ioctl = pn544_ioctl, -}; - -#ifdef CONFIG_PM -static int pn544_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct pn544_info *info; - int r = 0; - - dev_info(&client->dev, "***\n%s: client %p\n***\n", __func__, client); - - info = i2c_get_clientdata(client); - dev_info(&client->dev, "%s: info: %p, client %p\n", __func__, - info, client); - - mutex_lock(&info->mutex); - - switch (info->state) { - case PN544_ST_FW_READY: - /* Do not suspend while upgrading FW, please! */ - r = -EPERM; - break; - - case PN544_ST_READY: - /* - * CHECK: Device should be in standby-mode. No way to check? - * Allowing low power mode for the regulator is potentially - * dangerous if pn544 does not go to suspension. - */ - break; - - case PN544_ST_COLD: - break; - }; - - mutex_unlock(&info->mutex); - return r; -} - -static int pn544_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct pn544_info *info = i2c_get_clientdata(client); - int r = 0; - - dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__, - info, client); - - mutex_lock(&info->mutex); - - switch (info->state) { - case PN544_ST_READY: - /* - * CHECK: If regulator low power mode is allowed in - * pn544_suspend, we should go back to normal mode - * here. - */ - break; - - case PN544_ST_COLD: - break; - - case PN544_ST_FW_READY: - break; - }; - - mutex_unlock(&info->mutex); - - return r; -} - -static SIMPLE_DEV_PM_OPS(pn544_pm_ops, pn544_suspend, pn544_resume); -#endif - -static struct device_attribute pn544_attr = - __ATTR(nfc_test, S_IRUGO, pn544_test, NULL); - -static int __devinit pn544_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct pn544_info *info; - struct pn544_nfc_platform_data *pdata; - int r = 0; - - dev_dbg(&client->dev, "%s\n", __func__); - dev_dbg(&client->dev, "IRQ: %d\n", client->irq); - - /* private data allocation */ - info = kzalloc(sizeof(struct pn544_info), GFP_KERNEL); - if (!info) { - dev_err(&client->dev, - "Cannot allocate memory for pn544_info.\n"); - r = -ENOMEM; - goto err_info_alloc; - } - - info->buflen = max(PN544_MSG_MAX_SIZE, PN544_MAX_I2C_TRANSFER); - info->buf = kzalloc(info->buflen, GFP_KERNEL); - if (!info->buf) { - dev_err(&client->dev, - "Cannot allocate memory for pn544_info->buf.\n"); - r = -ENOMEM; - goto err_buf_alloc; - } - - info->regs[0].supply = reg_vdd_io; - info->regs[1].supply = reg_vbat; - info->regs[2].supply = reg_vsim; - r = regulator_bulk_get(&client->dev, ARRAY_SIZE(info->regs), - info->regs); - if (r < 0) - goto err_kmalloc; - - info->i2c_dev = client; - info->state = PN544_ST_COLD; - info->read_irq = PN544_NONE; - mutex_init(&info->read_mutex); - mutex_init(&info->mutex); - init_waitqueue_head(&info->read_wait); - i2c_set_clientdata(client, info); - pdata = client->dev.platform_data; - if (!pdata) { - dev_err(&client->dev, "No platform data\n"); - r = -EINVAL; - goto err_reg; - } - - if (!pdata->request_resources) { - dev_err(&client->dev, "request_resources() missing\n"); - r = -EINVAL; - goto err_reg; - } - - r = pdata->request_resources(client); - if (r) { - dev_err(&client->dev, "Cannot get platform resources\n"); - goto err_reg; - } - - r = request_threaded_irq(client->irq, NULL, pn544_irq_thread_fn, - IRQF_TRIGGER_RISING, PN544_DRIVER_NAME, - info); - if (r < 0) { - dev_err(&client->dev, "Unable to register IRQ handler\n"); - goto err_res; - } - - /* If we don't have the test we don't need the sysfs file */ - if (pdata->test) { - r = device_create_file(&client->dev, &pn544_attr); - if (r) { - dev_err(&client->dev, - "sysfs registration failed, error %d\n", r); - goto err_irq; - } - } - - info->miscdev.minor = MISC_DYNAMIC_MINOR; - info->miscdev.name = PN544_DRIVER_NAME; - info->miscdev.fops = &pn544_fops; - info->miscdev.parent = &client->dev; - r = misc_register(&info->miscdev); - if (r < 0) { - dev_err(&client->dev, "Device registration failed\n"); - goto err_sysfs; - } - - dev_dbg(&client->dev, "%s: info: %p, pdata %p, client %p\n", - __func__, info, pdata, client); - - return 0; - -err_sysfs: - if (pdata->test) - device_remove_file(&client->dev, &pn544_attr); -err_irq: - free_irq(client->irq, info); -err_res: - if (pdata->free_resources) - pdata->free_resources(); -err_reg: - regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs); -err_kmalloc: - kfree(info->buf); -err_buf_alloc: - kfree(info); -err_info_alloc: - return r; -} - -static __devexit int pn544_remove(struct i2c_client *client) -{ - struct pn544_info *info = i2c_get_clientdata(client); - struct pn544_nfc_platform_data *pdata = client->dev.platform_data; - - dev_dbg(&client->dev, "%s\n", __func__); - - misc_deregister(&info->miscdev); - if (pdata->test) - device_remove_file(&client->dev, &pn544_attr); - - if (info->state != PN544_ST_COLD) { - if (pdata->disable) - pdata->disable(); - - info->read_irq = PN544_NONE; - } - - free_irq(client->irq, info); - if (pdata->free_resources) - pdata->free_resources(); - - regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs); - kfree(info->buf); - kfree(info); - - return 0; -} - -static struct i2c_driver pn544_driver = { - .driver = { - .name = PN544_DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &pn544_pm_ops, -#endif - }, - .probe = pn544_probe, - .id_table = pn544_id_table, - .remove = __devexit_p(pn544_remove), -}; - -static int __init pn544_init(void) -{ - int r; - - pr_debug(DRIVER_DESC ": %s\n", __func__); - - r = i2c_add_driver(&pn544_driver); - if (r) { - pr_err(PN544_DRIVER_NAME ": driver registration failed\n"); - return r; - } - - return 0; -} - -static void __exit pn544_exit(void) -{ - i2c_del_driver(&pn544_driver); - pr_info(DRIVER_DESC ", Exiting.\n"); -} - -module_init(pn544_init); -module_exit(pn544_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION(DRIVER_DESC); -- cgit v1.2.3 From 96e324024b421b3753eb142d5d92fbe4ac5e7519 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 20 Sep 2012 08:59:10 +0200 Subject: NFC: xmit from hci ops must return 0 or negative xmit callback provided by a driver encapsulates upper layers data and sends it to the hardware. So, HCI does not know the exact amount of data being sent and thus can't handle partially sent frames properly. Therefore, the driver must return 0 for completely sent frame or negative for failure. Signed-off-by: Waldemar Rymarkiewicz Acked-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544_hci.c | 8 ++++++-- include/net/nfc/hci.h | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c index 7b0c2176e89b..c9c8570273ab 100644 --- a/drivers/nfc/pn544_hci.c +++ b/drivers/nfc/pn544_hci.c @@ -235,8 +235,12 @@ static int pn544_hci_i2c_write(struct i2c_client *client, u8 *buf, int len) r = i2c_master_send(client, buf, len); } - if (r >= 0 && r != len) - r = -EREMOTEIO; + if (r >= 0) { + if (r != len) + return -EREMOTEIO; + else + return 0; + } return r; } diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 9b5ed2d94d60..e900072950cb 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -30,6 +30,11 @@ struct nfc_hci_ops { int (*open) (struct nfc_hci_dev *hdev); void (*close) (struct nfc_hci_dev *hdev); int (*hci_ready) (struct nfc_hci_dev *hdev); + /* + * xmit must always send the complete buffer before + * returning. Returned result must be 0 for success + * or negative for failure. + */ int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb); int (*start_poll) (struct nfc_hci_dev *hdev, u32 im_protocols, u32 tm_protocols); -- 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') 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') 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') 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') 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') 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') 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 From ee5e8d812ca25bf95a97b4368aec4e680678e75e Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Thu, 27 Sep 2012 09:16:54 +0200 Subject: NFC: Fix missing mutex unlock in pn533_send_cmd_frame_async If command allocation failed cmd_lock was not released and deadlock would occur. Signed-off-by: Szymon Janc Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index d123444404c8..97c440a8cd61 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -716,7 +716,7 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev, void *arg, gfp_t flags) { struct pn533_cmd *cmd; - int rc; + int rc = 0; nfc_dev_dbg(&dev->interface->dev, "%s", __func__); @@ -729,16 +729,16 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev, if (!rc) dev->cmd_pending = 1; - mutex_unlock(&dev->cmd_lock); - - return rc; + goto unlock; } nfc_dev_dbg(&dev->interface->dev, "%s Queueing command", __func__); cmd = kzalloc(sizeof(struct pn533_cmd), flags); - if (!cmd) - return -ENOMEM; + if (!cmd) { + rc = -ENOMEM; + goto unlock; + } INIT_LIST_HEAD(&cmd->queue); cmd->out_frame = out_frame; @@ -750,9 +750,10 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev, list_add_tail(&cmd->queue, &dev->cmd_queue); +unlock: mutex_unlock(&dev->cmd_lock); - return 0; + return rc; } struct pn533_sync_cmd_response { -- cgit v1.2.3