From 05f57195ab5a232afd773328f00784e79c60e64e Mon Sep 17 00:00:00 2001 From: Martin Decky Date: Thu, 10 Sep 2009 03:44:47 +0200 Subject: hostap: Revert a toxic part of the conversion to net_device_ops As the hostap driver was converted to use net_device_ops, a mistake was made in hostap_main.c (commit 5ae4efbcd2611562a8b93596be034e63495706a5). Originally, the tx_queue_len was set to 0 for every other interface than HOSTAP_INTERFACE_MASTER, but the new fragment of code sets tx_queue_len to 0 only for HOSTAP_INTERFACE_MASTER. The opposite of the previous behavior makes the driver to drop all packets in AP mode. Change the way 0 is assigned to tx_queue_len according to the original logic. Signed-off-by: Martin Decky Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 6fe122f18c0..eb57d1ea361 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -875,15 +875,16 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local, switch(type) { case HOSTAP_INTERFACE_AP: + dev->tx_queue_len = 0; /* use main radio device queue */ dev->netdev_ops = &hostap_mgmt_netdev_ops; dev->type = ARPHRD_IEEE80211; dev->header_ops = &hostap_80211_ops; break; case HOSTAP_INTERFACE_MASTER: - dev->tx_queue_len = 0; /* use main radio device queue */ dev->netdev_ops = &hostap_master_ops; break; default: + dev->tx_queue_len = 0; /* use main radio device queue */ dev->netdev_ops = &hostap_netdev_ops; } -- cgit v1.2.3-18-g5258 From 5ab9549a64c77b6975b079b27e95fc2c115f613b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 10 Sep 2009 20:31:46 +0200 Subject: b43: Force-wake queues on init Force wake the mac80211 queues on init. Under rare circumstances they may be stopped, if a DMA error or something else causes a device reset while a queue was stopped. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 7a9a3fa5542..78e9834d4c1 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4287,6 +4287,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev) if (!dev->suspend_in_progress) b43_rng_init(wl); + ieee80211_wake_queues(dev->wl->hw); + b43_set_status(dev, B43_STAT_INITIALIZED); if (!dev->suspend_in_progress) -- cgit v1.2.3-18-g5258 From 10a01bfd4e077ff03a4ace76a6d9b81272f91678 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 11 Sep 2009 08:30:03 +0530 Subject: ath9k: Fix bug in ANI channel handling When processing MIB interrupts, OFDM and CCK error handling routines for low RSSI values have to be invoked only when the channel mode is 11G/11B. Since HT channels will also fall under the bands 2Ghz/5Ghz, check appropriately. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index a7cbb07988c..2b493742ef1 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -327,7 +327,8 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) aniState->firstepLevel + 1); return; } else { - if (conf->channel->band == IEEE80211_BAND_2GHZ) { + if ((conf->channel->band == IEEE80211_BAND_2GHZ) && + !conf_is_ht(conf)) { if (!aniState->ofdmWeakSigDetectOff) ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, @@ -369,7 +370,8 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } else { - if (conf->channel->band == IEEE80211_BAND_2GHZ) { + if ((conf->channel->band == IEEE80211_BAND_2GHZ) && + !conf_is_ht(conf)) { if (aniState->firstepLevel > 0) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); -- cgit v1.2.3-18-g5258 From 7ab44f17bc5b16ab1b4fc4dad4a0667c21e727b5 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 11 Sep 2009 04:43:29 -0400 Subject: wireless: default CONFIG_WLAN to y When this was added no defaults were set and it seems this implies n. Default this to y. Reported-by: Jouni Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index ad89d23968d..49ea9c92b7e 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -5,6 +5,7 @@ menuconfig WLAN bool "Wireless LAN" depends on !S390 + default y ---help--- This section contains all the pre 802.11 and 802.11 wireless device drivers. For a complete list of drivers and documentation -- cgit v1.2.3-18-g5258 From 44fdd375cd8bb3544f9832b4a42df497d180feb2 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 11 Sep 2009 16:08:06 +0200 Subject: ssb: Disable verbose SDIO coreswitch Disable SDIO coreswitch debugging. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ssb/sdio.c b/drivers/ssb/sdio.c index 114051056b5..4ff73473e69 100644 --- a/drivers/ssb/sdio.c +++ b/drivers/ssb/sdio.c @@ -21,7 +21,7 @@ #include "ssb_private.h" /* Define the following to 1 to enable a printk on each coreswitch. */ -#define SSB_VERBOSE_SDIOCORESWITCH_DEBUG 1 +#define SSB_VERBOSE_SDIOCORESWITCH_DEBUG 0 /* Hardware invariants CIS tuples */ -- cgit v1.2.3-18-g5258 From 91d372c0afc55faf44c1b763693f089b5dad31ec Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 11 Sep 2009 18:31:32 +0200 Subject: b43: Fix resume failure This fixes a resume failure where a signal is pending on resume so the firmware upload fails. This removes the interruptible sleep, because we don't really need it. In the worst case (with broken firmware) the sleep loop will take 1 second. In the common case (working firmware), it will only take a few milliseconds. So we don't really need to be interruptible. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 78e9834d4c1..e789792a36b 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2289,11 +2289,7 @@ static int b43_upload_microcode(struct b43_wldev *dev) err = -ENODEV; goto error; } - msleep_interruptible(50); - if (signal_pending(current)) { - err = -EINTR; - goto error; - } + msleep(50); } b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); /* dummy read */ -- cgit v1.2.3-18-g5258 From c929c5a1281b666fabc9aa94c607932ec6d28c6d Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 11 Sep 2009 10:38:08 -0700 Subject: iwlwifi: fix HT operation in 2.4 GHz band When we cleaned up the driver to properly tell mac80211 about HT rates ("iwlwifi: use iwl_hwrate_get_mac80211_idx where appropriate"), we broke internal rate indexing in 2.4 GHz band. Signed-off-by: Daniel C Halperin Tested-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 40b207aa8fe..fd731534df1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -883,6 +883,12 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, mac_index &= RATE_MCS_CODE_MSK; /* Remove # of streams */ if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE)) mac_index++; + /* + * mac80211 HT index is always zero-indexed; we need to move + * HT OFDM rates after CCK rates in 2.4 GHz band + */ + if (priv->band == IEEE80211_BAND_2GHZ) + mac_index += IWL_FIRST_OFDM_RATE; } if ((mac_index < 0) || -- cgit v1.2.3-18-g5258 From de0bd50845eb5935ce3d503c5d2f565d6cb9ece1 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 11 Sep 2009 10:38:12 -0700 Subject: iwlwifi: fix potential rx buffer loss RX handling maintains a few lists that keep track of the RX buffers. Buffers move from one list to the other as they are used, replenished, and again made available for usage. In one such instance, when a buffer is used it enters the "rx_used" list. When buffers are replenished an skb is attached to the buffer and it is moved to the "rx_free" list. The problem here is that the buffer is first removed from the "rx_used" list _before_ the skb is allocated. Thus, if the skb allocation fails this buffer remains removed from the "rx_used" list and is thus lost for future usage. Fix this by first allocating the skb before trying to attach it to a list. We add an additional check to not do this unnecessarily. Reported-by: Rick Farrington Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-rx.c | 24 +++++++++++++++++------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 24 ++++++++++++++++-------- 2 files changed, 33 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 8150c5c3a16..b90adcb73b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -239,26 +239,22 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; struct iwl_rx_mem_buffer *rxb; + struct sk_buff *skb; unsigned long flags; while (1) { spin_lock_irqsave(&rxq->lock, flags); - if (list_empty(&rxq->rx_used)) { spin_unlock_irqrestore(&rxq->lock, flags); return; } - element = rxq->rx_used.next; - rxb = list_entry(element, struct iwl_rx_mem_buffer, list); - list_del(element); - spin_unlock_irqrestore(&rxq->lock, flags); /* Alloc a new receive buffer */ - rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256, + skb = alloc_skb(priv->hw_params.rx_buf_size + 256, priority); - if (!rxb->skb) { + if (!skb) { IWL_CRIT(priv, "Can not allocate SKB buffers\n"); /* We don't reschedule replenish work here -- we will * call the restock method and if it still needs @@ -266,6 +262,20 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) break; } + spin_lock_irqsave(&rxq->lock, flags); + + if (list_empty(&rxq->rx_used)) { + spin_unlock_irqrestore(&rxq->lock, flags); + dev_kfree_skb_any(skb); + return; + } + element = rxq->rx_used.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + + spin_unlock_irqrestore(&rxq->lock, flags); + + rxb->skb = skb; /* Get physical address of RB/SKB */ rxb->real_dma_addr = pci_map_single( priv->pci_dev, diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 2238c9f2018..090966837f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1134,6 +1134,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; struct iwl_rx_mem_buffer *rxb; + struct sk_buff *skb; unsigned long flags; while (1) { @@ -1143,17 +1144,11 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) spin_unlock_irqrestore(&rxq->lock, flags); return; } - - element = rxq->rx_used.next; - rxb = list_entry(element, struct iwl_rx_mem_buffer, list); - list_del(element); spin_unlock_irqrestore(&rxq->lock, flags); /* Alloc a new receive buffer */ - rxb->skb = - alloc_skb(priv->hw_params.rx_buf_size, - priority); - if (!rxb->skb) { + skb = alloc_skb(priv->hw_params.rx_buf_size, priority); + if (!skb) { if (net_ratelimit()) IWL_CRIT(priv, ": Can not allocate SKB buffers\n"); /* We don't reschedule replenish work here -- we will @@ -1162,6 +1157,19 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) break; } + spin_lock_irqsave(&rxq->lock, flags); + if (list_empty(&rxq->rx_used)) { + spin_unlock_irqrestore(&rxq->lock, flags); + dev_kfree_skb_any(skb); + return; + } + element = rxq->rx_used.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + spin_unlock_irqrestore(&rxq->lock, flags); + + rxb->skb = skb; + /* If radiotap head is required, reserve some headroom here. * The physical head count is a variable rx_stats->phy_count. * We reserve 4 bytes here. Plus these extra bytes, the -- cgit v1.2.3-18-g5258 From 4a86eaa46dbaf26498bcf0bb3535d4fd36a32858 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 11 Sep 2009 10:38:18 -0700 Subject: iwlwifi: find the correct first antenna We can not assume antenna "A" is the first valid anttena for all the NIC. Need to make sure choice the correct antenna based on h/w configuration for transmit to avoid sending frame on invalid antenna Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index fd731534df1..346dc06fa7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -760,6 +760,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, u16 high_low; u8 switch_to_legacy = 0; u8 is_green = lq_sta->is_green; + struct iwl_priv *priv = lq_sta->drv; /* check if we need to switch from HT to legacy rates. * assumption is that mandatory rates (1Mbps or 6Mbps) @@ -773,7 +774,8 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, tbl->lq_type = LQ_G; if (num_of_ant(tbl->ant_type) > 1) - tbl->ant_type = ANT_A;/*FIXME:RS*/ + tbl->ant_type = + first_antenna(priv->hw_params.valid_tx_ant); tbl->is_ht40 = 0; tbl->is_SGI = 0; -- cgit v1.2.3-18-g5258 From 96d8c6af24bcacb16f18fc88fb7f2de1a59c09d6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 11 Sep 2009 10:50:37 -0700 Subject: iwlwifi: disable powersave for 4965 There's a bug in 4965 powersave that appears to be related to the way it keeps track of its data during sleep, but we haven't found it yet. Due to that, using powersave may spontaneously cause the device to SYSASSERT when transitioning from sleep to wake. Therefore, disable powersave for 4965, until (if ever, unfortunately) we can identify and fix the problem. Cf. http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=1982 which was closed, but now has re-appeared with IDLE mode, which probably means we never really fixed it. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-core.c | 9 ++++++--- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-power.c | 5 +++-- 4 files changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 6a13bfbc9d9..ca61d3796ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2346,6 +2346,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .mod_params = &iwl4965_mod_params, .use_isr_legacy = true, .ht_greenfield_support = false, + .broken_powersave = true, }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index acfd7b40afb..fd26c0dc9c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1585,9 +1585,12 @@ int iwl_setup_mac(struct iwl_priv *priv) hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM | IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_DYNAMIC_PS; + IEEE80211_HW_SPECTRUM_MGMT; + + if (!priv->cfg->broken_powersave) + hw->flags |= IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index c04d2a27081..7ff9ffb2b70 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -252,6 +252,7 @@ struct iwl_cfg { const u16 max_ll_items; const bool shadow_ram_support; const bool ht_greenfield_support; + const bool broken_powersave; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 4ec6a8307cc..60be976afff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -292,8 +292,9 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) else dtimper = 1; - /* TT power setting overwrites everything */ - if (tt->state >= IWL_TI_1) + if (priv->cfg->broken_powersave) + iwl_power_sleep_cam_cmd(priv, &cmd); + else if (tt->state >= IWL_TI_1) iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper); else if (!enabled) iwl_power_sleep_cam_cmd(priv, &cmd); -- cgit v1.2.3-18-g5258 From d45b90ddee58db8caa3b06c3709b73dd0444559c Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 13 Sep 2009 15:55:13 -0500 Subject: ssb: Fix error when V1 SPROM extraction is forced When an SPROM revision is not recognized, the code falls back to a V1 SPROM; however, that revision is not forced in the appropriate structure. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/ssb/pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index f853d5600ca..9e50896233a 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -600,6 +600,7 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, ssb_printk(KERN_WARNING PFX "Unsupported SPROM" " revision %d detected. Will extract" " v1\n", out->revision); + out->revision = 1; sprom_extract_r123(out, in); } } -- cgit v1.2.3-18-g5258 From c3de943ad6e535ceb5238b3b7d3903c6e294061a Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 14 Sep 2009 23:08:43 +0200 Subject: p54usb: add Zcomax XG-705A usbid This patch adds a new usbid for Zcomax XG-705A to the device table. Cc: stable@kernel.org Reported-by: Jari Jaakola Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index e44460ff149..17e199546ee 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -67,6 +67,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/ {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */ {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */ + {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */ {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */ {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */ {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */ -- cgit v1.2.3-18-g5258 From 71702bc13efd3238e02197780d6e62c51c196a9d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 15 Sep 2009 14:52:40 -0700 Subject: ssb/sdio: fix printk format warnings Fix printk format warnings: drivers/ssb/sdio.c:336: warning: format '%u' expects type 'unsigned int', but argument 7 has type 'size_t' drivers/ssb/sdio.c:443: warning: format '%u' expects type 'unsigned int', but argument 7 has type 'size_t' Signed-off-by: Randy Dunlap Signed-off-by: John W. Linville --- drivers/ssb/sdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ssb/sdio.c b/drivers/ssb/sdio.c index 4ff73473e69..65a6080cb02 100644 --- a/drivers/ssb/sdio.c +++ b/drivers/ssb/sdio.c @@ -333,7 +333,7 @@ static void ssb_sdio_block_read(struct ssb_device *dev, void *buffer, goto out; err_out: - dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%u), error %d\n", + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%zu), error %d\n", bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error); out: sdio_release_host(bus->host_sdio); @@ -440,7 +440,7 @@ static void ssb_sdio_block_write(struct ssb_device *dev, const void *buffer, goto out; err_out: - dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%u), error %d\n", + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%zu), error %d\n", bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error); out: sdio_release_host(bus->host_sdio); -- cgit v1.2.3-18-g5258 From a78b3bb2f3ab9afcf78dbcff18fd7bf900c7c27e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 11 Sep 2009 21:44:05 +0200 Subject: b43: Rewrite suspend/resume code This removes most of the b43 suspend/resume code (it's handled by mac80211) and moves the registration of devices to the attachment phase. This is required, because we must not register/unregister devices on suspend/resume. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 19 +-- drivers/net/wireless/b43/leds.c | 259 ++++++++++++++++++++++++++++------------ drivers/net/wireless/b43/leds.h | 28 ++++- drivers/net/wireless/b43/main.c | 100 ++++------------ 4 files changed, 233 insertions(+), 173 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 09cfe68537b..89ccf0d50f3 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -629,13 +629,6 @@ struct b43_wl { * from the mac80211 subsystem. */ u16 mac80211_initially_registered_queues; - /* R/W lock for data transmission. - * Transmissions on 2+ queues can run concurrently, but somebody else - * might sync with TX by write_lock_irqsave()'ing. */ - rwlock_t tx_lock; - /* Lock for LEDs access. */ - spinlock_t leds_lock; - /* We can only have one operating interface (802.11 core) * at a time. General information about this interface follows. */ @@ -686,6 +679,9 @@ struct b43_wl { struct work_struct tx_work; /* Queue of packets to be transmitted. */ struct sk_buff_head tx_queue; + + /* The device LEDs. */ + struct b43_leds leds; }; /* The type of the firmware file. */ @@ -768,13 +764,10 @@ struct b43_wldev { /* The device initialization status. * Use b43_status() to query. */ atomic_t __init_status; - /* Saved init status for handling suspend. */ - int suspend_init_status; bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */ bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ bool radio_hw_enable; /* saved state of radio hardware enabled state */ - bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */ bool qos_enabled; /* TRUE, if QoS is used. */ bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */ @@ -794,12 +787,6 @@ struct b43_wldev { /* Various statistics about the physical device. */ struct b43_stats stats; - /* The device LEDs. */ - struct b43_led led_tx; - struct b43_led led_rx; - struct b43_led led_assoc; - struct b43_led led_radio; - /* Reason code of the last interrupt. */ u32 irq_reason; u32 dma_reason[6]; diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index c8b317094c3..ac5a322c84b 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -34,57 +34,91 @@ static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index, bool activelow) { - struct b43_wl *wl = dev->wl; - unsigned long flags; u16 ctl; - spin_lock_irqsave(&wl->leds_lock, flags); ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); if (activelow) ctl &= ~(1 << led_index); else ctl |= (1 << led_index); b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl); - spin_unlock_irqrestore(&wl->leds_lock, flags); } static void b43_led_turn_off(struct b43_wldev *dev, u8 led_index, bool activelow) { - struct b43_wl *wl = dev->wl; - unsigned long flags; u16 ctl; - spin_lock_irqsave(&wl->leds_lock, flags); ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); if (activelow) ctl |= (1 << led_index); else ctl &= ~(1 << led_index); b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl); - spin_unlock_irqrestore(&wl->leds_lock, flags); } -/* Callback from the LED subsystem. */ -static void b43_led_brightness_set(struct led_classdev *led_dev, - enum led_brightness brightness) +static void b43_led_update(struct b43_wldev *dev, + struct b43_led *led) { - struct b43_led *led = container_of(led_dev, struct b43_led, led_dev); - struct b43_wldev *dev = led->dev; bool radio_enabled; + bool turn_on; - if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) + if (!led->wl) return; - /* Checking the radio-enabled status here is slightly racy, - * but we want to avoid the locking overhead and we don't care - * whether the LED has the wrong state for a second. */ radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable); - if (brightness == LED_OFF || !radio_enabled) - b43_led_turn_off(dev, led->index, led->activelow); + /* The led->state read is racy, but we don't care. In case we raced + * with the brightness_set handler, we will be called again soon + * to fixup our state. */ + if (radio_enabled) + turn_on = atomic_read(&led->state) != LED_OFF; else + turn_on = 0; + if (turn_on == led->hw_state) + return; + led->hw_state = turn_on; + + if (turn_on) b43_led_turn_on(dev, led->index, led->activelow); + else + b43_led_turn_off(dev, led->index, led->activelow); +} + +static void b43_leds_work(struct work_struct *work) +{ + struct b43_leds *leds = container_of(work, struct b43_leds, work); + struct b43_wl *wl = container_of(leds, struct b43_wl, leds); + struct b43_wldev *dev; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED)) + goto out_unlock; + + b43_led_update(dev, &wl->leds.led_tx); + b43_led_update(dev, &wl->leds.led_rx); + b43_led_update(dev, &wl->leds.led_radio); + b43_led_update(dev, &wl->leds.led_assoc); + +out_unlock: + mutex_unlock(&wl->mutex); +} + +/* Callback from the LED subsystem. */ +static void b43_led_brightness_set(struct led_classdev *led_dev, + enum led_brightness brightness) +{ + struct b43_led *led = container_of(led_dev, struct b43_led, led_dev); + struct b43_wl *wl = led->wl; + + /* The check for current_dev is only needed while unregistering, + * so it is sequencial and does not race. But we must not dereference + * current_dev here. */ + if (likely(wl->current_dev)) { + atomic_set(&led->state, brightness); + ieee80211_queue_work(wl->hw, &wl->leds.work); + } } static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, @@ -93,15 +127,15 @@ static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, { int err; - b43_led_turn_off(dev, led_index, activelow); - if (led->dev) + if (led->wl) return -EEXIST; if (!default_trigger) return -EINVAL; - led->dev = dev; + led->wl = dev->wl; led->index = led_index; led->activelow = activelow; strncpy(led->name, name, sizeof(led->name)); + atomic_set(&led->state, 0); led->led_dev.name = led->name; led->led_dev.default_trigger = default_trigger; @@ -110,19 +144,19 @@ static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, err = led_classdev_register(dev->dev->dev, &led->led_dev); if (err) { b43warn(dev->wl, "LEDs: Failed to register %s\n", name); - led->dev = NULL; + led->wl = NULL; return err; } + return 0; } static void b43_unregister_led(struct b43_led *led) { - if (!led->dev) + if (!led->wl) return; led_classdev_unregister(&led->led_dev); - b43_led_turn_off(led->dev, led->index, led->activelow); - led->dev = NULL; + led->wl = NULL; } static void b43_map_led(struct b43_wldev *dev, @@ -137,24 +171,20 @@ static void b43_map_led(struct b43_wldev *dev, * generic LED triggers. */ switch (behaviour) { case B43_LED_INACTIVE: - break; case B43_LED_OFF: - b43_led_turn_off(dev, led_index, activelow); - break; case B43_LED_ON: - b43_led_turn_on(dev, led_index, activelow); break; case B43_LED_ACTIVITY: case B43_LED_TRANSFER: case B43_LED_APTRANSFER: snprintf(name, sizeof(name), "b43-%s::tx", wiphy_name(hw->wiphy)); - b43_register_led(dev, &dev->led_tx, name, + b43_register_led(dev, &dev->wl->leds.led_tx, name, ieee80211_get_tx_led_name(hw), led_index, activelow); snprintf(name, sizeof(name), "b43-%s::rx", wiphy_name(hw->wiphy)); - b43_register_led(dev, &dev->led_rx, name, + b43_register_led(dev, &dev->wl->leds.led_rx, name, ieee80211_get_rx_led_name(hw), led_index, activelow); break; @@ -164,18 +194,15 @@ static void b43_map_led(struct b43_wldev *dev, case B43_LED_MODE_BG: snprintf(name, sizeof(name), "b43-%s::radio", wiphy_name(hw->wiphy)); - b43_register_led(dev, &dev->led_radio, name, + b43_register_led(dev, &dev->wl->leds.led_radio, name, ieee80211_get_radio_led_name(hw), led_index, activelow); - /* Sync the RF-kill LED state with radio and switch states. */ - if (dev->phy.radio_on && b43_is_hw_radio_enabled(dev)) - b43_led_turn_on(dev, led_index, activelow); break; case B43_LED_WEIRD: case B43_LED_ASSOC: snprintf(name, sizeof(name), "b43-%s::assoc", wiphy_name(hw->wiphy)); - b43_register_led(dev, &dev->led_assoc, name, + b43_register_led(dev, &dev->wl->leds.led_assoc, name, ieee80211_get_assoc_led_name(hw), led_index, activelow); break; @@ -186,58 +213,140 @@ static void b43_map_led(struct b43_wldev *dev, } } -void b43_leds_init(struct b43_wldev *dev) +static void b43_led_get_sprominfo(struct b43_wldev *dev, + unsigned int led_index, + enum b43_led_behaviour *behaviour, + bool *activelow) { struct ssb_bus *bus = dev->dev->bus; u8 sprom[4]; - int i; - enum b43_led_behaviour behaviour; - bool activelow; sprom[0] = bus->sprom.gpio0; sprom[1] = bus->sprom.gpio1; sprom[2] = bus->sprom.gpio2; sprom[3] = bus->sprom.gpio3; - for (i = 0; i < 4; i++) { - if (sprom[i] == 0xFF) { - /* There is no LED information in the SPROM - * for this LED. Hardcode it here. */ - activelow = 0; - switch (i) { - case 0: - behaviour = B43_LED_ACTIVITY; - activelow = 1; - if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) - behaviour = B43_LED_RADIO_ALL; - break; - case 1: - behaviour = B43_LED_RADIO_B; - if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) - behaviour = B43_LED_ASSOC; - break; - case 2: - behaviour = B43_LED_RADIO_A; - break; - case 3: - behaviour = B43_LED_OFF; - break; - default: - B43_WARN_ON(1); - return; - } + if (sprom[led_index] == 0xFF) { + /* There is no LED information in the SPROM + * for this LED. Hardcode it here. */ + *activelow = 0; + switch (led_index) { + case 0: + *behaviour = B43_LED_ACTIVITY; + *activelow = 1; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) + *behaviour = B43_LED_RADIO_ALL; + break; + case 1: + *behaviour = B43_LED_RADIO_B; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) + *behaviour = B43_LED_ASSOC; + break; + case 2: + *behaviour = B43_LED_RADIO_A; + break; + case 3: + *behaviour = B43_LED_OFF; + break; + default: + B43_WARN_ON(1); + return; + } + } else { + *behaviour = sprom[led_index] & B43_LED_BEHAVIOUR; + *activelow = !!(sprom[led_index] & B43_LED_ACTIVELOW); + } +} + +void b43_leds_init(struct b43_wldev *dev) +{ + struct b43_led *led; + unsigned int i; + enum b43_led_behaviour behaviour; + bool activelow; + + /* Sync the RF-kill LED state (if we have one) with radio and switch states. */ + led = &dev->wl->leds.led_radio; + if (led->wl) { + if (dev->phy.radio_on && b43_is_hw_radio_enabled(dev)) { + b43_led_turn_on(dev, led->index, led->activelow); + led->hw_state = 1; + atomic_set(&led->state, 1); } else { - behaviour = sprom[i] & B43_LED_BEHAVIOUR; - activelow = !!(sprom[i] & B43_LED_ACTIVELOW); + b43_led_turn_off(dev, led->index, led->activelow); + led->hw_state = 0; + atomic_set(&led->state, 0); + } + } + + /* Initialize TX/RX/ASSOC leds */ + led = &dev->wl->leds.led_tx; + if (led->wl) { + b43_led_turn_off(dev, led->index, led->activelow); + led->hw_state = 0; + atomic_set(&led->state, 0); + } + led = &dev->wl->leds.led_rx; + if (led->wl) { + b43_led_turn_off(dev, led->index, led->activelow); + led->hw_state = 0; + atomic_set(&led->state, 0); + } + led = &dev->wl->leds.led_assoc; + if (led->wl) { + b43_led_turn_off(dev, led->index, led->activelow); + led->hw_state = 0; + atomic_set(&led->state, 0); + } + + /* Initialize other LED states. */ + for (i = 0; i < B43_MAX_NR_LEDS; i++) { + b43_led_get_sprominfo(dev, i, &behaviour, &activelow); + switch (behaviour) { + case B43_LED_OFF: + b43_led_turn_off(dev, i, activelow); + break; + case B43_LED_ON: + b43_led_turn_on(dev, i, activelow); + break; + default: + /* Leave others as-is. */ + break; } - b43_map_led(dev, i, behaviour, activelow); } } void b43_leds_exit(struct b43_wldev *dev) { - b43_unregister_led(&dev->led_tx); - b43_unregister_led(&dev->led_rx); - b43_unregister_led(&dev->led_assoc); - b43_unregister_led(&dev->led_radio); + struct b43_leds *leds = &dev->wl->leds; + + b43_led_turn_off(dev, leds->led_tx.index, leds->led_tx.activelow); + b43_led_turn_off(dev, leds->led_rx.index, leds->led_rx.activelow); + b43_led_turn_off(dev, leds->led_assoc.index, leds->led_assoc.activelow); + b43_led_turn_off(dev, leds->led_radio.index, leds->led_radio.activelow); +} + +void b43_leds_register(struct b43_wldev *dev) +{ + unsigned int i; + enum b43_led_behaviour behaviour; + bool activelow; + + INIT_WORK(&dev->wl->leds.work, b43_leds_work); + + /* Register the LEDs to the LED subsystem. */ + for (i = 0; i < B43_MAX_NR_LEDS; i++) { + b43_led_get_sprominfo(dev, i, &behaviour, &activelow); + b43_map_led(dev, i, behaviour, activelow); + } +} + +void b43_leds_unregister(struct b43_wldev *dev) +{ + struct b43_leds *leds = &dev->wl->leds; + + b43_unregister_led(&leds->led_tx); + b43_unregister_led(&leds->led_rx); + b43_unregister_led(&leds->led_assoc); + b43_unregister_led(&leds->led_radio); } diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h index b8b1dd52124..c4a58a0fc1d 100644 --- a/drivers/net/wireless/b43/leds.h +++ b/drivers/net/wireless/b43/leds.h @@ -7,12 +7,13 @@ struct b43_wldev; #include #include +#include #define B43_LED_MAX_NAME_LEN 31 struct b43_led { - struct b43_wldev *dev; + struct b43_wl *wl; /* The LED class device */ struct led_classdev led_dev; /* The index number of the LED. */ @@ -22,8 +23,23 @@ struct b43_led { bool activelow; /* The unique name string for this LED device. */ char name[B43_LED_MAX_NAME_LEN + 1]; + /* The current status of the LED. This is updated locklessly. */ + atomic_t state; + /* The active state in hardware. */ + bool hw_state; }; +struct b43_leds { + struct b43_led led_tx; + struct b43_led led_rx; + struct b43_led led_radio; + struct b43_led led_assoc; + + struct work_struct work; +}; + +#define B43_MAX_NR_LEDS 4 + #define B43_LED_BEHAVIOUR 0x7F #define B43_LED_ACTIVELOW 0x80 /* LED behaviour values */ @@ -42,6 +58,8 @@ enum b43_led_behaviour { B43_LED_INACTIVE, }; +void b43_leds_register(struct b43_wldev *dev); +void b43_leds_unregister(struct b43_wldev *dev); void b43_leds_init(struct b43_wldev *dev); void b43_leds_exit(struct b43_wldev *dev); @@ -49,10 +67,16 @@ void b43_leds_exit(struct b43_wldev *dev); #else /* CONFIG_B43_LEDS */ /* LED support disabled */ -struct b43_led { +struct b43_leds { /* empty */ }; +static inline void b43_leds_register(struct b43_wldev *dev) +{ +} +static inline void b43_leds_unregister(struct b43_wldev *dev) +{ +} static inline void b43_leds_init(struct b43_wldev *dev) { } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index e789792a36b..2984a915f8b 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3002,14 +3002,18 @@ static void b43_security_init(struct b43_wldev *dev) static int b43_rng_read(struct hwrng *rng, u32 *data) { struct b43_wl *wl = (struct b43_wl *)rng->priv; + struct b43_wldev *dev; + int count = -ENODEV; - /* FIXME: We need to take wl->mutex here to make sure the device - * is not going away from under our ass. However it could deadlock - * with hwrng internal locking. */ - - *data = b43_read16(wl->current_dev, B43_MMIO_RNG); + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (likely(dev && b43_status(dev) >= B43_STAT_INITIALIZED)) { + *data = b43_read16(dev, B43_MMIO_RNG); + count = sizeof(u16); + } + mutex_unlock(&wl->mutex); - return (sizeof(u16)); + return count; } #endif /* CONFIG_B43_HWRNG */ @@ -3851,6 +3855,7 @@ redo: b43_mac_suspend(dev); free_irq(dev->dev->irq, dev); + b43_leds_exit(dev); b43dbg(wl, "Wireless interface stopped\n"); return dev; @@ -3882,8 +3887,10 @@ static int b43_wireless_core_start(struct b43_wldev *dev) /* Start maintainance work */ b43_periodic_tasks_setup(dev); + b43_leds_init(dev); + b43dbg(dev->wl, "Wireless interface started\n"); - out: +out: return err; } @@ -4160,10 +4167,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) macctl |= B43_MACCTL_PSM_JMP0; b43_write32(dev, B43_MMIO_MACCTL, macctl); - if (!dev->suspend_in_progress) { - b43_leds_exit(dev); - b43_rng_exit(dev->wl); - } b43_dma_free(dev); b43_pio_free(dev); b43_chip_exit(dev); @@ -4180,7 +4183,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) /* Initialize a wireless core */ static int b43_wireless_core_init(struct b43_wldev *dev) { - struct b43_wl *wl = dev->wl; struct ssb_bus *bus = dev->dev->bus; struct ssb_sprom *sprom = &bus->sprom; struct b43_phy *phy = &dev->phy; @@ -4280,15 +4282,11 @@ static int b43_wireless_core_init(struct b43_wldev *dev) ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)); b43_upload_card_macaddress(dev); b43_security_init(dev); - if (!dev->suspend_in_progress) - b43_rng_init(wl); ieee80211_wake_queues(dev->wl->hw); b43_set_status(dev, B43_STAT_INITIALIZED); - if (!dev->suspend_in_progress) - b43_leds_init(dev); out: return err; @@ -4837,7 +4835,6 @@ static int b43_wireless_init(struct ssb_device *dev) /* Initialize struct b43_wl */ wl->hw = hw; - spin_lock_init(&wl->leds_lock); mutex_init(&wl->mutex); spin_lock_init(&wl->hardirq_lock); INIT_LIST_HEAD(&wl->devlist); @@ -4878,6 +4875,8 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id) err = ieee80211_register_hw(wl->hw); if (err) goto err_one_core_detach; + b43_leds_register(wl->current_dev); + b43_rng_init(wl); } out: @@ -4906,12 +4905,16 @@ static void b43_remove(struct ssb_device *dev) * might have modified it. Restoring is important, so the networking * stack can properly free resources. */ wl->hw->queues = wl->mac80211_initially_registered_queues; + wl->current_dev = NULL; + cancel_work_sync(&wl->leds.work); ieee80211_unregister_hw(wl->hw); } b43_one_core_detach(dev); if (list_empty(&wl->devlist)) { + b43_rng_exit(wl); + b43_leds_unregister(wldev); /* Last core on the chip unregistered. * We can destroy common struct b43_wl. */ @@ -4929,74 +4932,11 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason) ieee80211_queue_work(dev->wl->hw, &dev->restart_work); } -#ifdef CONFIG_PM - -static int b43_suspend(struct ssb_device *dev, pm_message_t state) -{ - struct b43_wldev *wldev = ssb_get_drvdata(dev); - struct b43_wl *wl = wldev->wl; - - b43dbg(wl, "Suspending...\n"); - - mutex_lock(&wl->mutex); - wldev->suspend_in_progress = true; - wldev->suspend_init_status = b43_status(wldev); - if (wldev->suspend_init_status >= B43_STAT_STARTED) - wldev = b43_wireless_core_stop(wldev); - if (wldev && wldev->suspend_init_status >= B43_STAT_INITIALIZED) - b43_wireless_core_exit(wldev); - mutex_unlock(&wl->mutex); - - b43dbg(wl, "Device suspended.\n"); - - return 0; -} - -static int b43_resume(struct ssb_device *dev) -{ - struct b43_wldev *wldev = ssb_get_drvdata(dev); - struct b43_wl *wl = wldev->wl; - int err = 0; - - b43dbg(wl, "Resuming...\n"); - - mutex_lock(&wl->mutex); - if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) { - err = b43_wireless_core_init(wldev); - if (err) { - b43err(wl, "Resume failed at core init\n"); - goto out; - } - } - if (wldev->suspend_init_status >= B43_STAT_STARTED) { - err = b43_wireless_core_start(wldev); - if (err) { - b43_leds_exit(wldev); - b43_rng_exit(wldev->wl); - b43_wireless_core_exit(wldev); - b43err(wl, "Resume failed at core start\n"); - goto out; - } - } - b43dbg(wl, "Device resumed.\n"); - out: - wldev->suspend_in_progress = false; - mutex_unlock(&wl->mutex); - return err; -} - -#else /* CONFIG_PM */ -# define b43_suspend NULL -# define b43_resume NULL -#endif /* CONFIG_PM */ - static struct ssb_driver b43_ssb_driver = { .name = KBUILD_MODNAME, .id_table = b43_ssb_tbl, .probe = b43_probe, .remove = b43_remove, - .suspend = b43_suspend, - .resume = b43_resume, }; static void b43_print_driverinfo(void) -- cgit v1.2.3-18-g5258 From 3dbba8e281552da640080f08a0f127d48456669f Mon Sep 17 00:00:00 2001 From: Albert Herranz Date: Thu, 10 Sep 2009 19:34:49 +0200 Subject: b43: Add Soft-MAC SDIO device support This adds support for Soft-MAC SDIO devices to b43. The driver still lacks some fixes for SDIO devices, so it's currently marked as BROKEN. Signed-off-by: Albert Herranz Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Kconfig | 21 +++- drivers/net/wireless/b43/Makefile | 1 + drivers/net/wireless/b43/main.c | 76 ++++++++++++--- drivers/net/wireless/b43/sdio.c | 197 ++++++++++++++++++++++++++++++++++++++ drivers/net/wireless/b43/sdio.h | 45 +++++++++ 5 files changed, 324 insertions(+), 16 deletions(-) create mode 100644 drivers/net/wireless/b43/sdio.c create mode 100644 drivers/net/wireless/b43/sdio.h (limited to 'drivers') diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 83e38134acc..4fc2ce429c7 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -61,11 +61,28 @@ config B43_PCMCIA If unsure, say N. +config B43_SDIO + bool "Broadcom 43xx SDIO device support (EXPERIMENTAL)" + depends on B43 && SSB_SDIOHOST_POSSIBLE && EXPERIMENTAL && BROKEN + select SSB_SDIOHOST + ---help--- + Broadcom 43xx device support for Soft-MAC SDIO devices. + + With this config option you can drive Soft-MAC b43 cards with a + Secure Digital I/O interface. + This includes the WLAN daughter card found on the Nintendo Wii + video game console. + Note that this does not support Broadcom 43xx Full-MAC devices. + + It's safe to select Y here, even if you don't have a B43 SDIO device. + + If unsure, say N. + # Data transfers to the device via PIO -# This is only needed on PCMCIA devices. All others can do DMA properly. +# This is only needed on PCMCIA and SDIO devices. All others can do DMA properly. config B43_PIO bool - depends on B43 && (B43_PCMCIA || B43_FORCE_PIO) + depends on B43 && (B43_SDIO || B43_PCMCIA || B43_FORCE_PIO) select SSB_BLOCKIO default y diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index da379f4b0c3..84772a2542d 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -16,6 +16,7 @@ b43-$(CONFIG_B43_PIO) += pio.o b43-y += rfkill.o b43-$(CONFIG_B43_LEDS) += leds.o b43-$(CONFIG_B43_PCMCIA) += pcmcia.o +b43-$(CONFIG_B43_SDIO) += sdio.o b43-$(CONFIG_B43_DEBUG) += debugfs.o obj-$(CONFIG_B43) += b43.o diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2984a915f8b..950a838757c 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -8,6 +8,9 @@ Copyright (c) 2005 Danny van Dyk Copyright (c) 2005 Andreas Jaggi + SDIO support + Copyright (c) 2009 Albert Herranz + Some parts of the code in this file are derived from the ipw2200 driver Copyright(c) 2003 - 2004 Intel Corporation. @@ -53,6 +56,8 @@ #include "xmit.h" #include "lo.h" #include "pcmcia.h" +#include "sdio.h" +#include MODULE_DESCRIPTION("Broadcom B43 wireless driver"); MODULE_AUTHOR("Martin Langer"); @@ -1587,7 +1592,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) mutex_lock(&wl->mutex); dev = wl->current_dev; if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { - if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { + if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) { /* wl->mutex is enough. */ b43_do_beacon_update_trigger_work(dev); mmiowb(); @@ -1905,6 +1910,27 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) return ret; } +/* SDIO interrupt handler. This runs in process context. */ +static void b43_sdio_interrupt_handler(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + struct sdio_func *func = dev->dev->bus->host_sdio; + irqreturn_t ret; + + if (unlikely(b43_status(dev) < B43_STAT_STARTED)) + return; + + mutex_lock(&wl->mutex); + sdio_release_host(func); + + ret = b43_do_interrupt(dev); + if (ret == IRQ_WAKE_THREAD) + b43_do_interrupt_thread(dev); + + sdio_claim_host(func); + mutex_unlock(&wl->mutex); +} + void b43_do_release_fw(struct b43_firmware_file *fw) { release_firmware(fw->data); @@ -3824,7 +3850,7 @@ redo: /* Disable interrupts on the device. */ b43_set_status(dev, B43_STAT_INITIALIZED); - if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { + if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) { /* wl->mutex is locked. That is enough. */ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ @@ -3854,7 +3880,10 @@ redo: dev_kfree_skb(skb_dequeue(&wl->tx_queue)); b43_mac_suspend(dev); - free_irq(dev->dev->irq, dev); + if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) + b43_sdio_free_irq(dev); + else + free_irq(dev->dev->irq, dev); b43_leds_exit(dev); b43dbg(wl, "Wireless interface stopped\n"); @@ -3869,12 +3898,20 @@ static int b43_wireless_core_start(struct b43_wldev *dev) B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED); drain_txstatus_queue(dev); - err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler, - b43_interrupt_thread_handler, - IRQF_SHARED, KBUILD_MODNAME, dev); - if (err) { - b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); - goto out; + if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) { + err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler); + if (err) { + b43err(dev->wl, "Cannot request SDIO IRQ\n"); + goto out; + } + } else { + err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler, + b43_interrupt_thread_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (err) { + b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); + goto out; + } } /* We are ready to run. */ @@ -4266,7 +4303,9 @@ static int b43_wireless_core_init(struct b43_wldev *dev) /* Maximum Contention Window */ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); - if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || B43_FORCE_PIO) { + if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || + (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) || + B43_FORCE_PIO) { dev->__using_pio_transfers = 1; err = b43_pio_init(dev); } else { @@ -4942,7 +4981,7 @@ static struct ssb_driver b43_ssb_driver = { static void b43_print_driverinfo(void) { const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "", - *feat_leds = ""; + *feat_leds = "", *feat_sdio = ""; #ifdef CONFIG_B43_PCI_AUTOSELECT feat_pci = "P"; @@ -4955,12 +4994,15 @@ static void b43_print_driverinfo(void) #endif #ifdef CONFIG_B43_LEDS feat_leds = "L"; +#endif +#ifdef CONFIG_B43_SDIO + feat_sdio = "S"; #endif printk(KERN_INFO "Broadcom 43xx driver loaded " - "[ Features: %s%s%s%s, Firmware-ID: " + "[ Features: %s%s%s%s%s, Firmware-ID: " B43_SUPPORTED_FIRMWARE_ID " ]\n", feat_pci, feat_pcmcia, feat_nphy, - feat_leds); + feat_leds, feat_sdio); } static int __init b43_init(void) @@ -4971,13 +5013,18 @@ static int __init b43_init(void) err = b43_pcmcia_init(); if (err) goto err_dfs_exit; - err = ssb_driver_register(&b43_ssb_driver); + err = b43_sdio_init(); if (err) goto err_pcmcia_exit; + err = ssb_driver_register(&b43_ssb_driver); + if (err) + goto err_sdio_exit; b43_print_driverinfo(); return err; +err_sdio_exit: + b43_sdio_exit(); err_pcmcia_exit: b43_pcmcia_exit(); err_dfs_exit: @@ -4988,6 +5035,7 @@ err_dfs_exit: static void __exit b43_exit(void) { ssb_driver_unregister(&b43_ssb_driver); + b43_sdio_exit(); b43_pcmcia_exit(); b43_debugfs_exit(); } diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c new file mode 100644 index 00000000000..2d337f1a60b --- /dev/null +++ b/drivers/net/wireless/b43/sdio.c @@ -0,0 +1,197 @@ +/* + * Broadcom B43 wireless driver + * + * SDIO over Sonics Silicon Backplane bus glue for b43. + * + * Copyright (C) 2009 Albert Herranz + * Copyright (C) 2009 Michael Buesch + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include "sdio.h" +#include "b43.h" + + +#define HNBU_CHIPID 0x01 /* vendor & device id */ + +#define B43_SDIO_BLOCK_SIZE 64 /* rx fifo max size in bytes */ + + +static const struct b43_sdio_quirk { + u16 vendor; + u16 device; + unsigned int quirks; +} b43_sdio_quirks[] = { + { 0x14E4, 0x4318, SSB_QUIRK_SDIO_READ_AFTER_WRITE32, }, + { }, +}; + + +static unsigned int b43_sdio_get_quirks(u16 vendor, u16 device) +{ + const struct b43_sdio_quirk *q; + + for (q = b43_sdio_quirks; q->quirks; q++) { + if (vendor == q->vendor && device == q->device) + return q->quirks; + } + + return 0; +} + +static void b43_sdio_interrupt_dispatcher(struct sdio_func *func) +{ + struct b43_sdio *sdio = sdio_get_drvdata(func); + struct b43_wldev *dev = sdio->irq_handler_opaque; + + sdio->irq_handler(dev); +} + +int b43_sdio_request_irq(struct b43_wldev *dev, + void (*handler)(struct b43_wldev *dev)) +{ + struct ssb_bus *bus = dev->dev->bus; + struct sdio_func *func = bus->host_sdio; + struct b43_sdio *sdio = sdio_get_drvdata(func); + int err; + + sdio->irq_handler_opaque = dev; + sdio->irq_handler = handler; + sdio_claim_host(func); + err = sdio_claim_irq(func, b43_sdio_interrupt_dispatcher); + sdio_release_host(func); + + return err; +} + +void b43_sdio_free_irq(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct sdio_func *func = bus->host_sdio; + struct b43_sdio *sdio = sdio_get_drvdata(func); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_release_host(func); + sdio->irq_handler_opaque = NULL; + sdio->irq_handler = NULL; +} + +static int b43_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct b43_sdio *sdio; + struct sdio_func_tuple *tuple; + u16 vendor = 0, device = 0; + int error; + + /* Look for the card chip identifier. */ + tuple = func->tuples; + while (tuple) { + switch (tuple->code) { + case 0x80: + switch (tuple->data[0]) { + case HNBU_CHIPID: + if (tuple->size != 5) + break; + vendor = tuple->data[1] | (tuple->data[2]<<8); + device = tuple->data[3] | (tuple->data[4]<<8); + dev_info(&func->dev, "Chip ID %04x:%04x\n", + vendor, device); + break; + default: + break; + } + break; + default: + break; + } + tuple = tuple->next; + } + if (!vendor || !device) { + error = -ENODEV; + goto out; + } + + sdio_claim_host(func); + error = sdio_set_block_size(func, B43_SDIO_BLOCK_SIZE); + if (error) { + dev_err(&func->dev, "failed to set block size to %u bytes," + " error %d\n", B43_SDIO_BLOCK_SIZE, error); + goto err_release_host; + } + error = sdio_enable_func(func); + if (error) { + dev_err(&func->dev, "failed to enable func, error %d\n", error); + goto err_release_host; + } + sdio_release_host(func); + + sdio = kzalloc(sizeof(*sdio), GFP_KERNEL); + if (!sdio) { + error = -ENOMEM; + dev_err(&func->dev, "failed to allocate ssb bus\n"); + goto err_disable_func; + } + error = ssb_bus_sdiobus_register(&sdio->ssb, func, + b43_sdio_get_quirks(vendor, device)); + if (error) { + dev_err(&func->dev, "failed to register ssb sdio bus," + " error %d\n", error); + goto err_free_ssb; + } + sdio_set_drvdata(func, sdio); + + return 0; + +err_free_ssb: + kfree(sdio); +err_disable_func: + sdio_disable_func(func); +err_release_host: + sdio_release_host(func); +out: + return error; +} + +static void b43_sdio_remove(struct sdio_func *func) +{ + struct b43_sdio *sdio = sdio_get_drvdata(func); + + ssb_bus_unregister(&sdio->ssb); + sdio_disable_func(func); + kfree(sdio); + sdio_set_drvdata(func, NULL); +} + +static const struct sdio_device_id b43_sdio_ids[] = { + { SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */ + { }, +}; + +static struct sdio_driver b43_sdio_driver = { + .name = "b43-sdio", + .id_table = b43_sdio_ids, + .probe = b43_sdio_probe, + .remove = b43_sdio_remove, +}; + +int b43_sdio_init(void) +{ + return sdio_register_driver(&b43_sdio_driver); +} + +void b43_sdio_exit(void) +{ + sdio_unregister_driver(&b43_sdio_driver); +} diff --git a/drivers/net/wireless/b43/sdio.h b/drivers/net/wireless/b43/sdio.h new file mode 100644 index 00000000000..fb633094403 --- /dev/null +++ b/drivers/net/wireless/b43/sdio.h @@ -0,0 +1,45 @@ +#ifndef B43_SDIO_H_ +#define B43_SDIO_H_ + +#include + +struct b43_wldev; + + +#ifdef CONFIG_B43_SDIO + +struct b43_sdio { + struct ssb_bus ssb; + void *irq_handler_opaque; + void (*irq_handler)(struct b43_wldev *dev); +}; + +int b43_sdio_request_irq(struct b43_wldev *dev, + void (*handler)(struct b43_wldev *dev)); +void b43_sdio_free_irq(struct b43_wldev *dev); + +int b43_sdio_init(void); +void b43_sdio_exit(void); + + +#else /* CONFIG_B43_SDIO */ + + +int b43_sdio_request_irq(struct b43_wldev *dev, + void (*handler)(struct b43_wldev *dev)) +{ + return -ENODEV; +} +void b43_sdio_free_irq(struct b43_wldev *dev) +{ +} +static inline int b43_sdio_init(void) +{ + return 0; +} +static inline void b43_sdio_exit(void) +{ +} + +#endif /* CONFIG_B43_SDIO */ +#endif /* B43_SDIO_H_ */ -- cgit v1.2.3-18-g5258 From ce6c4a13927bc0418169fe543c6614abfab051eb Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 10 Sep 2009 20:22:02 +0200 Subject: b43: Do not use _irqsafe callbacks We don't need to call the irqsafe callbacks. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/dma.c | 4 ++-- drivers/net/wireless/b43/pio.c | 2 +- drivers/net/wireless/b43/xmit.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index a467ee260a1..8701034569f 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1428,9 +1428,9 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, ring->nr_failed_tx_packets++; ring->nr_total_packet_tries += status->frame_count; #endif /* DEBUG */ - ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); + ieee80211_tx_status(dev->wl->hw, meta->skb); - /* skb is freed by ieee80211_tx_status_irqsafe() */ + /* skb is freed by ieee80211_tx_status() */ meta->skb = NULL; } else { /* No need to call free_descriptor_buffer here, as diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 3498b68385e..e96091b3149 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -574,7 +574,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, q->buffer_used -= total_len; q->free_packet_slots += 1; - ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb); + ieee80211_tx_status(dev->wl->hw, pack->skb); pack->skb = NULL; list_add(&pack->list, &q->packets_list); diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 14f541248b5..c403c616d3b 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -690,7 +690,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) } memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); - ieee80211_rx_irqsafe(dev->wl->hw, skb); + ieee80211_rx(dev->wl->hw, skb); return; drop: -- cgit v1.2.3-18-g5258 From a8696c800b8154e27b359866f7b837079cdb513a Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 11 Sep 2009 16:00:19 +0200 Subject: b43: Fix SDIO interrupt handler deadlock We need to release the SDIO host before locking the driver mutex. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 6 ------ drivers/net/wireless/b43/sdio.c | 5 +++++ 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 950a838757c..5b0aeff01db 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1914,20 +1914,14 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) static void b43_sdio_interrupt_handler(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; - struct sdio_func *func = dev->dev->bus->host_sdio; irqreturn_t ret; - if (unlikely(b43_status(dev) < B43_STAT_STARTED)) - return; - mutex_lock(&wl->mutex); - sdio_release_host(func); ret = b43_do_interrupt(dev); if (ret == IRQ_WAKE_THREAD) b43_do_interrupt_thread(dev); - sdio_claim_host(func); mutex_unlock(&wl->mutex); } diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c index 2d337f1a60b..0d3ac64147a 100644 --- a/drivers/net/wireless/b43/sdio.c +++ b/drivers/net/wireless/b43/sdio.c @@ -54,7 +54,12 @@ static void b43_sdio_interrupt_dispatcher(struct sdio_func *func) struct b43_sdio *sdio = sdio_get_drvdata(func); struct b43_wldev *dev = sdio->irq_handler_opaque; + if (unlikely(b43_status(dev) < B43_STAT_STARTED)) + return; + + sdio_release_host(func); sdio->irq_handler(dev); + sdio_claim_host(func); } int b43_sdio_request_irq(struct b43_wldev *dev, -- cgit v1.2.3-18-g5258 From 176e9f6a4cf4b1bf66d18243ede0938a35c81541 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 11 Sep 2009 23:04:04 +0200 Subject: b43: Fix IRQ sync for SDIO synchronize_irq is meaningless for SDIO. sdio_release_irq will sync the IRQ thread for us. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 5b0aeff01db..7d22dadfd89 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3854,10 +3854,15 @@ redo: b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ spin_unlock_irq(&wl->hardirq_lock); } - /* Synchronize the interrupt handlers. Unlock to avoid deadlocks. */ + /* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */ orig_dev = dev; mutex_unlock(&wl->mutex); - synchronize_irq(dev->dev->irq); + if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) { + b43_sdio_free_irq(dev); + } else { + synchronize_irq(dev->dev->irq); + free_irq(dev->dev->irq, dev); + } mutex_lock(&wl->mutex); dev = wl->current_dev; if (!dev) @@ -3874,10 +3879,6 @@ redo: dev_kfree_skb(skb_dequeue(&wl->tx_queue)); b43_mac_suspend(dev); - if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) - b43_sdio_free_irq(dev); - else - free_irq(dev->dev->irq, dev); b43_leds_exit(dev); b43dbg(wl, "Wireless interface stopped\n"); -- cgit v1.2.3-18-g5258 From 990b86f4f9c54f83085d4136498ac44719b17654 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 12 Sep 2009 00:48:03 +0200 Subject: b43: Add optional verbose runtime statistics This adds support for verbose runtime statistics. It defaults to off and must be enabled in debugfs, if desired. The first measurement may be incorrect, because statistics are not cleared after they got enabled through debugfs. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 4 ++++ drivers/net/wireless/b43/debugfs.c | 1 + drivers/net/wireless/b43/debugfs.h | 1 + drivers/net/wireless/b43/main.c | 34 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/b43/xmit.c | 3 +++ 5 files changed, 43 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 89ccf0d50f3..fa1549a03c7 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -817,6 +817,10 @@ struct b43_wldev { /* Debugging stuff follows. */ #ifdef CONFIG_B43_DEBUG struct b43_dfsentry *dfsentry; + unsigned int irq_count; + unsigned int irq_bit_count[32]; + unsigned int tx_count; + unsigned int rx_count; #endif }; diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 8f64943e3f6..80b19a44a40 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -689,6 +689,7 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev) add_dyn_dbg("debug_lo", B43_DBG_LO, 0); add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0); add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0); + add_dyn_dbg("debug_v