mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-13 00:20:06 +00:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Conflicts: drivers/net/wireless/iwlwifi/iwl-rx.c
This commit is contained in:
commit
139d6065c8
@ -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 */
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
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));
|
||||
/* 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);
|
||||
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
|
||||
|
||||
/* Load the new settings */
|
||||
REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
|
||||
|
||||
} else {
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
|
||||
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* Ignore ah->ah_config.pcie_clock_req setting for
|
||||
* pre-AR9280 11n
|
||||
*/
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
|
||||
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
|
||||
|
||||
/* Load the new settings */
|
||||
REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
|
||||
}
|
||||
} 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);
|
||||
udelay(1000);
|
||||
|
||||
/* 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);
|
||||
/* 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_PCIE_SERDES, 0x1aaabe40);
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Load the new settings */
|
||||
REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
|
||||
|
||||
} else {
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
|
||||
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* Ignore ah->ah_config.pcie_clock_req setting for
|
||||
* pre-AR9280 11n
|
||||
*/
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
|
||||
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
|
||||
REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
|
||||
|
||||
/* Load the new settings */
|
||||
REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
|
||||
REG_WRITE(ah, AR_WA, val);
|
||||
}
|
||||
|
||||
udelay(1000);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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;
|
||||
|
@ -106,7 +106,7 @@
|
||||
#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);
|
||||
|
@ -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;
|
||||
|
@ -676,8 +676,9 @@
|
||||
#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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -34,35 +34,75 @@
|
||||
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);
|
||||
}
|
||||
|
||||
static void b43_led_update(struct b43_wldev *dev,
|
||||
struct b43_led *led)
|
||||
{
|
||||
bool radio_enabled;
|
||||
bool turn_on;
|
||||
|
||||
if (!led->wl)
|
||||
return;
|
||||
|
||||
radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable);
|
||||
|
||||
/* 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. */
|
||||
@ -70,21 +110,12 @@ 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_wldev *dev = led->dev;
|
||||
bool radio_enabled;
|
||||
struct b43_wl *wl = led->wl;
|
||||
|
||||
if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED))
|
||||
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);
|
||||
else
|
||||
b43_led_turn_on(dev, led->index, led->activelow);
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
behaviour = sprom[i] & B43_LED_BEHAVIOUR;
|
||||
activelow = !!(sprom[i] & B43_LED_ACTIVELOW);
|
||||
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;
|
||||
}
|
||||
b43_map_led(dev, i, behaviour, activelow);
|
||||
} 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 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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. */
|
||||
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);
|
||||
|
||||
*data = b43_read16(wl->current_dev, B43_MMIO_RNG);
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
202
drivers/net/wireless/b43/sdio.c
Normal file
202
drivers/net/wireless/b43/sdio.c
Normal file
@ -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);
|
||||
}
|
45
drivers/net/wireless/b43/sdio.h
Normal file
45
drivers/net/wireless/b43/sdio.h
Normal file
@ -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_ */
|
@ -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");
|
||||
|
@ -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)) {
|
||||
|
@ -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)) {
|
||||
|
@ -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 */
|
||||
|
@ -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 +
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user