Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorDavid S. Miller <davem@davemloft.net>
Wed, 23 Sep 2009 23:23:46 +0000 (16:23 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 23 Sep 2009 23:23:46 +0000 (16:23 -0700)
Conflicts:
drivers/net/wireless/iwlwifi/iwl-rx.c

33 files changed:
drivers/net/wireless/ath/ar9170/usb.c
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/calib.h
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/b43/Kconfig
drivers/net/wireless/b43/Makefile
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/debugfs.c
drivers/net/wireless/b43/debugfs.h
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/leds.c
drivers/net/wireless/b43/leds.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_lp.c
drivers/net/wireless/b43/pio.c
drivers/net/wireless/b43/rfkill.c
drivers/net/wireless/b43/sdio.c [new file with mode: 0644]
drivers/net/wireless/b43/sdio.h [new file with mode: 0644]
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/rt2x00/rt2x00lib.h
drivers/net/wireless/wl12xx/Kconfig
drivers/net/wireless/zd1211rw/zd_usb.c
net/mac80211/scan.c
net/wireless/wext-sme.c

index e0138ac..e974e58 100644 (file)
@@ -64,6 +64,8 @@ static struct usb_device_id ar9170_usb_ids[] = {
        { USB_DEVICE(0x0cf3, 0x9170) },
        /* Atheros TG121N */
        { USB_DEVICE(0x0cf3, 0x1001) },
+       /* TP-Link TL-WN821N v2 */
+       { USB_DEVICE(0x0cf3, 0x1002) },
        /* Cace Airpcap NX */
        { USB_DEVICE(0xcace, 0x0300) },
        /* D-Link DWA 160A */
index 3234995..0ad6d0b 100644 (file)
@@ -609,14 +609,24 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
                AR_PHY_CH1_EXT_CCA,
                AR_PHY_CH2_EXT_CCA
        };
-       u8 chainmask;
+       u8 chainmask, rx_chain_status;
 
+       rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK);
        if (AR_SREV_9285(ah))
                chainmask = 0x9;
-       else if (AR_SREV_9280(ah) || AR_SREV_9287(ah))
-               chainmask = 0x1B;
-       else
-               chainmask = 0x3F;
+       else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
+               if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4))
+                       chainmask = 0x1B;
+               else
+                       chainmask = 0x09;
+       } else {
+               if (rx_chain_status & 0x4)
+                       chainmask = 0x3F;
+               else if (rx_chain_status & 0x2)
+                       chainmask = 0x1B;
+               else
+                       chainmask = 0x09;
+       }
 
        h = ah->nfCalHist;
 
@@ -697,6 +707,8 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
                noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
        else if (AR_SREV_9285(ah))
                noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
+       else if (AR_SREV_9287(ah))
+               noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE;
        else
                noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
 
@@ -924,6 +936,7 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset)
                regVal |= (1 << (19 + i));
                REG_WRITE(ah, 0x7834, regVal);
                udelay(1);
+               regVal = REG_READ(ah, 0x7834);
                regVal &= (~(0x1 << (19 + i)));
                reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
                regVal |= (reg_field << (19 + i));
index 019bcbb..9028ab1 100644 (file)
@@ -28,6 +28,7 @@ extern const struct ath9k_percal_data adc_init_dc_cal;
 #define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE       -85
 #define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE       -112
 #define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE       -118
+#define AR_PHY_CCA_MAX_AR9287_GOOD_VALUE       -118
 #define AR_PHY_CCA_MAX_HIGH_VALUE                      -62
 #define AR_PHY_CCA_MIN_BAD_VALUE                       -140
 #define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT     3
index ae7fb5d..4071fc9 100644 (file)
@@ -509,6 +509,8 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
                        REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE,
                                      eep->baseEepHeader.dacLpMode);
 
+               udelay(100);
+
                REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP,
                              pModal->miscBits >> 2);
 
