From 178bdb5791f18e33b5a368acee6fab5bb64396fe Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 14 Apr 2013 16:28:39 +0300 Subject: iwlwifi: mvm: remove TODO which has been addressed Chain noise is done in the firmware and Bluetooth Coexistence is implemented now. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index 0f0b44eabd93..a28a1d1f23eb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c @@ -153,11 +153,6 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, cmd->ci.ctrl_pos = iwl_mvm_get_ctrl_pos(chandef); /* Set rx the chains */ - - /* TODO: - * Need to add on chain noise calibration limitations, and - * BT coex considerations. - */ idle_cnt = chains_static; active_cnt = chains_dynamic; -- cgit v1.2.3 From d7dad550e6ddb96db9d3e4d322f7d1dd8a6a9c8d Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 14 Apr 2013 14:41:03 +0300 Subject: iwlwifi: mvm: fix first_antenna first_antenna is supposed to return the first antenna as a 0-based bitmap: ANT_A is BIT(0), ANT_B is BIT(1), etc... Since ffs is 1 based (ffs(BIT(0)) = 1), then we had an off-by-one bug: BIT(ffs(ANT_A)) = BIT(ffs(BIT(0))) = BIT(1) = ANT_B. So what we really want is: BIT(ffs(ANT_A) - 1) = BIT(ffs(BIT(0)) - 1) = BIT(0) = ANT_A. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/utils.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 0cc8d8c0d393..687b34e387ac 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -253,8 +253,9 @@ int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, u8 first_antenna(u8 mask) { BUILD_BUG_ON(ANT_A != BIT(0)); /* using ffs is wrong if not */ - WARN_ON_ONCE(!mask); /* ffs will return 0 if mask is zeroed */ - return (u8)(BIT(ffs(mask))); + if (WARN_ON_ONCE(!mask)) /* ffs will return 0 if mask is zeroed */ + return BIT(0); + return BIT(ffs(mask) - 1); } /* -- cgit v1.2.3 From 0aed849f61c1235041f98e4178d0a60aaa1dc548 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Sun, 14 Apr 2013 10:18:25 +0300 Subject: iwlwifi: mvm: change TX/RX AM-to-PSM transition time for LP mode Recently in low power (LP) mode FW moved from active to power save mode after TX/RX completion faster than in balanced power mode (BPS). Change AM-to-PSM transition time so that it will be the same as for BPS. Signed-off-by: Alexander Bondar Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/power.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 9395ab2a1af2..dde384de3ae2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -146,14 +146,8 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); cmd->keep_alive_seconds = keep_alive; - if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP) { - /* TODO: Also for D3 (device sleep / WoWLAN) */ - cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); - cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); - } else { - cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); - cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); - } + cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); + cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); } int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -- cgit v1.2.3 From 3309ccf7fcebceef540ebe90c65d2f94d745a45b Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 16 Apr 2013 15:38:29 +0200 Subject: iwlwifi: fix freeing uninitialized pointer If on iwl_dump_nic_event_log() error occurs before that function initialize buf, we process uninitiated pointer in iwl_dbgfs_log_event_read() and can hit "BUG at mm/slub.c:3409" Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=951241 Cc: stable@vger.kernel.org Reported-by: ian.odette@eprize.com Signed-off-by: Stanislaw Gruszka Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/debugfs.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index 7b8178be119f..cb6dd5813fbc 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -2237,15 +2237,15 @@ static ssize_t iwl_dbgfs_log_event_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - char *buf; - int pos = 0; - ssize_t ret = -ENOMEM; + char *buf = NULL; + ssize_t ret; - ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true); - if (buf) { - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - } + ret = iwl_dump_nic_event_log(priv, true, &buf, true); + if (ret < 0) + goto err; + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); +err: + kfree(buf); return ret; } -- cgit v1.2.3 From a6db00613bd6a0c631848b0debe1d3f7ce67c77d Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 16 Apr 2013 15:40:54 +0200 Subject: iwlwifi: remove redundant argument from iwl_dump_nic_event_log We can check buf against NULL instead of having additional bool variable. Signed-off-by: Stanislaw Gruszka Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/agn.h | 2 +- drivers/net/wireless/iwlwifi/dvm/debugfs.c | 4 ++-- drivers/net/wireless/iwlwifi/dvm/main.c | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index e575b9b0cda8..48545ab00311 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -172,7 +172,7 @@ int iwl_calib_set(struct iwl_priv *priv, const struct iwl_calib_hdr *cmd, int len); void iwl_calib_free_results(struct iwl_priv *priv); int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, - char **buf, bool display); + char **buf); int iwlagn_hw_valid_rtc_data_addr(u32 addr); /* lib */ diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index cb6dd5813fbc..17f04de272d8 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -2240,7 +2240,7 @@ static ssize_t iwl_dbgfs_log_event_read(struct file *file, char *buf = NULL; ssize_t ret; - ret = iwl_dump_nic_event_log(priv, true, &buf, true); + ret = iwl_dump_nic_event_log(priv, true, &buf); if (ret < 0) goto err; ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); @@ -2269,7 +2269,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, if (sscanf(buf, "%d", &event_log_flag) != 1) return -EFAULT; if (event_log_flag == 1) - iwl_dump_nic_event_log(priv, true, NULL, false); + iwl_dump_nic_event_log(priv, true, NULL); return count; } diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index b9e3517652d6..74d7572e7091 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -1795,7 +1795,7 @@ static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, #define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, - char **buf, bool display) + char **buf) { u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ @@ -1866,7 +1866,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, size); #ifdef CONFIG_IWLWIFI_DEBUG - if (display) { + if (buf) { if (full_log) bufsz = capacity * 48; else @@ -1962,7 +1962,7 @@ static void iwl_nic_error(struct iwl_op_mode *op_mode) priv->fw->fw_version); iwl_dump_nic_error_log(priv); - iwl_dump_nic_event_log(priv, false, NULL, false); + iwl_dump_nic_event_log(priv, false, NULL); iwlagn_fw_error(priv, false); } -- cgit v1.2.3 From ade50652fc60314f433c6d28322a605874fb3996 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Wed, 3 Apr 2013 16:28:47 +0300 Subject: iwlwifi: mvm: remove usage of power_save module parameter Make power management in MVM driver enabled by default and remove using the power_save module parameter. Rely only on the power_scheme parameter to decide if power management should be used. Signed-off-by: Alexander Bondar Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/mvm/power.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index fe031608fd91..dd158ec571fb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -207,7 +207,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->hw_version = mvm->trans->hw_id; - if (iwlwifi_mod_params.power_save) + if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; else hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index dde384de3ae2..ed77e437aac4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -111,8 +111,7 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, */ cmd->keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC; - if ((iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) || - !iwlwifi_mod_params.power_save) + if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); @@ -171,8 +170,7 @@ int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; - if ((iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) && - iwlwifi_mod_params.power_save) + if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); iwl_mvm_power_log(mvm, &cmd); -- cgit v1.2.3 From d557894106f71cc23c9d053876d0c367c285950f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 17 Apr 2013 08:23:50 +0200 Subject: iwlwifi: remove unneeded goto from iwl_dbgfs_log_event_read Make code simpler a bit. Reported-by: Jonas Gorski Signed-off-by: Stanislaw Gruszka Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/debugfs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index 17f04de272d8..d5329489245a 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -2241,10 +2241,8 @@ static ssize_t iwl_dbgfs_log_event_read(struct file *file, ssize_t ret; ret = iwl_dump_nic_event_log(priv, true, &buf); - if (ret < 0) - goto err; - ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); -err: + if (ret > 0) + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); kfree(buf); return ret; } -- cgit v1.2.3 From 63b77bf489881747c5118476918cc8c29378ee63 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 17 Apr 2013 09:47:00 +0300 Subject: iwlwifi: dvm: don't send zeroed LQ cmd When the stations are being restored because of unassoc RXON, the LQ cmd may not have been initialized because it is initialized only after association. Sending zeroed LQ_CMD makes the fw unhappy: it raises SYSASSERT_2078. Cc: stable@vger.kernel.org Signed-off-by: Emmanuel Grumbach Reviewed-by: Johannes Berg [move zero_lq and make static const] Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/sta.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index b775769f8322..db183b44e038 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -695,6 +695,7 @@ void iwl_clear_ucode_stations(struct iwl_priv *priv, void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { struct iwl_addsta_cmd sta_cmd; + static const struct iwl_link_quality_cmd zero_lq = {}; struct iwl_link_quality_cmd lq; int i; bool found = false; @@ -733,7 +734,9 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx) else memcpy(&lq, priv->stations[i].lq, sizeof(struct iwl_link_quality_cmd)); - send_lq = true; + + if (!memcmp(&lq, &zero_lq, sizeof(lq))) + send_lq = true; } spin_unlock_bh(&priv->sta_lock); ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); -- cgit v1.2.3 From 499892f2a9ad89910ff21c687273ac80b4367dc0 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 17 Apr 2013 11:03:57 +0300 Subject: iwlwifi: add a subdevice ID for 7000 series Add another ID for a 7000 series device. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/drv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 0016bb24b3d7..8cb53ec2b77b 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -256,6 +256,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { /* 7000 Series */ {IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x08B1, 0x4062, iwl7260_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B1, 0xC070, iwl7260_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B3, 0x0070, iwl3160_ac_cfg)}, {IWL_PCI_DEVICE(0x08B3, 0x8070, iwl3160_ac_cfg)}, -- cgit v1.2.3 From faff7f74d2f945527ef92d68e501d9e8adaca750 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 18 Apr 2013 19:35:33 -0300 Subject: Bluetooth: remove unneeded var initialization in btmrvl There is no need to init ret to zero in btmrvl_sdio_download_fw(). Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btmrvl_sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 1cb51839912d..0e9e8e95916d 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -874,7 +874,7 @@ exit: static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) { - int ret = 0; + int ret; u8 fws0; int pollnum = MAX_POLL_TRIES; -- cgit v1.2.3 From dffd30ee9619ccd7153f1861ba0436bbc4400f36 Mon Sep 17 00:00:00 2001 From: Tedd Ho-Jeong An Date: Fri, 19 Apr 2013 09:57:43 -0700 Subject: Bluetooth: Add support for Intel Bluetooth device [8087:07dc] This patch adds support for Intel Bluetooth device by adding btusb_setup_intel() routine that update the device with ROM patch. T: Bus=02 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=8087 ProdID=07dc Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 64 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Tedd Ho-Jeong An Acked-by: Marcel Holtmann Acked-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btusb.c | 377 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 3d684d20b584..7a7e5f8ecadc 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -47,6 +48,7 @@ static struct usb_driver btusb_driver; #define BTUSB_BROKEN_ISOC 0x20 #define BTUSB_WRONG_SCO_MTU 0x40 #define BTUSB_ATH3012 0x80 +#define BTUSB_INTEL 0x100 static struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -207,6 +209,9 @@ static struct usb_device_id blacklist_table[] = { /* Frontline ComProbe Bluetooth Sniffer */ { USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER }, + /* Intel Bluetooth device */ + { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, + { } /* Terminating entry */ }; @@ -943,6 +948,375 @@ static int btusb_setup_bcm92035(struct hci_dev *hdev) return 0; } +struct intel_version { + u8 status; + u8 hw_platform; + u8 hw_variant; + u8 hw_revision; + u8 fw_variant; + u8 fw_revision; + u8 fw_build_num; + u8 fw_build_ww; + u8 fw_build_yy; + u8 fw_patch_num; +} __packed; + +static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev, + struct intel_version *ver) +{ + const struct firmware *fw; + char fwname[64]; + int ret; + + snprintf(fwname, sizeof(fwname), + "intel/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.bseq", + ver->hw_platform, ver->hw_variant, ver->hw_revision, + ver->fw_variant, ver->fw_revision, ver->fw_build_num, + ver->fw_build_ww, ver->fw_build_yy); + + ret = request_firmware(&fw, fwname, &hdev->dev); + if (ret < 0) { + if (ret == -EINVAL) { + BT_ERR("%s Intel firmware file request failed (%d)", + hdev->name, ret); + return NULL; + } + + BT_ERR("%s failed to open Intel firmware file: %s(%d)", + hdev->name, fwname, ret); + + /* If the correct firmware patch file is not found, use the + * default firmware patch file instead + */ + snprintf(fwname, sizeof(fwname), "intel/ibt-hw-%x.%x.bseq", + ver->hw_platform, ver->hw_variant); + if (request_firmware(&fw, fwname, &hdev->dev) < 0) { + BT_ERR("%s failed to open default Intel fw file: %s", + hdev->name, fwname); + return NULL; + } + } + + BT_INFO("%s: Intel Bluetooth firmware file: %s", hdev->name, fwname); + + return fw; +} + +static int btusb_setup_intel_patching(struct hci_dev *hdev, + const struct firmware *fw, + const u8 **fw_ptr, int *disable_patch) +{ + struct sk_buff *skb; + struct hci_command_hdr *cmd; + const u8 *cmd_param; + struct hci_event_hdr *evt = NULL; + const u8 *evt_param = NULL; + int remain = fw->size - (*fw_ptr - fw->data); + + /* The first byte indicates the types of the patch command or event. + * 0x01 means HCI command and 0x02 is HCI event. If the first bytes + * in the current firmware buffer doesn't start with 0x01 or + * the size of remain buffer is smaller than HCI command header, + * the firmware file is corrupted and it should stop the patching + * process. + */ + if (remain > HCI_COMMAND_HDR_SIZE && *fw_ptr[0] != 0x01) { + BT_ERR("%s Intel fw corrupted: invalid cmd read", hdev->name); + return -EINVAL; + } + (*fw_ptr)++; + remain--; + + cmd = (struct hci_command_hdr *)(*fw_ptr); + *fw_ptr += sizeof(*cmd); + remain -= sizeof(*cmd); + + /* Ensure that the remain firmware data is long enough than the length + * of command parameter. If not, the firmware file is corrupted. + */ + if (remain < cmd->plen) { + BT_ERR("%s Intel fw corrupted: invalid cmd len", hdev->name); + return -EFAULT; + } + + /* If there is a command that loads a patch in the firmware + * file, then enable the patch upon success, otherwise just + * disable the manufacturer mode, for example patch activation + * is not required when the default firmware patch file is used + * because there are no patch data to load. + */ + if (*disable_patch && le16_to_cpu(cmd->opcode) == 0xfc8e) + *disable_patch = 0; + + cmd_param = *fw_ptr; + *fw_ptr += cmd->plen; + remain -= cmd->plen; + + /* This reads the expected events when the above command is sent to the + * device. Some vendor commands expects more than one events, for + * example command status event followed by vendor specific event. + * For this case, it only keeps the last expected event. so the command + * can be sent with __hci_cmd_sync_ev() which returns the sk_buff of + * last expected event. + */ + while (remain > HCI_EVENT_HDR_SIZE && *fw_ptr[0] == 0x02) { + (*fw_ptr)++; + remain--; + + evt = (struct hci_event_hdr *)(*fw_ptr); + *fw_ptr += sizeof(*evt); + remain -= sizeof(*evt); + + if (remain < evt->plen) { + BT_ERR("%s Intel fw corrupted: invalid evt len", + hdev->name); + return -EFAULT; + } + + evt_param = *fw_ptr; + *fw_ptr += evt->plen; + remain -= evt->plen; + } + + /* Every HCI commands in the firmware file has its correspond event. + * If event is not found or remain is smaller than zero, the firmware + * file is corrupted. + */ + if (!evt || !evt_param || remain < 0) { + BT_ERR("%s Intel fw corrupted: invalid evt read", hdev->name); + return -EFAULT; + } + + skb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cmd->opcode), cmd->plen, + cmd_param, evt->evt, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s sending Intel patch command (0x%4.4x) failed (%ld)", + hdev->name, cmd->opcode, PTR_ERR(skb)); + return -PTR_ERR(skb); + } + + /* It ensures that the returned event matches the event data read from + * the firmware file. At fist, it checks the length and then + * the contents of the event. + */ + if (skb->len != evt->plen) { + BT_ERR("%s mismatch event length (opcode 0x%4.4x)", hdev->name, + le16_to_cpu(cmd->opcode)); + kfree_skb(skb); + return -EFAULT; + } + + if (memcmp(skb->data, evt_param, evt->plen)) { + BT_ERR("%s mismatch event parameter (opcode 0x%4.4x)", + hdev->name, le16_to_cpu(cmd->opcode)); + kfree_skb(skb); + return -EFAULT; + } + kfree_skb(skb); + + return 0; +} + +static int btusb_setup_intel(struct hci_dev *hdev) +{ + struct sk_buff *skb; + const struct firmware *fw; + const u8 *fw_ptr; + int disable_patch; + struct intel_version *ver; + + const u8 mfg_enable[] = { 0x01, 0x00 }; + const u8 mfg_disable[] = { 0x00, 0x00 }; + const u8 mfg_reset_deactivate[] = { 0x00, 0x01 }; + const u8 mfg_reset_activate[] = { 0x00, 0x02 }; + + BT_DBG("%s", hdev->name); + + /* The controller has a bug with the first HCI command sent to it + * returning number of completed commands as zero. This would stall the + * command processing in the Bluetooth core. + * + * As a workaround, send HCI Reset command first which will reset the + * number of completed commands and allow normal command processing + * from now on. + */ + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s sending initial HCI reset command failed (%ld)", + hdev->name, PTR_ERR(skb)); + return -PTR_ERR(skb); + } + kfree_skb(skb); + + /* Read Intel specific controller version first to allow selection of + * which firmware file to load. + * + * The returned information are hardware variant and revision plus + * firmware variant, revision and build number. + */ + skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s reading Intel fw version command failed (%ld)", + hdev->name, PTR_ERR(skb)); + return -PTR_ERR(skb); + } + + if (skb->len != sizeof(*ver)) { + BT_ERR("%s Intel version event length mismatch", hdev->name); + kfree_skb(skb); + return -EIO; + } + + ver = (struct intel_version *)skb->data; + if (ver->status) { + BT_ERR("%s Intel fw version event failed (%02x)", hdev->name, + ver->status); + kfree_skb(skb); + return -bt_to_errno(ver->status); + } + + BT_INFO("%s: read Intel version: %02x%02x%02x%02x%02x%02x%02x%02x%02x", + hdev->name, ver->hw_platform, ver->hw_variant, + ver->hw_revision, ver->fw_variant, ver->fw_revision, + ver->fw_build_num, ver->fw_build_ww, ver->fw_build_yy, + ver->fw_patch_num); + + /* fw_patch_num indicates the version of patch the device currently + * have. If there is no patch data in the device, it is always 0x00. + * So, if it is other than 0x00, no need to patch the deivce again. + */ + if (ver->fw_patch_num) { + BT_INFO("%s: Intel device is already patched. patch num: %02x", + hdev->name, ver->fw_patch_num); + kfree_skb(skb); + return 0; + } + + /* Opens the firmware patch file based on the firmware version read + * from the controller. If it fails to open the matching firmware + * patch file, it tries to open the default firmware patch file. + * If no patch file is found, allow the device to operate without + * a patch. + */ + fw = btusb_setup_intel_get_fw(hdev, ver); + if (!fw) { + kfree_skb(skb); + return 0; + } + fw_ptr = fw->data; + + /* This Intel specific command enables the manufacturer mode of the + * controller. + * + * Only while this mode is enabled, the driver can download the + * firmware patch data and configuration parameters. + */ + skb = __hci_cmd_sync(hdev, 0xfc11, 2, mfg_enable, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s entering Intel manufacturer mode failed (%ld)", + hdev->name, PTR_ERR(skb)); + release_firmware(fw); + return -PTR_ERR(skb); + } + + if (skb->data[0]) { + u8 evt_status = skb->data[0]; + BT_ERR("%s enable Intel manufacturer mode event failed (%02x)", + hdev->name, evt_status); + kfree_skb(skb); + release_firmware(fw); + return -bt_to_errno(evt_status); + } + kfree_skb(skb); + + disable_patch = 1; + + /* The firmware data file consists of list of Intel specific HCI + * commands and its expected events. The first byte indicates the + * type of the message, either HCI command or HCI event. + * + * It reads the command and its expected event from the firmware file, + * and send to the controller. Once __hci_cmd_sync_ev() returns, + * the returned event is compared with the event read from the firmware + * file and it will continue until all the messages are downloaded to + * the controller. + * + * Once the firmware patching is completed successfully, + * the manufacturer mode is disabled with reset and activating the + * downloaded patch. + * + * If the firmware patching fails, the manufacturer mode is + * disabled with reset and deactivating the patch. + * + * If the default patch file is used, no reset is done when disabling + * the manufacturer. + */ + while (fw->size > fw_ptr - fw->data) { + int ret; + + ret = btusb_setup_intel_patching(hdev, fw, &fw_ptr, + &disable_patch); + if (ret < 0) + goto exit_mfg_deactivate; + } + + release_firmware(fw); + + if (disable_patch) + goto exit_mfg_disable; + + /* Patching completed successfully and disable the manufacturer mode + * with reset and activate the downloaded firmware patches. + */ + skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_reset_activate), + mfg_reset_activate, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s exiting Intel manufacturer mode failed (%ld)", + hdev->name, PTR_ERR(skb)); + return -PTR_ERR(skb); + } + kfree_skb(skb); + + BT_INFO("%s: Intel Bluetooth firmware patch completed and activated", + hdev->name); + + return 0; + +exit_mfg_disable: + /* Disable the manufacturer mode without reset */ + skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_disable), mfg_disable, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s exiting Intel manufacturer mode failed (%ld)", + hdev->name, PTR_ERR(skb)); + return -PTR_ERR(skb); + } + kfree_skb(skb); + + BT_INFO("%s: Intel Bluetooth firmware patch completed", hdev->name); + return 0; + +exit_mfg_deactivate: + release_firmware(fw); + + /* Patching failed. Disable the manufacturer mode with reset and + * deactivate the downloaded firmware patches. + */ + skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_reset_deactivate), + mfg_reset_deactivate, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s exiting Intel manufacturer mode failed (%ld)", + hdev->name, PTR_ERR(skb)); + return -PTR_ERR(skb); + } + kfree_skb(skb); + + BT_INFO("%s: Intel Bluetooth firmware patch completed and deactivated", + hdev->name); + + return 0; +} + static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1048,6 +1422,9 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BCM92035) hdev->setup = btusb_setup_bcm92035; + if (id->driver_info & BTUSB_INTEL) + hdev->setup = btusb_setup_intel; + /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); -- cgit v1.2.3 From 9da226c7919aaed40e0195f0b7c7713ed00e380f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Apr 2013 12:53:46 +0300 Subject: Bluetooth: btmrvl: use native helpers for debugfs Clean up the code by using native debugfs helpers, instead of implementing them ourselves: debugfs_create_u8() debugfs_create_x16() debugfs_create_file() debugfs_remove_recursive() Signed-off-by: Andy Shevchenko Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btmrvl_debugfs.c | 266 +++---------------------------------- 1 file changed, 22 insertions(+), 244 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c index 428dbb7574bd..db2c3c305df8 100644 --- a/drivers/bluetooth/btmrvl_debugfs.c +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -29,20 +29,6 @@ struct btmrvl_debugfs_data { struct dentry *config_dir; struct dentry *status_dir; - - /* config */ - struct dentry *psmode; - struct dentry *pscmd; - struct dentry *hsmode; - struct dentry *hscmd; - struct dentry *gpiogap; - struct dentry *hscfgcmd; - - /* status */ - struct dentry *curpsmode; - struct dentry *hsstate; - struct dentry *psstate; - struct dentry *txdnldready; }; static ssize_t btmrvl_hscfgcmd_write(struct file *file, @@ -91,47 +77,6 @@ static const struct file_operations btmrvl_hscfgcmd_fops = { .llseek = default_llseek, }; -static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) -{ - struct btmrvl_private *priv = file->private_data; - char buf[16]; - long result, ret; - - memset(buf, 0, sizeof(buf)); - - if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) - return -EFAULT; - - ret = strict_strtol(buf, 10, &result); - if (ret) - return ret; - - priv->btmrvl_dev.psmode = result; - - return count; -} - -static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct btmrvl_private *priv = file->private_data; - char buf[16]; - int ret; - - ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->btmrvl_dev.psmode); - - return simple_read_from_buffer(userbuf, count, ppos, buf, ret); -} - -static const struct file_operations btmrvl_psmode_fops = { - .read = btmrvl_psmode_read, - .write = btmrvl_psmode_write, - .open = simple_open, - .llseek = default_llseek, -}; - static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { @@ -178,47 +123,6 @@ static const struct file_operations btmrvl_pscmd_fops = { .llseek = default_llseek, }; -static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) -{ - struct btmrvl_private *priv = file->private_data; - char buf[16]; - long result, ret; - - memset(buf, 0, sizeof(buf)); - - if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) - return -EFAULT; - - ret = strict_strtol(buf, 16, &result); - if (ret) - return ret; - - priv->btmrvl_dev.gpio_gap = result; - - return count; -} - -static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct btmrvl_private *priv = file->private_data; - char buf[16]; - int ret; - - ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n", - priv->btmrvl_dev.gpio_gap); - - return simple_read_from_buffer(userbuf, count, ppos, buf, ret); -} - -static const struct file_operations btmrvl_gpiogap_fops = { - .read = btmrvl_gpiogap_read, - .write = btmrvl_gpiogap_write, - .open = simple_open, - .llseek = default_llseek, -}; - static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { @@ -263,119 +167,6 @@ static const struct file_operations btmrvl_hscmd_fops = { .llseek = default_llseek, }; -static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) -{ - struct btmrvl_private *priv = file->private_data; - char buf[16]; - long result, ret; - - memset(buf, 0, sizeof(buf)); - - if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) - return -EFAULT; - - ret = strict_strtol(buf, 10, &result); - if (ret) - return ret; - - priv->btmrvl_dev.hsmode = result; - - return count; -} - -static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) -{ - struct btmrvl_private *priv = file->private_data; - char buf[16]; - int ret; - - ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hsmode); - - return simple_read_from_buffer(userbuf, count, ppos, buf, ret); -} - -static const struct file_operations btmrvl_hsmode_fops = { - .read = btmrvl_hsmode_read, - .write = btmrvl_hsmode_write, - .open = simple_open, - .llseek = default_llseek, -}; - -static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct btmrvl_private *priv = file->private_data; - char buf[16]; - int ret; - - ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode); - - return simple_read_from_buffer(userbuf, count, ppos, buf, ret); -} - -static const struct file_operations btmrvl_curpsmode_fops = { - .read = btmrvl_curpsmode_read, - .open = simple_open, - .llseek = default_llseek, -}; - -static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) -{ - struct btmrvl_private *priv = file->private_data; - char buf[16]; - int ret; - - ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->ps_state); - - return simple_read_from_buffer(userbuf, count, ppos, buf, ret); -} - -static const struct file_operations btmrvl_psstate_fops = { - .read = btmrvl_psstate_read, - .open = simple_open, - .llseek = default_llseek, -}; - -static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct btmrvl_private *priv = file->private_data; - char buf[16]; - int ret; - - ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->hs_state); - - return simple_read_from_buffer(userbuf, count, ppos, buf, ret); -} - -static const struct file_operations btmrvl_hsstate_fops = { - .read = btmrvl_hsstate_read, - .open = simple_open, - .llseek = default_llseek, -}; - -static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct btmrvl_private *priv = file->private_data; - char buf[16]; - int ret; - - ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->btmrvl_dev.tx_dnld_rdy); - - return simple_read_from_buffer(userbuf, count, ppos, buf, ret); -} - -static const struct file_operations btmrvl_txdnldready_fops = { - .read = btmrvl_txdnldready_read, - .open = simple_open, - .llseek = default_llseek, -}; - void btmrvl_debugfs_init(struct hci_dev *hdev) { struct btmrvl_private *priv = hci_get_drvdata(hdev); @@ -394,30 +185,28 @@ void btmrvl_debugfs_init(struct hci_dev *hdev) dbg->config_dir = debugfs_create_dir("config", hdev->debugfs); - dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir, - priv, &btmrvl_psmode_fops); - dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir, - priv, &btmrvl_pscmd_fops); - dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir, - priv, &btmrvl_gpiogap_fops); - dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir, - priv, &btmrvl_hsmode_fops); - dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir, - priv, &btmrvl_hscmd_fops); - dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, - priv, &btmrvl_hscfgcmd_fops); + debugfs_create_u8("psmode", 0644, dbg->config_dir, + &priv->btmrvl_dev.psmode); + debugfs_create_file("pscmd", 0644, dbg->config_dir, + priv, &btmrvl_pscmd_fops); + debugfs_create_x16("gpiogap", 0644, dbg->config_dir, + &priv->btmrvl_dev.gpio_gap); + debugfs_create_u8("hsmode", 0644, dbg->config_dir, + &priv->btmrvl_dev.hsmode); + debugfs_create_file("hscmd", 0644, dbg->config_dir, + priv, &btmrvl_hscmd_fops); + debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, + priv, &btmrvl_hscfgcmd_fops); dbg->status_dir = debugfs_create_dir("status", hdev->debugfs); - dbg->curpsmode = debugfs_create_file("curpsmode", 0444, - dbg->status_dir, priv, - &btmrvl_curpsmode_fops); - dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir, - priv, &btmrvl_psstate_fops); - dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir, - priv, &btmrvl_hsstate_fops); - dbg->txdnldready = debugfs_create_file("txdnldready", 0444, - dbg->status_dir, priv, - &btmrvl_txdnldready_fops); + debugfs_create_u8("curpsmode", 0444, dbg->status_dir, + &priv->adapter->psmode); + debugfs_create_u8("psstate", 0444, dbg->status_dir, + &priv->adapter->ps_state); + debugfs_create_u8("hsstate", 0444, dbg->status_dir, + &priv->adapter->hs_state); + debugfs_create_u8("txdnldready", 0444, dbg->status_dir, + &priv->btmrvl_dev.tx_dnld_rdy); } void btmrvl_debugfs_remove(struct hci_dev *hdev) @@ -428,19 +217,8 @@ void btmrvl_debugfs_remove(struct hci_dev *hdev) if (!dbg) return; - debugfs_remove(dbg->psmode); - debugfs_remove(dbg->pscmd); - debugfs_remove(dbg->gpiogap); - debugfs_remove(dbg->hsmode); - debugfs_remove(dbg->hscmd); - debugfs_remove(dbg->hscfgcmd); - debugfs_remove(dbg->config_dir); - - debugfs_remove(dbg->curpsmode); - debugfs_remove(dbg->psstate); - debugfs_remove(dbg->hsstate); - debugfs_remove(dbg->txdnldready); - debugfs_remove(dbg->status_dir); + debugfs_remove_recursive(dbg->config_dir); + debugfs_remove_recursive(dbg->status_dir); kfree(dbg); } -- cgit v1.2.3 From c1c999e27ce5681c5b43c7f82947030e7134f1d0 Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Mon, 22 Apr 2013 11:10:22 +0200 Subject: Bluetooth: btmrvl: release lock while waiting for fw download complete If not winner, driver must release the sdio host lock, so the fw download can progress. While holding the lock fw download is stalled and the following error is produced: [ 235.746015] Bluetooth: FW failed to be active in time! [ 235.752799] Bluetooth: Downloading firmware failed! Signed-off-by: Andreas Fenkart Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btmrvl_sdio.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 0e9e8e95916d..758d5ac81ecc 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -234,7 +234,10 @@ static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card, /* Wait for firmware to become ready */ for (tries = 0; tries < pollnum; tries++) { - if (btmrvl_sdio_read_fw_status(card, &firmwarestat) < 0) + sdio_claim_host(card->func); + ret = btmrvl_sdio_read_fw_status(card, &firmwarestat); + sdio_release_host(card->func); + if (ret < 0) continue; if (firmwarestat == FIRMWARE_READY) { @@ -882,13 +885,14 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) BT_ERR("card or function is NULL!"); return -EINVAL; } - sdio_claim_host(card->func); if (!btmrvl_sdio_verify_fw_download(card, 1)) { BT_DBG("Firmware already downloaded!"); - goto done; + return 0; } + sdio_claim_host(card->func); + /* Check if other function driver is downloading the firmware */ fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret); if (ret) { @@ -918,15 +922,17 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) } } + sdio_release_host(card->func); + if (btmrvl_sdio_verify_fw_download(card, pollnum)) { BT_ERR("FW failed to be active in time!"); - ret = -ETIMEDOUT; - goto done; + return -ETIMEDOUT; } + return 0; + done: sdio_release_host(card->func); - return ret; } -- cgit v1.2.3 From 69676b1c2af451bfe5cd36ff4973a484b5d5a86c Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Mon, 22 Apr 2013 11:10:23 +0200 Subject: Bluetooth: btmrvl: report error if verify_fw_download times out FW does the synchronization of the different modules during init. It will report different modules, that it is ready at different times. The fw download 'winner' will be reported fw ready first. Without this patch, btmrvl was already continuing before the FW told it too. Probably on behalf of the 'winner' which then never sees FW ready and times out. Signed-off-by: Andreas Fenkart Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btmrvl_sdio.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 758d5ac81ecc..c63488c54f4a 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -228,9 +228,8 @@ failed: static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card, int pollnum) { - int ret = -ETIMEDOUT; u16 firmwarestat; - unsigned int tries; + int tries, ret; /* Wait for firmware to become ready */ for (tries = 0; tries < pollnum; tries++) { @@ -240,15 +239,13 @@ static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card, if (ret < 0) continue; - if (firmwarestat == FIRMWARE_READY) { - ret = 0; - break; - } else { - msleep(10); - } + if (firmwarestat == FIRMWARE_READY) + return 0; + + msleep(10); } - return ret; + return -ETIMEDOUT; } static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) @@ -924,6 +921,10 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) sdio_release_host(card->func); + /* + * winner or not, with this test the FW synchronizes when the + * module can continue its initialization + */ if (btmrvl_sdio_verify_fw_download(card, pollnum)) { BT_ERR("FW failed to be active in time!"); return -ETIMEDOUT; @@ -995,8 +996,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func, goto unreg_dev; } - msleep(100); - btmrvl_sdio_enable_host_int(card); priv = btmrvl_add_card(card); -- cgit v1.2.3 From c380aafb77b7435d010698fe3ca6d3e1cd745fde Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Tue, 23 Apr 2013 16:49:47 -0700 Subject: mwifiex: Use pci_release_region() instead of a pci_release_regions() PCI regions are associated with the device using pci_request_region() call. Hence use pci_release_region() instead of pci_release_regions(). Cc: # 3.2+ Signed-off-by: Yogesh Ashok Powar Signed-off-by: Amitkumar Karwar Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/pcie.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 80f282c0bd4d..fec2a617bf98 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -2294,8 +2294,8 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter) if (pdev) { pci_iounmap(pdev, card->pci_mmap); pci_iounmap(pdev, card->pci_mmap1); - - pci_release_regions(pdev); + pci_release_region(pdev, 2); + pci_release_region(pdev, 0); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } -- cgit v1.2.3 From 5b0d9b218b74042ff72bf4bfda6eeb2e4bf98397 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Tue, 23 Apr 2013 16:49:48 -0700 Subject: mwifiex: Call pci_release_region after calling pci_disable_device "drivers should call pci_release_region() AFTER calling pci_disable_device()" Please refer section 3.2 Request MMIO/IOP resources in Documentation/PCI/pci.txt Cc: # 3.2+ Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Yogesh Ashok Powar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/pcie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index fec2a617bf98..b924e1d9cf9c 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -2294,9 +2294,9 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter) if (pdev) { pci_iounmap(pdev, card->pci_mmap); pci_iounmap(pdev, card->pci_mmap1); + pci_disable_device(pdev); pci_release_region(pdev, 2); pci_release_region(pdev, 0); - pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } } -- cgit v1.2.3 From 955ab095c51a6f5a105aaeff4fc8e32c2ee94814 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Tue, 23 Apr 2013 16:49:49 -0700 Subject: mwifiex: Do not kfree cmd buf while unregistering PCIe All the command buffers are freed in mwifiex_free_cmd_buffer() and hence there is no need to kfree the current command buffer again. This might ends up freeing memory allocated by some other kernel code. Signed-off-by: Amitkumar Karwar Signed-off-by: Avinash Patil Signed-off-by: Yogesh Ashok Powar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/pcie.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index b924e1d9cf9c..eaf93f55e4db 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -863,7 +863,6 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) MWIFIEX_SKB_PACB(card->cmd_buf, &buf_pa); pci_unmap_single(card->dev, buf_pa, MWIFIEX_SIZE_OF_CMD_BUFFER, PCI_DMA_TODEVICE); - dev_kfree_skb_any(card->cmd_buf); } return 0; } -- cgit v1.2.3 From 7af1ce0e0daaf181335c8edc21e12d69ee5cd1d1 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Tue, 23 Apr 2013 16:49:50 -0700 Subject: mwifiex: Correct pci_unmap_single's size There exist mismatch between the size used for pci_map and pci_unmap on command skb. Correcting it. Signed-off-by: Amitkumar Karwar Signed-off-by: Avinash Patil Signed-off-by: Yogesh Ashok Powar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/pcie.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index eaf93f55e4db..20c9c4c7b0b2 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -861,7 +861,7 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) if (card && card->cmd_buf) { MWIFIEX_SKB_PACB(card->cmd_buf, &buf_pa); - pci_unmap_single(card->dev, buf_pa, MWIFIEX_SIZE_OF_CMD_BUFFER, + pci_unmap_single(card->dev, buf_pa, card->cmd_buf->len, PCI_DMA_TODEVICE); } return 0; @@ -1572,7 +1572,7 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter, skb_tmp = card->cmd_buf; if (skb_tmp) { MWIFIEX_SKB_PACB(skb_tmp, &buf_pa); - pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, + pci_unmap_single(card->dev, buf_pa, skb_tmp->len, PCI_DMA_FROMDEVICE); card->cmd_buf = NULL; } -- cgit v1.2.3 From 00b38ab35d9bd2253a4d1e659382871d2220e095 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 24 Apr 2013 21:30:54 +0200 Subject: ssb: implement ssb spuravoid for chipid BCM43222 Signed-off-by: Hauke Mehrtens Acked-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/ssb/driver_chipcommon_pmu.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c index 23c5dbfea115..1173a091b402 100644 --- a/drivers/ssb/driver_chipcommon_pmu.c +++ b/drivers/ssb/driver_chipcommon_pmu.c @@ -687,8 +687,23 @@ void ssb_pmu_spuravoid_pllupdate(struct ssb_chipcommon *cc, int spuravoid) pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD; break; case 43222: - /* TODO: BCM43222 requires updating PLLs too */ - return; + if (spuravoid == 1) { + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11500008); + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0C000C06); + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x0F600a08); + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000); + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x2001E920); + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888815); + } else { + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100008); + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0c000c06); + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x03000a08); + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000); + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x200005c0); + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888855); + } + pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD; + break; default: ssb_printk(KERN_ERR PFX "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n", -- cgit v1.2.3 From d1497f21056ca1d8ad11f1cd9734bbe9e67c5b95 Mon Sep 17 00:00:00 2001 From: Piotr Haber Date: Thu, 25 Apr 2013 12:27:09 +0200 Subject: brcmsmac: Fix merge issue Commit 7088f4835aa353f7226e57e73fd9e6564a4dfb75 "Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless" ramoved call to brcms_led_unregister in mac80211_if.c Reviewed-by: Hante Meuleman Reviewed-by: Arend van Spriel Signed-off-by: Piotr Haber Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 2346821667e6..3a6544710c8a 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -336,6 +336,7 @@ static void brcms_remove(struct bcma_device *pdev) struct brcms_info *wl = hw->priv; if (wl->wlc) { + brcms_led_unregister(wl); wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false); wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); ieee80211_unregister_hw(hw); -- cgit v1.2.3 From cc0446bfeb3a9038c881db77d30c68a2beb4fa60 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 25 Apr 2013 09:50:28 -0500 Subject: rtlwifi: rtl8192cu: Fix false loss of AP indication A major change in the rtlwifi family recently added code to detect when there is loss of AP signals. One critical statement needed for the USB driver was missed. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/usb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 83915dcd0e58..76732b0cd221 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -521,6 +521,9 @@ static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw, rtlpriv->link_info.num_rx_inperiod++; } + /* static bcn for roaming */ + rtl_beacon_statistic(hw, skb); + if (likely(rtl_action_proc(hw, skb, false))) ieee80211_rx(hw, skb); else -- cgit v1.2.3