@@ -902,7 +904,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
                                                  u16 powerLimit)
 {
 #define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6  /* 10*log10(2)*2 */
-#define REDUCE_SCALED_POWER_BY_THREE_CHAIN   10 /* 10*log10(3)*2 */
+#define REDUCE_SCALED_POWER_BY_THREE_CHAIN   9 /* 10*log10(3)*2 */
 
        struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
        struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
index b6c6cca..ca7694c 100644 (file)
@@ -842,7 +842,7 @@ static void ath9k_hw_init_mode_regs(struct ath_hw *ah)
 
 static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
 {
-       if (AR_SREV_9287_11(ah))
+       if (AR_SREV_9287_11_OR_LATER(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                ar9287Modes_rx_gain_9287_1_1,
                ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6);
@@ -853,7 +853,7 @@ static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
        else if (AR_SREV_9280_20(ah))
                ath9k_hw_init_rxgain_ini(ah);
 
-       if (AR_SREV_9287_11(ah)) {
+       if (AR_SREV_9287_11_OR_LATER(ah)) {
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                ar9287Modes_tx_gain_9287_1_1,
                ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6);
@@ -965,7 +965,7 @@ int ath9k_hw_init(struct ath_hw *ah)
        ath9k_hw_init_mode_regs(ah);
 
        if (ah->is_pciexpress)
-               ath9k_hw_configpcipowersave(ah, 0);
+               ath9k_hw_configpcipowersave(ah, 0, 0);
        else
                ath9k_hw_disablepcie(ah);
 
@@ -1273,6 +1273,15 @@ static void ath9k_hw_override_ini(struct ath_hw *ah,
         */
        REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
 
+       if (AR_SREV_9280_10_OR_LATER(ah)) {
+               val = REG_READ(ah, AR_PCU_MISC_MODE2) &
+                              (~AR_PCU_MISC_MODE2_HWWAR1);
+
+               if (AR_SREV_9287_10_OR_LATER(ah))
+                       val = val & (~AR_PCU_MISC_MODE2_HWWAR2);
+
+               REG_WRITE(ah, AR_PCU_MISC_MODE2, val);
+       }
 
        if (!AR_SREV_5416_20_OR_LATER(ah) ||
            AR_SREV_9280_10_OR_LATER(ah))
@@ -1784,7 +1793,7 @@ static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan,
 static bool ath9k_hw_chip_reset(struct ath_hw *ah,
                                struct ath9k_channel *chan)
 {
-       if (OLC_FOR_AR9280_20_LATER) {
+       if (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) {
                if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON))
                        return false;
        } else if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
@@ -2338,6 +2347,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        struct ath9k_channel *curchan = ah->curchan;
        u32 saveDefAntenna;
        u32 macStaId1;
+       u64 tsf = 0;
        int i, rx_chainmask, r;
 
        ah->extprotspacing = sc->ht_extprotspacing;
@@ -2347,7 +2357,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
                return -EIO;
 
-       if (curchan)
+       if (curchan && !ah->chip_fullsleep)
                ath9k_hw_getnf(ah, curchan);
 
        if (bChannelChange &&
@@ -2356,8 +2366,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
            (chan->channel != ah->curchan->channel) &&
            ((chan->channelFlags & CHANNEL_ALL) ==
             (ah->curchan->channelFlags & CHANNEL_ALL)) &&
-           (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) &&
-                                  !IS_CHAN_A_5MHZ_SPACED(ah->curchan)))) {
+            !(AR_SREV_9280(ah) || IS_CHAN_A_5MHZ_SPACED(chan) ||
+            IS_CHAN_A_5MHZ_SPACED(ah->curchan))) {
 
                if (ath9k_hw_channel_change(ah, chan, sc->tx_chan_width)) {
                        ath9k_hw_loadnf(ah, ah->curchan);
@@ -2372,6 +2382,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
 
+       /* For chips on which RTC reset is done, save TSF before it gets cleared */
+       if (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+               tsf = ath9k_hw_gettsf64(ah);
+
        saveLedState = REG_READ(ah, AR_CFG_LED) &
                (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
                 AR_CFG_LED_BLINK_THRESH_SEL | AR_CFG_LED_BLINK_SLOW);
@@ -2398,6 +2412,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                udelay(50);
        }
 
+       /* Restore TSF */
+       if (tsf && AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+               ath9k_hw_settsf64(ah, tsf);
+
        if (AR_SREV_9280_10_OR_LATER(ah))
                REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
 
@@ -3005,9 +3023,10 @@ void ath9k_ps_restore(struct ath_softc *sc)
  * Programming the SerDes must go through the same 288 bit serial shift
  * register as the other analog registers.  Hence the 9 writes.
  */
-void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore)
+void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off)
 {
        u8 i;
+       u32 val;
 
        if (ah->is_pciexpress != true)
                return;
@@ -3017,84 +3036,113 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore)
                return;
 
        /* Nothing to do on restore for 11N */
-       if (restore)
-               return;
+       if (!restore) {
+               if (AR_SREV_9280_20_OR_LATER(ah)) {
+                       /*
+                        * AR9280 2.0 or later chips use SerDes values from the
+                        * initvals.h initialized depending on chipset during
+                        * ath9k_hw_init()
+                        */
+                       for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) {
+                               REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
+                                         INI_RA(&ah->iniPcieSerdes, i, 1));
+                       }
+               } else if (AR_SREV_9280(ah) &&
+                          (ah->hw_version.macRev == AR_SREV_REVISION_9280_10)) {
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+
+                       /* RX shut off when elecidle is asserted */
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
+
+                       /* Shut off CLKREQ active in L1 */
+                       if (ah->config.pcie_clock_req)
+                               REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
+                       else
+                               REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
 
-       if (AR_SREV_9280_20_OR_LATER(ah)) {
-               /*
-                * AR9280 2.0 or later chips use SerDes values from the
-                * initvals.h initialized depending on chipset during
-                * ath9k_hw_init()
-                */
-               for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) {
-                       REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
-                                 INI_RA(&ah->iniPcieSerdes, i, 1));
-               }
-       } else if (AR_SREV_9280(ah) &&
-                  (ah->hw_version.macRev == AR_SREV_REVISION_9280_10)) {
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
 
-               /* RX shut off when elecidle is asserted */
-               REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
+                       /* Load the new settings */
+                       REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
 
-               /* Shut off CLKREQ active in L1 */
-               if (ah->config.pcie_clock_req)
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
-               else
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
-
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
+               } else {
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
 
-               /* Load the new settings */
-               REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+                       /* RX shut off when elecidle is asserted */
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
 
-       } else {
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+                       /*
+                        * Ignore ah->ah_config.pcie_clock_req setting for
+                        * pre-AR9280 11n
+                        */
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
 
-               /* RX shut off when elecidle is asserted */
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
 
-               /*
-                * Ignore ah->ah_config.pcie_clock_req setting for
-                * pre-AR9280 11n
-                */
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
+                       /* Load the new settings */
+                       REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+               }
 
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
+               udelay(1000);
 
-               /* Load the new settings */
-               REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-       }
+               /* set bit 19 to allow forcing of pcie core into L1 state */
+               REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
 
-       udelay(1000);
+               /* Several PCIe massages to ensure proper behaviour */
+               if (ah->config.pcie_waen) {
+                       val = ah->config.pcie_waen;
+                       if (!power_off)
+                               val &= (~AR_WA_D3_L1_DISABLE);
+               } else {
+                       if (AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
+                           AR_SREV_9287(ah)) {
+                               val = AR9285_WA_DEFAULT;
+                               if (!power_off)
+                                       val &= (~AR_WA_D3_L1_DISABLE);
+                       } else if (AR_SREV_9280(ah)) {
+                               /*
+                                * On AR9280 chips bit 22 of 0x4004 needs to be
+                                * set otherwise card may disappear.
+                                */
+                               val = AR9280_WA_DEFAULT;
+                               if (!power_off)
+                                       val &= (~AR_WA_D3_L1_DISABLE);
+                       } else
+                               val = AR_WA_DEFAULT;
+               }
 
-       /* set bit 19 to allow forcing of pcie core into L1 state */
-       REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+               REG_WRITE(ah, AR_WA, val);
+       }
 
-       /* Several PCIe massages to ensure proper behaviour */
-       if (ah->config.pcie_waen) {
-               REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
-       } else {
-               if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah))
-                       REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT);
+       if (power_off) {
                /*
-                * On AR9280 chips bit 22 of 0x4004 needs to be set to
-                * otherwise card may disappear.
+                * Set PCIe workaround bits
+                * bit 14 in WA register (disable L1) should only
+                * be set when device enters D3 and be cleared
+                * when device comes back to D0.
                 */
-               else if (AR_SREV_9280(ah))
-                       REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT);
-               else
-                       REG_WRITE(ah, AR_WA, AR_WA_DEFAULT);
+               if (ah->config.pcie_waen) {
+                       if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
+                               REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
+               } else {
+                       if (((AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
+                             AR_SREV_9287(ah)) &&
+                            (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) ||
+                           (AR_SREV_9280(ah) &&
+                            (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) {
+                               REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
+                       }
+               }
        }
 }
 
@@ -3652,15 +3700,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
        }
 #endif
 
-       if ((ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) ||
-           (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) ||
-           (ah->hw_version.macVersion == AR_SREV_VERSION_9160) ||
-           (ah->hw_version.macVersion == AR_SREV_VERSION_9100) ||
-           (ah->hw_version.macVersion == AR_SREV_VERSION_9280) ||
-           (ah->hw_version.macVersion == AR_SREV_VERSION_9285))
-               pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
-       else
-               pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
+       pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
 
        if (AR_SREV_9280(ah) || AR_SREV_9285(ah))
                pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS;
index 9106a0b..b892345 100644 (file)
 #define AH_TSF_WRITE_TIMEOUT        100    /* (us) */
 #define AH_TIME_QUANTUM             10
 #define AR_KEYTABLE_SIZE            128
-#define POWER_UP_TIME               200000
+#define POWER_UP_TIME               10000
 #define SPUR_RSSI_THRESH            40
 
 #define CAB_TIMEOUT_VAL             10
@@ -650,7 +650,7 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
                                    const struct ath9k_beacon_state *bs);
 bool ath9k_hw_setpower(struct ath_hw *ah,
                       enum ath9k_power_mode mode);
-void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore);
+void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off);
 
 /* Interrupt Handling */
 bool ath9k_hw_intrpend(struct ath_hw *ah);
index 3dc7b5a..52bed89 100644 (file)
@@ -1131,7 +1131,7 @@ void ath_radio_enable(struct ath_softc *sc)
        int r;
 
        ath9k_ps_wakeup(sc);
-       ath9k_hw_configpcipowersave(ah, 0);
+       ath9k_hw_configpcipowersave(ah, 0, 0);
 
        if (!ah->curchan)
                ah->curchan = ath_get_curchannel(sc, sc->hw);
@@ -1202,7 +1202,7 @@ void ath_radio_disable(struct ath_softc *sc)
        spin_unlock_bh(&sc->sc_resetlock);
 
        ath9k_hw_phy_disable(ah);
-       ath9k_hw_configpcipowersave(ah, 1);
+       ath9k_hw_configpcipowersave(ah, 1, 1);
        ath9k_ps_restore(sc);
        ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
 }
@@ -1226,11 +1226,6 @@ static void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)
        bool blocked = !!ath_is_rfkill_set(sc);
 
        wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
-
-       if (blocked)
-               ath_radio_disable(sc);
-       else
-               ath_radio_enable(sc);
 }
 
 static void ath_start_rfkill_poll(struct ath_softc *sc)
@@ -1260,6 +1255,7 @@ void ath_detach(struct ath_softc *sc)
        DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n");
 
        ath_deinit_leds(sc);
+       wiphy_rfkill_stop_polling(sc->hw->wiphy);
 
        for (i = 0; i < sc->num_sec_wiphy; i++) {
                struct ath_wiphy *aphy = sc->sec_wiphy[i];
@@ -1942,7 +1938,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
        init_channel = ath_get_curchannel(sc, hw);
 
        /* Reset SERDES registers */
-       ath9k_hw_configpcipowersave(sc->sc_ah, 0);
+       ath9k_hw_configpcipowersave(sc->sc_ah, 0, 0);
 
        /*
         * The basic interface to setting the hardware in a good
@@ -2166,11 +2162,9 @@ static void ath9k_stop(struct ieee80211_hw *hw)
        } else
                sc->rx.rxlink = NULL;
 
-       wiphy_rfkill_stop_polling(sc->hw->wiphy);
-
        /* disable HAL and put h/w to sleep */
        ath9k_hw_disable(sc->sc_ah);
-       ath9k_hw_configpcipowersave(sc->sc_ah, 1);
+       ath9k_hw_configpcipowersave(sc->sc_ah, 1, 1);
        ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
 
        sc->sc_flags |= SC_OP_INVALID;
index e5c29eb..d83b77f 100644 (file)
 #define AR_RC_HOSTIF         0x00000100
 
 #define AR_WA                          0x4004
+#define AR_WA_D3_L1_DISABLE            (1 << 14)
 #define AR9285_WA_DEFAULT              0x004a05cb
-#define AR9280_WA_DEFAULT              0x0040073f
+#define AR9280_WA_DEFAULT              0x0040073b
 #define AR_WA_DEFAULT                  0x0000073f
 
 
index 83e3813..54ea61c 100644 (file)
@@ -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
+       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
 
index da379f4..84772a2 100644 (file)
@@ -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
index 09cfe68..fa1549a 100644 (file)
@@ -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];
@@ -830,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
 };
 
index 8f64943..80b19a4 100644 (file)
@@ -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_verbose_stats", B43_DBG_VERBOSESTATS, 0);
 
 #undef add_dyn_dbg
 }
index e47b4b4..822aad8 100644 (file)
@@ -13,6 +13,7 @@ enum b43_dyndbg {             /* Dynamic debugging features */
        B43_DBG_LO,
        B43_DBG_FIRMWARE,
        B43_DBG_KEYS,
+       B43_DBG_VERBOSESTATS,
        __B43_NR_DYNDBG,
 };
 
index a467ee2..8701034 100644 (file)
@@ -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
index c8b3170..fbe3d4f 100644 (file)
 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;
+
+       if (likely(!wl->leds.stop)) {
+               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 +124,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 +141,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 +168,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 +191,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 +210,150 @@ 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);
                }
-               b43_map_led(dev, i, behaviour, activelow);
        }
+
+       /* 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;
+               }
+       }
+
+       dev->wl->leds.stop = 0;
 }
 
 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_stop(struct b43_wldev *dev)
+{
+       struct b43_leds *leds = &dev->wl->leds;
+
+       leds->stop = 1;
+       cancel_work_sync(&leds->work);
+}
+
+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);
 }
index b8b1dd5..9592e4c 100644 (file)
@@ -7,12 +7,13 @@ struct b43_wldev;
 
 #include <linux/types.h>
 #include <linux/leds.h>
+#include <linux/workqueue.h>
 
 
 #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,24 @@ 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;
+
+       bool stop;
+       struct work_struct work;
+};
+
+#define B43_MAX_NR_LEDS                        4
+
 #define B43_LED_BEHAVIOUR              0x7F
 #define B43_LED_ACTIVELOW              0x80
 /* LED behaviour values */
@@ -42,23 +59,35 @@ 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);
+void b43_leds_stop(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)
 {
 }
 static inline void b43_leds_exit(struct b43_wldev *dev)
 {
 }
+static inline void b43_leds_stop(struct b43_wldev *dev)
+{
+}
 #endif /* CONFIG_B43_LEDS */
 
 #endif /* B43_LEDS_H_ */
index e789792..9b907a3 100644 (file)
@@ -8,6 +8,9 @@
   Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
 
+  SDIO support
+  Copyright (c) 2009 Albert Herranz <albert_herranz@yahoo.es>
+
   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 <linux/mmc/sdio_func.h>
 
 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();
@@ -1825,6 +1830,16 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev)
 
        /* Re-enable interrupts on the device by restoring the current interrupt mask. */
        b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
+
+#if B43_DEBUG
+       if (b43_debug(dev, B43_DBG_VERBOSESTATS)) {
+               dev->irq_count++;
+               for (i = 0; i < ARRAY_SIZE(dev->irq_bit_count); i++) {
+                       if (reason & (1 << i))
+                               dev->irq_bit_count[i]++;
+               }
+       }
+#endif
 }
 
 /* Interrupt thread handler. Handles device interrupts in thread context. */
@@ -1905,6 +1920,21 @@ 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;
+       irqreturn_t ret;
+
+       mutex_lock(&wl->mutex);
+
+       ret = b43_do_interrupt(dev);
+       if (ret == IRQ_WAKE_THREAD)
+               b43_do_interrupt_thread(dev);
+
+       mutex_unlock(&wl->mutex);
+}
+
 void b43_do_release_fw(struct b43_firmware_file *fw)
 {
        release_firmware(fw->data);
@@ -2645,6 +2675,20 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
                        cfp_pretbtt = 50;
        }
        b43_write16(dev, 0x612, cfp_pretbtt);
+
+       /* FIXME: We don't currently implement the PMQ mechanism,
+        *        so always disable it. If we want to implement PMQ,
+        *        we need to enable it here (clear DISCPMQ) in AP mode.
+        */
+       if (0  /* ctl & B43_MACCTL_AP */) {
+               b43_write32(dev, B43_MMIO_MACCTL,
+                           b43_read32(dev, B43_MMIO_MACCTL)
+                           & ~B43_MACCTL_DISCPMQ);
+       } else {
+               b43_write32(dev, B43_MMIO_MACCTL,
+                           b43_read32(dev, B43_MMIO_MACCTL)
+                           | B43_MACCTL_DISCPMQ);
+       }
 }
 
 static void b43_rate_memory_write(struct b43_wldev *dev, u16 rate, int is_ofdm)
@@ -2873,6 +2917,27 @@ static void b43_periodic_every15sec(struct b43_wldev *dev)
 
        atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
        wmb();
+
+#if B43_DEBUG
+       if (b43_debug(dev, B43_DBG_VERBOSESTATS)) {
+               unsigned int i;
+
+               b43dbg(dev->wl, "Stats: %7u IRQs/sec, %7u TX/sec, %7u RX/sec\n",
+                      dev->irq_count / 15,
+                      dev->tx_count / 15,
+                      dev->rx_count / 15);
+               dev->irq_count = 0;
+               dev->tx_count = 0;
+               dev->rx_count = 0;
+               for (i = 0; i < ARRAY_SIZE(dev->irq_bit_count); i++) {
+                       if (dev->irq_bit_count[i]) {
+                               b43dbg(dev->wl, "Stats: %7u IRQ-%02u/sec (0x%08X)\n",
+                                      dev->irq_bit_count[i] / 15, i, (1 << i));
+                               dev->irq_bit_count[i] = 0;
+                       }
+               }
+       }
+#endif
 }
 
 static void do_periodic_work(struct b43_wldev *dev)
@@ -3002,14 +3067,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 */
 
@@ -3068,6 +3137,9 @@ static void b43_tx_work(struct work_struct *work)
                        dev_kfree_skb(skb); /* Drop it */
        }
 
+#if B43_DEBUG
+       dev->tx_count++;
+#endif
        mutex_unlock(&wl->mutex);
 }
 
@@ -3820,7 +3892,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 */
@@ -3830,10 +3902,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)
@@ -3850,7 +3927,7 @@ redo:
                dev_kfree_skb(skb_dequeue(&wl->tx_queue));
 
        b43_mac_suspend(dev);
-       free_irq(dev->dev->irq, dev);
+       b43_leds_exit(dev);
        b43dbg(wl, "Wireless interface stopped\n");
 
        return dev;
@@ -3864,12 +3941,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. */
@@ -3882,8 +3967,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 +4247,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 +4263,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;
@@ -4264,7 +4346,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 {
@@ -4280,15 +4364,13 @@ 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);
 
        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 +4919,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 +4959,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 +4989,15 @@ 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;
+               b43_leds_stop(wldev);
                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,80 +5015,17 @@ 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)
 {
        const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "",
-                  *feat_leds = "";
+                  *feat_leds = "", *feat_sdio = "";
 
 #ifdef CONFIG_B43_PCI_AUTOSELECT
        feat_pci = "P";
@@ -5015,12 +5038,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)
@@ -5031,13 +5057,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:
@@ -5048,6 +5079,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();
 }
index 3e02d96..1e318d8 100644 (file)
@@ -2228,6 +2228,16 @@ static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
        return B43_TXPWR_RES_DONE;
 }
 
+void b43_lpphy_op_switch_analog(struct b43_wldev *dev, bool on)
+{
+       if (on) {
+               b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xfff8);
+       } else {
+               b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0x0007);
+               b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x0007);
+       }
+}
+
 const struct b43_phy_operations b43_phyops_lp = {
        .allocate               = b43_lpphy_op_allocate,
        .free                   = b43_lpphy_op_free,
@@ -2239,7 +2249,7 @@ const struct b43_phy_operations b43_phyops_lp = {
        .radio_read             = b43_lpphy_op_radio_read,
        .radio_write            = b43_lpphy_op_radio_write,
        .software_rfkill        = b43_lpphy_op_software_rfkill,
-       .switch_analog          = b43_phyop_switch_analog_generic,
+       .switch_analog          = b43_lpphy_op_switch_analog,
        .switch_channel         = b43_lpphy_op_switch_channel,
        .get_default_chan       = b43_lpphy_op_get_default_chan,
        .set_rx_antenna         = b43_lpphy_op_set_rx_antenna,
index 3498b68..e96091b 100644 (file)
@@ -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);
 
index 31e5599..7a3218c 100644 (file)
@@ -28,7 +28,7 @@
 /* Returns TRUE, if the radio is enabled in hardware. */
 bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
 {
-       if (dev->phy.rev >= 3) {
+       if (dev->phy.rev >= 3 || dev->phy.type == B43_PHYTYPE_LP) {
                if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI)
                      & B43_MMIO_RADIO_HWENABLED_HI_MASK))
                        return 1;
diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c
new file mode 100644 (file)
index 0000000..0d3ac64
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Broadcom B43 wireless driver
+ *
+ * SDIO over Sonics Silicon Backplane bus glue for b43.
+ *
+ * Copyright (C) 2009 Albert Herranz
+ * Copyright (C) 2009 Michael Buesch <mb@bu3sch.de>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/ssb/ssb.h>
+
+#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;
+
+       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,
+                        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 (file)
index 0000000..fb63309
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef B43_SDIO_H_
+#define B43_SDIO_H_
+
+#include <linux/ssb/ssb.h>
+
+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_ */
index 14f5412..ac9f600 100644 (file)
@@ -690,8 +690,11 @@ 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);
 
+#if B43_DEBUG
+       dev->rx_count++;
+#endif
        return;
 drop:
        b43dbg(dev->wl, "RX: Packet dropped\n");
index ca61d37..3259b88 100644 (file)
@@ -2021,6 +2021,12 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
                                           agg->frame_count, txq_id, idx);
 
                        hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
+                       if (!hdr) {
+                               IWL_ERR(priv,
+                                       "BUG_ON idx doesn't point to valid skb"
+                                       " idx=%d, txq_id=%d\n", idx, txq_id);
+                               return -1;
+                       }
 
                        sc = le16_to_cpu(hdr->seq_ctrl);
                        if (idx != (SEQ_TO_SN(sc) & 0xff)) {
index 1d539e3..a6391c7 100644 (file)
@@ -1163,6 +1163,12 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
                                           agg->frame_count, txq_id, idx);
 
                        hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
+                       if (!hdr) {
+                               IWL_ERR(priv,
+                                       "BUG_ON idx doesn't point to valid skb"
+                                       " idx=%d, txq_id=%d\n", idx, txq_id);
+                               return -1;
+                       }
 
                        sc = le16_to_cpu(hdr->seq_ctrl);
                        if (idx != (SEQ_TO_SN(sc) & 0xff)) {
index b90adcb..8e1bb53 100644 (file)
@@ -250,12 +250,20 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
                }
                spin_unlock_irqrestore(&rxq->lock, flags);
 
+               if (rxq->free_count > RX_LOW_WATERMARK)
+                       priority |= __GFP_NOWARN;
                /* Alloc a new receive buffer */
                skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
                                                priority);
 
                if (!skb) {
-                       IWL_CRIT(priv, "Can not allocate SKB buffers\n");
+                       if (net_ratelimit())
+                               IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n");
+                       if ((rxq->free_count <= RX_LOW_WATERMARK) &&
+                           net_ratelimit())
+                               IWL_CRIT(priv, "Failed to allocate SKB buffer with %s. Only %u free buffers remaining.\n",
+                                        priority == GFP_ATOMIC ?  "GFP_ATOMIC" : "GFP_KERNEL",
+                                        rxq->free_count);
                        /* We don't reschedule replenish work here -- we will
                         * call the restock method and if it still needs
                         * more buffers it will schedule replenish */
index a2b9ec8..c6633fe 100644 (file)
@@ -520,7 +520,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
        struct iwl_host_cmd cmd = {
                .id = REPLY_WEPKEY,
                .data = wep_cmd,
-               .flags = CMD_SYNC,
+               .flags = CMD_ASYNC,
        };
 
        memset(wep_cmd, 0, cmd_size +
index 0909668..4f2d439 100644 (file)
@@ -1146,11 +1146,18 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
                }
                spin_unlock_irqrestore(&rxq->lock, flags);
 
+               if (rxq->free_count > RX_LOW_WATERMARK)
+                       priority |= __GFP_NOWARN;
                /* Alloc a new receive buffer */
                skb = alloc_skb(priv->hw_params.rx_buf_size, priority);
                if (!skb) {
                        if (net_ratelimit())
-                               IWL_CRIT(priv, ": Can not allocate SKB buffers\n");
+                               IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n");
+                       if ((rxq->free_count <= RX_LOW_WATERMARK) &&
+                           net_ratelimit())
+                               IWL_CRIT(priv, "Failed to allocate SKB buffer with %s. Only %u free buffers remaining.\n",
+                                        priority == GFP_ATOMIC ?  "GFP_ATOMIC" : "GFP_KERNEL",
+                                        rxq->free_count);
                        /* We don't reschedule replenish work here -- we will
                         * call the restock method and if it still needs
                         * more buffers it will schedule replenish */
index 5462cb5..567f029 100644 (file)
@@ -380,7 +380,7 @@ static inline void rt2x00crypto_tx_insert_iv(struct sk_buff *skb,
 {
 }
 
-static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad,
+static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
                                             unsigned int header_length,
                                             struct rxdone_entry_desc *rxdesc)
 {
index 7b14d5b..88060e1 100644 (file)
@@ -1,5 +1,5 @@
 menuconfig WL12XX
-       boolean "TI wl12xx driver support"
+       tristate "TI wl12xx driver support"
        depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
        ---help---
          This will enable TI wl12xx driver support. The drivers make
index 3868884..23a6a6d 100644 (file)
@@ -1070,7 +1070,7 @@ static int eject_installer(struct usb_interface *intf)
 
        /* Find bulk out endpoint */
        endpoint = &iface_desc->endpoint[1].desc;
-       if ((endpoint->bEndpointAddress & USB_TYPE_MASK) == USB_DIR_OUT &&
+       if (usb_endpoint_dir_out(endpoint) &&
            usb_endpoint_xfer_bulk(endpoint)) {
                bulk_out_ep = endpoint->bEndpointAddress;
        } else {
index 0399011..71e10ca 100644 (file)
@@ -90,8 +90,8 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
                bss->dtim_period = tim_ie->dtim_period;
        }
 
-       /* set default value for buggy APs */
-       if (!elems->tim || bss->dtim_period == 0)
+       /* set default value for buggy AP/no TIM element */
+       if (bss->dtim_period == 0)
                bss->dtim_period = 1;
 
        bss->supp_rates_len = 0;
index d16cd9e..bf72527 100644 (file)
@@ -26,11 +26,11 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
 
        wdev->wext.connect.ie = wdev->wext.ie;
        wdev->wext.connect.ie_len = wdev->wext.ie_len;
-       wdev->wext.connect.privacy = wdev->wext.default_key != -1;
 
        if (wdev->wext.keys) {
                wdev->wext.keys->def = wdev->wext.default_key;
                wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key;
+               wdev->wext.connect.privacy = true;
        }
 
        if (!wdev->wext.connect.ssid_len)