From 5c630ce7e6cb144a29fd5a993363f4928fb4b890 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Thu, 3 Sep 2009 01:02:59 +0200 Subject: ar9170: added phy register initialisation from eeprom values This patch adds the initialisation of some PHY registers from the modal_header[] values in the EEPROM (see otus/hal/hpmain.c, line 333 ff.) Signed-off-by: Joerg Albert Acked-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/phy.c | 135 +++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index df86f70cd81..3ace58ab40c 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -396,6 +396,136 @@ static struct ar9170_phy_init ar5416_phy_init[] = { { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, } }; +/* + * look up a certain register in ar5416_phy_init[] and return the init. value + * for the band and bandwidth given. Return 0 if register address not found. + */ +static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz) +{ + unsigned int i; + for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { + if (ar5416_phy_init[i].reg != reg) + continue; + + if (is_2ghz) { + if (is_40mhz) + return ar5416_phy_init[i]._2ghz_40; + else + return ar5416_phy_init[i]._2ghz_20; + } else { + if (is_40mhz) + return ar5416_phy_init[i]._5ghz_40; + else + return ar5416_phy_init[i]._5ghz_20; + } + } + return 0; +} + +/* + * initialize some phy regs from eeprom values in modal_header[] + * acc. to band and bandwith + */ +static int ar9170_init_phy_from_eeprom(struct ar9170 *ar, + bool is_2ghz, bool is_40mhz) +{ + static const u8 xpd2pd[16] = { + 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2, + 0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2 + }; + u32 defval, newval; + /* pointer to the modal_header acc. to band */ + struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz]; + + ar9170_regwrite_begin(ar); + + /* ant common control (index 0) */ + newval = le32_to_cpu(m->antCtrlCommon); + ar9170_regwrite(0x1c5964, newval); + + /* ant control chain 0 (index 1) */ + newval = le32_to_cpu(m->antCtrlChain[0]); + ar9170_regwrite(0x1c5960, newval); + + /* ant control chain 2 (index 2) */ + newval = le32_to_cpu(m->antCtrlChain[1]); + ar9170_regwrite(0x1c7960, newval); + + /* SwSettle (index 3) */ + if (!is_40mhz) { + defval = ar9170_get_default_phy_reg_val(0x1c5844, + is_2ghz, is_40mhz); + newval = (defval & ~0x3f80) | + ((m->switchSettling & 0x7f) << 7); + ar9170_regwrite(0x1c5844, newval); + } + + /* adcDesired, pdaDesired (index 4) */ + defval = ar9170_get_default_phy_reg_val(0x1c5850, is_2ghz, is_40mhz); + newval = (defval & ~0xffff) | ((u8)m->pgaDesiredSize << 8) | + ((u8)m->adcDesiredSize); + ar9170_regwrite(0x1c5850, newval); + + /* TxEndToXpaOff, TxFrameToXpaOn (index 5) */ + defval = ar9170_get_default_phy_reg_val(0x1c5834, is_2ghz, is_40mhz); + newval = (m->txEndToXpaOff << 24) | (m->txEndToXpaOff << 16) | + (m->txFrameToXpaOn << 8) | m->txFrameToXpaOn; + ar9170_regwrite(0x1c5834, newval); + + /* TxEndToRxOn (index 6) */ + defval = ar9170_get_default_phy_reg_val(0x1c5828, is_2ghz, is_40mhz); + newval = (defval & ~0xff0000) | (m->txEndToRxOn << 16); + ar9170_regwrite(0x1c5828, newval); + + /* thresh62 (index 7) */ + defval = ar9170_get_default_phy_reg_val(0x1c8864, is_2ghz, is_40mhz); + newval = (defval & ~0x7f000) | (m->thresh62 << 12); + ar9170_regwrite(0x1c8864, newval); + + /* tx/rx attenuation chain 0 (index 8) */ + defval = ar9170_get_default_phy_reg_val(0x1c5848, is_2ghz, is_40mhz); + newval = (defval & ~0x3f000) | ((m->txRxAttenCh[0] & 0x3f) << 12); + ar9170_regwrite(0x1c5848, newval); + + /* tx/rx attenuation chain 2 (index 9) */ + defval = ar9170_get_default_phy_reg_val(0x1c7848, is_2ghz, is_40mhz); + newval = (defval & ~0x3f000) | ((m->txRxAttenCh[1] & 0x3f) << 12); + ar9170_regwrite(0x1c7848, newval); + + /* tx/rx margin chain 0 (index 10) */ + defval = ar9170_get_default_phy_reg_val(0x1c620c, is_2ghz, is_40mhz); + newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[0] & 0x3f) << 18); + /* bsw margin chain 0 for 5GHz only */ + if (!is_2ghz) + newval = (newval & ~0x3c00) | ((m->bswMargin[0] & 0xf) << 10); + ar9170_regwrite(0x1c620c, newval); + + /* tx/rx margin chain 2 (index 11) */ + defval = ar9170_get_default_phy_reg_val(0x1c820c, is_2ghz, is_40mhz); + newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[1] & 0x3f) << 18); + ar9170_regwrite(0x1c820c, newval); + + /* iqCall, iqCallq chain 0 (index 12) */ + defval = ar9170_get_default_phy_reg_val(0x1c5920, is_2ghz, is_40mhz); + newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[0] & 0x3f) << 5) | + ((u8)m->iqCalQCh[0] & 0x1f); + ar9170_regwrite(0x1c5920, newval); + + /* iqCall, iqCallq chain 2 (index 13) */ + defval = ar9170_get_default_phy_reg_val(0x1c7920, is_2ghz, is_40mhz); + newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[1] & 0x3f) << 5) | + ((u8)m->iqCalQCh[1] & 0x1f); + ar9170_regwrite(0x1c7920, newval); + + /* xpd gain mask (index 14) */ + defval = ar9170_get_default_phy_reg_val(0x1c6258, is_2ghz, is_40mhz); + newval = (defval & ~0xf0000) | (xpd2pd[m->xpdGain & 0xf] << 16); + ar9170_regwrite(0x1c6258, newval); + ar9170_regwrite_finish(); + + return ar9170_regwrite_result(); +} + int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) { int i, err; @@ -426,7 +556,10 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) if (err) return err; - /* XXX: use EEPROM data here! */ + /* TODO: (heavy clip) regulatory domain power level fine-tuning. */ + err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz); + if (err) + return err; err = ar9170_init_power_cal(ar); if (err) -- cgit v1.2.3 From db6be53cbaf118fdad5bdca211a19ca5354c9462 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 2 Sep 2009 16:34:57 -0700 Subject: ath9k: propagate ieee80211_alloc_hw() failure The -ENOMEM was never being passed on failure. While at it use dev_err() as ahb does upon failure. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 685a8cebb46..17862ccc340 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -160,8 +160,9 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + sizeof(struct ath_softc), &ath9k_ops); - if (hw == NULL) { - printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n"); + if (!hw) { + dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); + ret = -ENOMEM; goto bad2; } -- cgit v1.2.3 From 580171f7cd08687cdf1b263aabb35608b3c37433 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 2 Sep 2009 17:02:18 -0700 Subject: ath9k: propagate errors on ath_init_device() and request_irq() We've cleaned up ath_init_device() and its children enough to pass meaninful errors back from probe. When this fails it means our device could not be initialized and a meaninful error will have been passed. Do the same for request_irq() and also synchronize the error messages while at it. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 8 +++----- drivers/net/wireless/ath/ath9k/pci.c | 12 ++++++------ 2 files changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 5618fc25d52..7dc6301ae20 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -120,16 +120,14 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->irq = irq; ret = ath_init_device(AR5416_AR9100_DEVID, sc); - if (ret != 0) { - dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret); - ret = -ENODEV; + if (ret) { + dev_err(&pdev->dev, "failed to initialize device\n"); goto err_free_hw; } ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { - dev_err(&pdev->dev, "request_irq failed, err=%d\n", ret); - ret = -EIO; + dev_err(&pdev->dev, "request_irq failed\n"); goto err_detach; } diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 17862ccc340..bc4bc2c2d37 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -179,17 +179,17 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->mem = mem; sc->bus_ops = &ath_pci_bus_ops; - if (ath_init_device(id->device, sc) != 0) { - ret = -ENODEV; + ret = ath_init_device(id->device, sc); + if (ret) { + dev_err(&pdev->dev, "failed to initialize device\n"); goto bad3; } /* setup interrupt service routine */ - if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) { - printk(KERN_ERR "%s: request_irq failed\n", - wiphy_name(hw->wiphy)); - ret = -EIO; + ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc); + if (ret) { + dev_err(&pdev->dev, "request_irq failed\n"); goto bad4; } -- cgit v1.2.3 From fc548af877374f7e26c4f670f3843c6d29e02a98 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 2 Sep 2009 17:06:21 -0700 Subject: ath9k: claim irq for ath9k, not ath for pci ath9k ahb requests an IRQ and indicates 'ath9k' claimed it, ath9k pci requests an IRQ and indicates 'ath' claims it; since 'ath' is another module sync both ahb and pci to claim the irq using 'ath9k'. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index bc4bc2c2d37..8bb286df71b 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -187,7 +187,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* setup interrupt service routine */ - ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc); + ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); goto bad4; -- cgit v1.2.3 From 7ea310be65bfcbc6e2395844fd3498762dc2aea6 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 3 Sep 2009 12:08:43 +0530 Subject: ath9k: Fix RX Filter handling for BAR BAR frames have to be sent to mac80211 only if the current channel is HT. Also, move the macro to enum ath9k_rx_filter. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 3 ++- drivers/net/wireless/ath/ath9k/mac.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 2 +- drivers/net/wireless/ath/ath9k/recv.c | 3 +++ drivers/net/wireless/ath/ath9k/reg.h | 1 - 5 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 71f27f324ce..011b14f35e5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3967,7 +3967,8 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) { u32 phybits; - REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR); + REG_WRITE(ah, AR_RX_FILTER, bits); + phybits = 0; if (bits & ATH9K_RX_FILTER_PHYRADAR) phybits |= AR_PHY_ERR_RADAR; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 7b3982295a4..f56e77da6c3 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -568,6 +568,7 @@ enum ath9k_rx_filter { ATH9K_RX_FILTER_PROBEREQ = 0x00000080, ATH9K_RX_FILTER_PHYERR = 0x00000100, ATH9K_RX_FILTER_MYBEACON = 0x00000200, + ATH9K_RX_FILTER_COMP_BAR = 0x00000400, ATH9K_RX_FILTER_PSPOLL = 0x00004000, ATH9K_RX_FILTER_PHYRADAR = 0x00002000, ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c2efdf2d72d..b1d189c6be8 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2433,7 +2433,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, ath9k_hw_setrxfilter(sc->sc_ah, rfilt); ath9k_ps_restore(sc); - DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); + DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", rfilt); } static void ath9k_sta_notify(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 52e62daad3c..ec0abf82399 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -423,6 +423,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (sc->rx.rxfilter & FIF_PSPOLL) rfilt |= ATH9K_RX_FILTER_PSPOLL; + if (conf_is_ht(&sc->hw->conf)) + rfilt |= ATH9K_RX_FILTER_COMP_BAR; + if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) { /* TODO: only needed if more than one BSSID is in use in * station/adhoc mode */ diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 3ddb243f000..e5c29eb86e8 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1325,7 +1325,6 @@ enum { #define AR_CFP_VAL 0x0000FFFF #define AR_RX_FILTER 0x803C -#define AR_RX_COMPR_BAR 0x00000400 #define AR_MCAST_FIL0 0x8040 #define AR_MCAST_FIL1 0x8044 -- cgit v1.2.3 From 8813262ea79acf9daa0e03901bdfe93db4dc4ca5 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 3 Sep 2009 12:08:53 +0530 Subject: ath9k: Fix channelFlags for 2GHZ CHANNEL_G has to be set for 2GHZ channels since IS_CHAN_G() checks for this in channelFlags and not in chanmode. To make things messier, ath9k_hw_process_ini() checks for CHANNEL_G in chanmode and not in channelFlags. The supreme, brain-searing fix is to set the flag in both cases. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b1d189c6be8..a69fda8a910 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1879,7 +1879,7 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, if (chan->band == IEEE80211_BAND_2GHZ) { ichan->chanmode = CHANNEL_G; - ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; + ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; } else { ichan->chanmode = CHANNEL_A; ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; -- cgit v1.2.3 From d9c35a506ed7770301f705a9070e05f0c5fae4bd Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 3 Sep 2009 20:25:31 +0200 Subject: ar9170: implement frequency calibration for one-stage/openfw This patch ports some code from the vendor driver, which is supposed to upload the right calibration values for the chosen frequency. In theory, this should give a better range and throughput for all users with the open, or one-stage firmware. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/phy.c | 122 ++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index 3ace58ab40c..108ebfe21fc 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -1120,6 +1120,124 @@ static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2) #undef SHIFT } +static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array) +{ + int i; + + for (i = 0; i < 3; i++) + if (x <= x_array[i + 1]) + break; + + return ar9170_interpolate_u8(x, + x_array[i], + y_array[i], + x_array[i + 1], + y_array[i + 1]); +} + +static int ar9170_set_freq_cal_data(struct ar9170 *ar, + struct ieee80211_channel *channel) +{ + u8 *cal_freq_pier; + u8 vpds[2][AR5416_PD_GAIN_ICEPTS]; + u8 pwrs[2][AR5416_PD_GAIN_ICEPTS]; + int chain, idx, i; + u8 f; + + switch (channel->band) { + case IEEE80211_BAND_2GHZ: + f = channel->center_freq - 2300; + cal_freq_pier = ar->eeprom.cal_freq_pier_2G; + i = AR5416_NUM_2G_CAL_PIERS - 1; + break; + + case IEEE80211_BAND_5GHZ: + f = (channel->center_freq - 4800) / 5; + cal_freq_pier = ar->eeprom.cal_freq_pier_5G; + i = AR5416_NUM_5G_CAL_PIERS - 1; + break; + + default: + return -EINVAL; + break; + } + + for (; i >= 0; i--) { + if (cal_freq_pier[i] != 0xff) + break; + } + if (i < 0) + return -EINVAL; + + idx = ar9170_find_freq_idx(i, cal_freq_pier, f); + + ar9170_regwrite_begin(ar); + + for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) { + for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) { + struct ar9170_calibration_data_per_freq *cal_pier_data; + int j; + + switch (channel->band) { + case IEEE80211_BAND_2GHZ: + cal_pier_data = &ar->eeprom. + cal_pier_data_2G[chain][idx]; + break; + + case IEEE80211_BAND_5GHZ: + cal_pier_data = &ar->eeprom. + cal_pier_data_5G[chain][idx]; + break; + + default: + return -EINVAL; + } + + for (j = 0; j < 2; j++) { + vpds[j][i] = ar9170_interpolate_u8(f, + cal_freq_pier[idx], + cal_pier_data->vpd_pdg[j][i], + cal_freq_pier[idx + 1], + cal_pier_data[1].vpd_pdg[j][i]); + + pwrs[j][i] = ar9170_interpolate_u8(f, + cal_freq_pier[idx], + cal_pier_data->pwr_pdg[j][i], + cal_freq_pier[idx + 1], + cal_pier_data[1].pwr_pdg[j][i]) / 2; + } + } + + for (i = 0; i < 76; i++) { + u32 phy_data; + u8 tmp; + + if (i < 25) { + tmp = ar9170_interpolate_val(i, &pwrs[0][0], + &vpds[0][0]); + } else { + tmp = ar9170_interpolate_val(i - 12, + &pwrs[1][0], + &vpds[1][0]); + } + + phy_data |= tmp << ((i & 3) << 3); + if ((i & 3) == 3) { + ar9170_regwrite(0x1c6280 + chain * 0x1000 + + (i & ~3), phy_data); + phy_data = 0; + } + } + + for (i = 19; i < 32; i++) + ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2), + 0x0); + } + + ar9170_regwrite_finish(); + return ar9170_regwrite_result(); +} + static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) { struct ar9170_calibration_target_power_legacy *ctpl; @@ -1340,6 +1458,10 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, if (err) return err; + err = ar9170_set_freq_cal_data(ar, channel); + if (err) + return err; + err = ar9170_set_power_cal(ar, channel->center_freq, bw); if (err) return err; -- cgit v1.2.3 From 36dbd9548e92268127b0c31b0e121e63e9207108 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:51:29 +0200 Subject: b43: Use a threaded IRQ handler Use a threaded IRQ handler to allow locking the mutex and sleeping while executing an interrupt. This removes usage of the irq_lock spinlock, but introduces a new hardirq_lock, which is _only_ used for the PCI/SSB lowlevel hard-irq handler. Sleeping busses (SDIO) will use mutex instead. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 23 +-- drivers/net/wireless/b43/debugfs.c | 53 ++---- drivers/net/wireless/b43/debugfs.h | 3 +- drivers/net/wireless/b43/dma.c | 5 +- drivers/net/wireless/b43/main.c | 319 ++++++++++++++++++---------------- drivers/net/wireless/b43/phy_common.c | 1 - drivers/net/wireless/b43/phy_common.h | 3 +- drivers/net/wireless/b43/phy_g.c | 7 - drivers/net/wireless/b43/phy_g.h | 3 +- drivers/net/wireless/b43/pio.c | 5 +- drivers/net/wireless/b43/sysfs.c | 3 - 11 files changed, 204 insertions(+), 221 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index a1b3b731935..d63af926d05 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -616,6 +616,12 @@ struct b43_wl { /* Pointer to the ieee80211 hardware data structure */ struct ieee80211_hw *hw; + /* Global driver mutex. Every operation must run with this mutex locked. */ + struct mutex mutex; + /* Hard-IRQ spinlock. This lock protects things used in the hard-IRQ + * handler, only. This basically is just the IRQ mask register. */ + spinlock_t hardirq_lock; + /* The number of queues that were registered with the mac80211 subsystem * initially. This is a backup copy of hw->queues in case hw->queues has * to be dynamically lowered at runtime (Firmware does not support QoS). @@ -623,8 +629,6 @@ struct b43_wl { * from the mac80211 subsystem. */ u16 mac80211_initially_registered_queues; - struct mutex mutex; - spinlock_t irq_lock; /* 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. */ @@ -665,8 +669,7 @@ struct b43_wl { bool radiotap_enabled; bool radio_enabled; - /* The beacon we are currently using (AP or IBSS mode). - * This beacon stuff is protected by the irq_lock. */ + /* The beacon we are currently using (AP or IBSS mode). */ struct sk_buff *current_beacon; bool beacon0_uploaded; bool beacon1_uploaded; @@ -754,14 +757,6 @@ enum { smp_wmb(); \ } while (0) -/* XXX--- HOW LOCKING WORKS IN B43 ---XXX - * - * You should always acquire both, wl->mutex and wl->irq_lock unless: - * - You don't need to acquire wl->irq_lock, if the interface is stopped. - * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet - * and packet TX path (and _ONLY_ there.) - */ - /* Data structure for one wireless device (802.11 core) */ struct b43_wldev { struct ssb_device *dev; @@ -807,14 +802,12 @@ struct b43_wldev { u32 dma_reason[6]; /* The currently active generic-interrupt mask. */ u32 irq_mask; + /* Link Quality calculation context. */ struct b43_noise_calculation noisecalc; /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ int mac_suspended; - /* Interrupt Service Routine tasklet (bottom-half) */ - struct tasklet_struct isr_tasklet; - /* Periodic tasks */ struct delayed_work periodic_work; unsigned int periodic_state; diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 45e3d6af69f..bf23a3a863f 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -46,8 +46,6 @@ struct b43_debugfs_fops { struct file_operations fops; /* Offset of struct b43_dfs_file in struct b43_dfsentry */ size_t file_struct_offset; - /* Take wl->irq_lock before calling read/write? */ - bool take_irqlock; }; static inline @@ -372,14 +370,12 @@ static ssize_t txstat_read_file(struct b43_wldev *dev, { struct b43_txstatus_log *log = &dev->dfsentry->txstatlog; ssize_t count = 0; - unsigned long flags; int i, idx; struct b43_txstatus *stat; - spin_lock_irqsave(&log->lock, flags); if (log->end < 0) { fappend("Nothing transmitted, yet\n"); - goto out_unlock; + goto out; } fappend("b43 TX status reports:\n\n" "index | cookie | seq | phy_stat | frame_count | " @@ -409,13 +405,11 @@ static ssize_t txstat_read_file(struct b43_wldev *dev, break; i++; } -out_unlock: - spin_unlock_irqrestore(&log->lock, flags); +out: return count; } -/* wl->irq_lock is locked */ static int restart_write_file(struct b43_wldev *dev, const char *buf, size_t count) { @@ -556,12 +550,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, goto out_unlock; } memset(buf, 0, bufsize); - if (dfops->take_irqlock) { - spin_lock_irq(&dev->wl->irq_lock); - ret = dfops->read(dev, buf, bufsize); - spin_unlock_irq(&dev->wl->irq_lock); - } else - ret = dfops->read(dev, buf, bufsize); + ret = dfops->read(dev, buf, bufsize); if (ret <= 0) { free_pages((unsigned long)buf, buforder); err = ret; @@ -623,12 +612,7 @@ static ssize_t b43_debugfs_write(struct file *file, err = -EFAULT; goto out_freepage; } - if (dfops->take_irqlock) { - spin_lock_irq(&dev->wl->irq_lock); - err = dfops->write(dev, buf, count); - spin_unlock_irq(&dev->wl->irq_lock); - } else - err = dfops->write(dev, buf, count); + err = dfops->write(dev, buf, count); if (err) goto out_freepage; @@ -641,7 +625,7 @@ out_unlock: } -#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \ +#define B43_DEBUGFS_FOPS(name, _read, _write) \ static struct b43_debugfs_fops fops_##name = { \ .read = _read, \ .write = _write, \ @@ -652,20 +636,19 @@ out_unlock: }, \ .file_struct_offset = offsetof(struct b43_dfsentry, \ file_##name), \ - .take_irqlock = _take_irqlock, \ } -B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file, 1); -B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file, 1); -B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file, 1); -B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file, 1); -B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file, 1); -B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file, 1); -B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1); -B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1); -B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); -B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); -B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0); +B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file); +B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file); +B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file); +B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file); +B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file); +B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file); +B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file); +B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file); +B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL); +B43_DEBUGFS_FOPS(restart, NULL, restart_write_file); +B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL); bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) @@ -738,7 +721,6 @@ void b43_debugfs_add_device(struct b43_wldev *dev) return; } log->end = -1; - spin_lock_init(&log->lock); dev->dfsentry = e; @@ -822,7 +804,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev) kfree(e); } -/* Called with IRQs disabled. */ void b43_debugfs_log_txstat(struct b43_wldev *dev, const struct b43_txstatus *status) { @@ -834,14 +815,12 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev, if (!e) return; log = &e->txstatlog; - spin_lock(&log->lock); /* IRQs are already disabled. */ i = log->end + 1; if (i == B43_NR_LOGGED_TXSTATUS) i = 0; log->end = i; cur = &(log->log[i]); memcpy(cur, status, sizeof(*cur)); - spin_unlock(&log->lock); } void b43_debugfs_init(void) diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h index b9d4de4a979..e47b4b488b0 100644 --- a/drivers/net/wireless/b43/debugfs.h +++ b/drivers/net/wireless/b43/debugfs.h @@ -23,9 +23,10 @@ struct dentry; #define B43_NR_LOGGED_TXSTATUS 100 struct b43_txstatus_log { + /* This structure is protected by wl->mutex */ + struct b43_txstatus *log; int end; - spinlock_t lock; }; struct b43_dfs_file { diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 289aaf6dfe7..25ced8bdec8 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1387,7 +1387,6 @@ out_unlock: return err; } -/* Called with IRQs disabled. */ void b43_dma_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status) { @@ -1402,7 +1401,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, if (unlikely(!ring)) return; - spin_lock(&ring->lock); /* IRQs are already disabled. */ + spin_lock_irq(&ring->lock); B43_WARN_ON(!ring->tx); ops = ring->ops; @@ -1463,7 +1462,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, } } - spin_unlock(&ring->lock); + spin_unlock_irq(&ring->lock); } void b43_dma_get_tx_stats(struct b43_wldev *dev, diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ae05f667114..80b688441ff 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -291,7 +291,7 @@ static struct ieee80211_supported_band b43_band_2GHz = { static void b43_wireless_core_exit(struct b43_wldev *dev); static int b43_wireless_core_init(struct b43_wldev *dev); -static void b43_wireless_core_stop(struct b43_wldev *dev); +static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev); static int b43_wireless_core_start(struct b43_wldev *dev); static int b43_ratelimit(struct b43_wl *wl) @@ -685,16 +685,6 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev) b43_set_slot_time(dev, 20); } -/* Synchronize IRQ top- and bottom-half. - * IRQs must be masked before calling this. - * This must not be called with the irq_lock held. - */ -static void b43_synchronize_irq(struct b43_wldev *dev) -{ - synchronize_irq(dev->dev->irq); - tasklet_kill(&dev->isr_tasklet); -} - /* DummyTransmission function, as documented on * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission */ @@ -720,8 +710,7 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) buffer[0] = 0x000B846E; } - spin_lock_irq(&wl->irq_lock); - write_lock(&wl->tx_lock); + write_lock_irq(&wl->tx_lock); for (i = 0; i < 5; i++) b43_ram_write(dev, i * 4, buffer[i]); @@ -779,8 +768,7 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) b43_radio_write16(dev, 0x0051, 0x0037); - write_unlock(&wl->tx_lock); - spin_unlock_irq(&wl->irq_lock); + write_unlock_irq(&wl->tx_lock); } static void key_write(struct b43_wldev *dev, @@ -1620,6 +1608,27 @@ static void handle_irq_beacon(struct b43_wldev *dev) } } +static void b43_do_beacon_update_trigger_work(struct b43_wldev *dev) +{ + u32 old_irq_mask = dev->irq_mask; + + /* update beacon right away or defer to irq */ + handle_irq_beacon(dev); + if (old_irq_mask != dev->irq_mask) { + /* The handler updated the IRQ mask. */ + B43_WARN_ON(!dev->irq_mask); + if (b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)) { + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); + } else { + /* Device interrupts are currently disabled. That means + * we just ran the hardirq handler and scheduled the + * IRQ thread. The thread will write the IRQ mask when + * it finished, so there's nothing to do here. Writing + * the mask _here_ would incorrectly re-enable IRQs. */ + } + } +} + static void b43_beacon_update_trigger_work(struct work_struct *work) { struct b43_wl *wl = container_of(work, struct b43_wl, @@ -1629,19 +1638,22 @@ 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))) { - spin_lock_irq(&wl->irq_lock); - /* update beacon right away or defer to irq */ - handle_irq_beacon(dev); - /* The handler might have updated the IRQ mask. */ - b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); - mmiowb(); - spin_unlock_irq(&wl->irq_lock); + if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { + /* wl->mutex is enough. */ + b43_do_beacon_update_trigger_work(dev); + mmiowb(); + } else { + spin_lock_irq(&wl->hardirq_lock); + b43_do_beacon_update_trigger_work(dev); + mmiowb(); + spin_unlock_irq(&wl->hardirq_lock); + } } mutex_unlock(&wl->mutex); } /* Asynchronously update the packet templates in template RAM. - * Locking: Requires wl->irq_lock to be locked. */ + * Locking: Requires wl->mutex to be locked. */ static void b43_update_templates(struct b43_wl *wl) { struct sk_buff *beacon; @@ -1778,18 +1790,15 @@ out: B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK); } -/* Interrupt handler bottom-half */ -static void b43_interrupt_tasklet(struct b43_wldev *dev) +static void b43_do_interrupt_thread(struct b43_wldev *dev) { u32 reason; u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; u32 merged_dma_reason = 0; int i; - unsigned long flags; - - spin_lock_irqsave(&dev->wl->irq_lock, flags); - B43_WARN_ON(b43_status(dev) != B43_STAT_STARTED); + if (unlikely(b43_status(dev) != B43_STAT_STARTED)) + return; reason = dev->irq_reason; for (i = 0; i < ARRAY_SIZE(dma_reason); i++) { @@ -1822,8 +1831,6 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) dma_reason[2], dma_reason[3], dma_reason[4], dma_reason[5]); b43_controller_restart(dev, "DMA error"); - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); return; } if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) { @@ -1867,47 +1874,36 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) if (reason & B43_IRQ_TX_OK) handle_irq_transmit_status(dev); + /* Re-enable interrupts on the device by restoring the current interrupt mask. */ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); } -static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason) +/* Interrupt thread handler. Handles device interrupts in thread context. */ +static irqreturn_t b43_interrupt_thread_handler(int irq, void *dev_id) { - b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); + struct b43_wldev *dev = dev_id; - b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); - b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]); - b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); - b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); - b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); -/* Unused ring - b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); -*/ + mutex_lock(&dev->wl->mutex); + b43_do_interrupt_thread(dev); + mmiowb(); + mutex_unlock(&dev->wl->mutex); + + return IRQ_HANDLED; } -/* Interrupt handler top-half */ -static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) +static irqreturn_t b43_do_interrupt(struct b43_wldev *dev) { - irqreturn_t ret = IRQ_NONE; - struct b43_wldev *dev = dev_id; u32 reason; - B43_WARN_ON(!dev); + /* This code runs under wl->hardirq_lock, but _only_ on non-SDIO busses. + * On SDIO, this runs under wl->mutex. */ - spin_lock(&dev->wl->irq_lock); - - if (unlikely(b43_status(dev) < B43_STAT_STARTED)) { - /* This can only happen on shared IRQ lines. */ - goto out; - } reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) /* shared IRQ */ - goto out; - ret = IRQ_HANDLED; + return IRQ_NONE; reason &= dev->irq_mask; if (!reason) - goto out; + return IRQ_HANDLED; dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON) & 0x0001DC00; @@ -1924,15 +1920,38 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) & 0x0000DC00; */ - b43_interrupt_ack(dev, reason); - /* disable all IRQs. They are enabled again in the bottom half. */ + /* ACK the interrupt. */ + b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); + b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); + b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]); + b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); + b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); + b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); +/* Unused ring + b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); +*/ + + /* Disable IRQs on the device. The IRQ thread handler will re-enable them. */ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); - /* save the reason code and call our bottom half. */ + /* Save the reason bitmasks for the IRQ thread handler. */ dev->irq_reason = reason; - tasklet_schedule(&dev->isr_tasklet); -out: + + return IRQ_WAKE_THREAD; +} + +/* Interrupt handler top-half. This runs with interrupts disabled. */ +static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) +{ + struct b43_wldev *dev = dev_id; + irqreturn_t ret; + + if (unlikely(b43_status(dev) < B43_STAT_STARTED)) + return IRQ_NONE; + + spin_lock(&dev->wl->hardirq_lock); + ret = b43_do_interrupt(dev); mmiowb(); - spin_unlock(&dev->wl->irq_lock); + spin_unlock(&dev->wl->hardirq_lock); return ret; } @@ -3038,15 +3057,12 @@ 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; - unsigned long flags; - /* Don't take wl->mutex here, as it could deadlock with - * hwrng internal locking. It's not needed to take - * wl->mutex here, anyway. */ + /* 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. */ - spin_lock_irqsave(&wl->irq_lock, flags); *data = b43_read16(wl->current_dev, B43_MMIO_RNG); - spin_unlock_irqrestore(&wl->irq_lock, flags); return (sizeof(u16)); } @@ -3283,22 +3299,20 @@ static int b43_op_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev = wl->current_dev; - unsigned long flags; + struct b43_wldev *dev; int err = -ENODEV; - if (!dev) - goto out; - spin_lock_irqsave(&wl->irq_lock, flags); - if (likely(b43_status(dev) >= B43_STAT_STARTED)) { + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (dev && b43_status(dev) >= B43_STAT_STARTED) { if (b43_using_pio_transfers(dev)) b43_pio_get_tx_stats(dev, stats); else b43_dma_get_tx_stats(dev, stats); err = 0; } - spin_unlock_irqrestore(&wl->irq_lock, flags); -out: + mutex_unlock(&wl->mutex); + return err; } @@ -3306,11 +3320,10 @@ static int b43_op_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { struct b43_wl *wl = hw_to_b43_wl(hw); - unsigned long flags; - spin_lock_irqsave(&wl->irq_lock, flags); + mutex_lock(&wl->mutex); memcpy(stats, &wl->ieee_stats, sizeof(*stats)); - spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); return 0; } @@ -3322,7 +3335,6 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw) u64 tsf; mutex_lock(&wl->mutex); - spin_lock_irq(&wl->irq_lock); dev = wl->current_dev; if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) @@ -3330,7 +3342,6 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw) else tsf = 0; - spin_unlock_irq(&wl->irq_lock); mutex_unlock(&wl->mutex); return tsf; @@ -3342,13 +3353,11 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) struct b43_wldev *dev; mutex_lock(&wl->mutex); - spin_lock_irq(&wl->irq_lock); dev = wl->current_dev; if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) b43_tsf_write(dev, tsf); - spin_unlock_irq(&wl->irq_lock); mutex_unlock(&wl->mutex); } @@ -3434,7 +3443,7 @@ static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan) prev_status = b43_status(down_dev); /* Shutdown the currently running core. */ if (prev_status >= B43_STAT_STARTED) - b43_wireless_core_stop(down_dev); + down_dev = b43_wireless_core_stop(down_dev); if (prev_status >= B43_STAT_INITIALIZED) b43_wireless_core_exit(down_dev); @@ -3498,7 +3507,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) struct b43_wldev *dev; struct b43_phy *phy; struct ieee80211_conf *conf = &hw->conf; - unsigned long flags; int antenna; int err = 0; @@ -3529,13 +3537,11 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) /* Adjust the desired TX power level. */ if (conf->power_level != 0) { - spin_lock_irqsave(&wl->irq_lock, flags); if (conf->power_level != phy->desired_txpower) { phy->desired_txpower = conf->power_level; b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME | B43_TXPWR_IGNORE_TSSI); } - spin_unlock_irqrestore(&wl->irq_lock, flags); } /* Antennas for RX and management frame TX. */ @@ -3620,7 +3626,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; - unsigned long flags; mutex_lock(&wl->mutex); @@ -3630,7 +3635,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, B43_WARN_ON(wl->vif != vif); - spin_lock_irqsave(&wl->irq_lock, flags); if (changed & BSS_CHANGED_BSSID) { if (conf->bssid) memcpy(wl->bssid, conf->bssid, ETH_ALEN); @@ -3648,7 +3652,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BSSID) b43_write_mac_bssid_templates(dev); } - spin_unlock_irqrestore(&wl->irq_lock, flags); b43_mac_suspend(dev); @@ -3683,18 +3686,15 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, u8 algorithm; u8 index; int err; + unsigned long flags; static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ mutex_lock(&wl->mutex); - spin_lock_irq(&wl->irq_lock); - write_lock(&wl->tx_lock); - /* Why do we need all this locking here? - * mutex -> Every config operation must take it. - * irq_lock -> We modify the dev->key array, which is accessed - * in the IRQ handlers. + write_lock_irqsave(&wl->tx_lock, flags); + /* mutex -> Every config operation must take it. * tx_lock -> We modify the dev->key array, which is accessed * in the TX handler. */ @@ -3789,8 +3789,7 @@ out_unlock: sta ? sta->addr : bcast_addr); b43_dump_keymemory(dev); } - write_unlock(&wl->tx_lock); - spin_unlock_irq(&wl->irq_lock); + write_unlock_irqrestore(&wl->tx_lock, flags); mutex_unlock(&wl->mutex); return err; @@ -3801,15 +3800,15 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev = wl->current_dev; - unsigned long flags; + struct b43_wldev *dev; + mutex_lock(&wl->mutex); + dev = wl->current_dev; if (!dev) { *fflags = 0; - return; + goto out_unlock; } - spin_lock_irqsave(&wl->irq_lock, flags); *fflags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | @@ -3830,41 +3829,66 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw, if (changed && b43_status(dev) >= B43_STAT_INITIALIZED) b43_adjust_opmode(dev); - spin_unlock_irqrestore(&wl->irq_lock, flags); + +out_unlock: + mutex_unlock(&wl->mutex); } -/* Locking: wl->mutex */ -static void b43_wireless_core_stop(struct b43_wldev *dev) +/* Locking: wl->mutex + * Returns the current dev. This might be different from the passed in dev, + * because the core might be gone away while we unlocked the mutex. */ +static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; - unsigned long flags; + struct b43_wldev *orig_dev; - if (b43_status(dev) < B43_STAT_STARTED) - return; +redo: + if (!dev || b43_status(dev) < B43_STAT_STARTED) + return dev; - /* Disable and sync interrupts. We must do this before than - * setting the status to INITIALIZED, as the interrupt handler - * won't care about IRQs then. */ - spin_lock_irqsave(&wl->irq_lock, flags); - b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); - b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */ - spin_unlock_irqrestore(&wl->irq_lock, flags); - b43_synchronize_irq(dev); + /* Disable periodic work. Unlock to avoid deadlocks. */ + mutex_unlock(&wl->mutex); + cancel_delayed_work_sync(&dev->periodic_work); + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (!dev || b43_status(dev) < B43_STAT_STARTED) { + /* Whoops, aliens ate up the device while we were unlocked. */ + return dev; + } - write_lock_irqsave(&wl->tx_lock, flags); + /* Disable interrupts on the device. */ b43_set_status(dev, B43_STAT_INITIALIZED); - write_unlock_irqrestore(&wl->tx_lock, flags); - - b43_pio_stop(dev); + if (0 /*FIXME 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 */ + } else { + spin_lock_irq(&wl->hardirq_lock); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); + b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ + spin_unlock_irq(&wl->hardirq_lock); + } + /* Synchronize the interrupt handlers. Unlock to avoid deadlocks. */ + orig_dev = dev; mutex_unlock(&wl->mutex); - /* Must unlock as it would otherwise deadlock. No races here. - * Cancel the possibly running self-rearming periodic work. */ - cancel_delayed_work_sync(&dev->periodic_work); + synchronize_irq(dev->dev->irq); mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (!dev) + return dev; + if (dev != orig_dev) { + if (b43_status(dev) >= B43_STAT_STARTED) + goto redo; + return dev; + } + B43_WARN_ON(b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)); + b43_pio_stop(dev); b43_mac_suspend(dev); free_irq(dev->dev->irq, dev); b43dbg(wl, "Wireless interface stopped\n"); + + return dev; } /* Locking: wl->mutex */ @@ -3875,8 +3899,9 @@ 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_irq(dev->dev->irq, b43_interrupt_handler, - IRQF_SHARED, KBUILD_MODNAME, 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; @@ -4155,8 +4180,8 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) { u32 macctl; - B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED); - if (b43_status(dev) != B43_STAT_INITIALIZED) + B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED); + if (!dev || b43_status(dev) != B43_STAT_INITIALIZED) return; b43_set_status(dev, B43_STAT_UNINIT); @@ -4309,7 +4334,6 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; - unsigned long flags; int err = -EOPNOTSUPP; /* TODO: allow WDS/AP devices to coexist */ @@ -4333,12 +4357,10 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, wl->if_type = conf->type; memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); - spin_lock_irqsave(&wl->irq_lock, flags); b43_adjust_opmode(dev); b43_set_pretbtt(dev); b43_set_synth_pu_delay(dev, 0); b43_upload_card_macaddress(dev); - spin_unlock_irqrestore(&wl->irq_lock, flags); err = 0; out_mutex_unlock: @@ -4352,7 +4374,6 @@ static void b43_op_remove_interface(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; - unsigned long flags; b43dbg(wl, "Removing Interface type %d\n", conf->type); @@ -4364,11 +4385,9 @@ static void b43_op_remove_interface(struct ieee80211_hw *hw, wl->operating = 0; - spin_lock_irqsave(&wl->irq_lock, flags); b43_adjust_opmode(dev); memset(wl->mac_addr, 0, ETH_ALEN); b43_upload_card_macaddress(dev); - spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); } @@ -4428,10 +4447,15 @@ static void b43_op_stop(struct ieee80211_hw *hw) cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); - if (b43_status(dev) >= B43_STAT_STARTED) - b43_wireless_core_stop(dev); + if (b43_status(dev) >= B43_STAT_STARTED) { + dev = b43_wireless_core_stop(dev); + if (!dev) + goto out_unlock; + } b43_wireless_core_exit(dev); wl->radio_enabled = 0; + +out_unlock: mutex_unlock(&wl->mutex); cancel_work_sync(&(wl->txpower_adjust_work)); @@ -4441,11 +4465,10 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { struct b43_wl *wl = hw_to_b43_wl(hw); - unsigned long flags; - spin_lock_irqsave(&wl->irq_lock, flags); + mutex_lock(&wl->mutex); b43_update_templates(wl); - spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); return 0; } @@ -4526,8 +4549,13 @@ static void b43_chip_reset(struct work_struct *work) prev_status = b43_status(dev); /* Bring the device down... */ - if (prev_status >= B43_STAT_STARTED) - b43_wireless_core_stop(dev); + if (prev_status >= B43_STAT_STARTED) { + dev = b43_wireless_core_stop(dev); + if (!dev) { + err = -ENODEV; + goto out; + } + } if (prev_status >= B43_STAT_INITIALIZED) b43_wireless_core_exit(dev); @@ -4742,9 +4770,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) wldev->wl = wl; b43_set_status(wldev, B43_STAT_UNINIT); wldev->bad_frames_preempt = modparam_bad_frames_preempt; - tasklet_init(&wldev->isr_tasklet, - (void (*)(unsigned long))b43_interrupt_tasklet, - (unsigned long)wldev); INIT_LIST_HEAD(&wldev->list); err = b43_wireless_core_attach(wldev); @@ -4841,11 +4866,11 @@ static int b43_wireless_init(struct ssb_device *dev) /* Initialize struct b43_wl */ wl->hw = hw; - spin_lock_init(&wl->irq_lock); rwlock_init(&wl->tx_lock); spin_lock_init(&wl->leds_lock); spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); + spin_lock_init(&wl->hardirq_lock); INIT_LIST_HEAD(&wl->devlist); INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); @@ -4946,8 +4971,8 @@ static int b43_suspend(struct ssb_device *dev, pm_message_t state) wldev->suspend_in_progress = true; wldev->suspend_init_status = b43_status(wldev); if (wldev->suspend_init_status >= B43_STAT_STARTED) - b43_wireless_core_stop(wldev); - if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) + wldev = b43_wireless_core_stop(wldev); + if (wldev && wldev->suspend_init_status >= B43_STAT_INITIALIZED) b43_wireless_core_exit(wldev); mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 6e704becda6..75b26e175e8 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -347,7 +347,6 @@ void b43_phy_txpower_adjust_work(struct work_struct *work) mutex_unlock(&wl->mutex); } -/* Called with wl->irq_lock locked */ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags) { struct b43_phy *phy = &dev->phy; diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 28e384633c3..9edd4e8e0c8 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -131,7 +131,7 @@ enum b43_txpwr_result { * If the parameter "ignore_tssi" is true, the TSSI values should * be ignored and a recalculation of the power settings should be * done even if the TSSI values did not change. - * This callback is called with wl->irq_lock held and must not sleep. + * This function may sleep, but should not. * Must not be NULL. * @adjust_txpower: Write the previously calculated TX power settings * (from @recalc_txpower) to the hardware. @@ -379,7 +379,6 @@ void b43_software_rfkill(struct b43_wldev *dev, bool blocked); * * Compare the current TX power output to the desired power emission * and schedule an adjustment in case it mismatches. - * Requires wl->irq_lock locked. * * @flags: OR'ed enum b43_phy_txpower_check_flags flags. * See the docs below. diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 5afa4df0b02..382826a8da8 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2823,8 +2823,6 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) b43_mac_suspend(dev); - spin_lock_irq(&dev->wl->irq_lock); - /* Calculate the new attenuation values. */ bbatt = gphy->bbatt.att; bbatt += gphy->bbatt_delta; @@ -2864,11 +2862,6 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) gphy->rfatt.att = rfatt; gphy->bbatt.att = bbatt; - /* We drop the lock early, so we can sleep during hardware - * adjustment. Possible races with op_recalc_txpower are harmless, - * as we will be called once again in case we raced. */ - spin_unlock_irq(&dev->wl->irq_lock); - if (b43_debug(dev, B43_DBG_XMITPOWER)) b43dbg(dev->wl, "Adjusting TX power\n"); diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h index 718947fd41a..8569fdd4c6b 100644 --- a/drivers/net/wireless/b43/phy_g.h +++ b/drivers/net/wireless/b43/phy_g.h @@ -141,8 +141,7 @@ struct b43_phy_g { int tgt_idle_tssi; /* Current idle TSSI */ int cur_idle_tssi; - /* The current average TSSI. - * Needs irq_lock, as it's updated in the IRQ path. */ + /* The current average TSSI. */ u8 average_tssi; /* Current TX power level attenuation control values */ struct b43_bbatt bbatt; diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 3fd653c78b1..ce6f36eb88c 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -570,7 +570,6 @@ out_unlock: return err; } -/* Called with IRQs disabled. */ void b43_pio_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status) { @@ -584,7 +583,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, return; B43_WARN_ON(!pack); - spin_lock(&q->lock); /* IRQs are already disabled. */ + spin_lock_irq(&q->lock); info = IEEE80211_SKB_CB(pack->skb); @@ -604,7 +603,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, q->stopped = 0; } - spin_unlock(&q->lock); + spin_unlock_irq(&q->lock); } void b43_pio_get_tx_stats(struct b43_wldev *dev, diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c index 5adaa3692d7..f1ae4e05a32 100644 --- a/drivers/net/wireless/b43/sysfs.c +++ b/drivers/net/wireless/b43/sysfs.c @@ -94,7 +94,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, const char *buf, size_t count) { struct b43_wldev *wldev = dev_to_b43_wldev(dev); - unsigned long flags; int err; int mode; @@ -120,7 +119,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, } mutex_lock(&wldev->wl->mutex); - spin_lock_irqsave(&wldev->wl->irq_lock, flags); if (wldev->phy.ops->interf_mitigation) { err = wldev->phy.ops->interf_mitigation(wldev, mode); @@ -132,7 +130,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, err = -ENOSYS; mmiowb(); - spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); mutex_unlock(&wldev->wl->mutex); return err ? err : count; -- cgit v1.2.3 From f5d40eedb32aa9a0e226d468e1f89fb676824694 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:53:18 +0200 Subject: b43: Remove TX spinlock This removes the TX spinlock and defers TX to a workqueue to allow locking wl->mutex instead and to allow sleeping for register accesses. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 5 +++ drivers/net/wireless/b43/main.c | 75 +++++++++++++++++++++-------------------- 2 files changed, 43 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index d63af926d05..1cd470d6e2d 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -683,6 +683,11 @@ struct b43_wl { * This is scheduled when we determine that the actual TX output * power doesn't match what we want. */ struct work_struct txpower_adjust_work; + + /* Packet transmit work */ + struct work_struct tx_work; + /* Queue of packets to be transmitted. */ + struct sk_buff_head tx_queue; }; /* The type of the firmware file. */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 80b688441ff..fca2fe947d7 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -690,7 +690,6 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev) */ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) { - struct b43_wl *wl = dev->wl; struct b43_phy *phy = &dev->phy; unsigned int i, max_loop; u16 value; @@ -710,8 +709,6 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) buffer[0] = 0x000B846E; } - write_lock_irq(&wl->tx_lock); - for (i = 0; i < 5; i++) b43_ram_write(dev, i * 4, buffer[i]); @@ -767,8 +764,6 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) } if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) b43_radio_write16(dev, 0x0051, 0x0037); - - write_unlock_irq(&wl->tx_lock); } static void key_write(struct b43_wldev *dev, @@ -3098,42 +3093,49 @@ static int b43_rng_init(struct b43_wl *wl) return err; } -static int b43_op_tx(struct ieee80211_hw *hw, - struct sk_buff *skb) +static void b43_tx_work(struct work_struct *work) { - struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev = wl->current_dev; - unsigned long flags; - int err; + struct b43_wl *wl = container_of(work, struct b43_wl, tx_work); + struct b43_wldev *dev; + struct sk_buff *skb; + int err = 0; - if (unlikely(skb->len < 2 + 2 + 6)) { - /* Too short, this can't be a valid frame. */ - goto drop_packet; + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED)) { + mutex_unlock(&wl->mutex); + return; } - B43_WARN_ON(skb_shinfo(skb)->nr_frags); - if (unlikely(!dev)) - goto drop_packet; - /* Transmissions on seperate queues can run concurrently. */ - read_lock_irqsave(&wl->tx_lock, flags); + while (skb_queue_len(&wl->tx_queue)) { + skb = skb_dequeue(&wl->tx_queue); - err = -ENODEV; - if (likely(b43_status(dev) >= B43_STAT_STARTED)) { if (b43_using_pio_transfers(dev)) err = b43_pio_tx(dev, skb); else err = b43_dma_tx(dev, skb); + if (unlikely(err)) + dev_kfree_skb(skb); /* Drop it */ } - read_unlock_irqrestore(&wl->tx_lock, flags); + mutex_unlock(&wl->mutex); +} - if (unlikely(err)) - goto drop_packet; - return NETDEV_TX_OK; +static int b43_op_tx(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + + if (unlikely(skb->len < 2 + 2 + 6)) { + /* Too short, this can't be a valid frame. */ + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + B43_WARN_ON(skb_shinfo(skb)->nr_frags); + + skb_queue_tail(&wl->tx_queue, skb); + ieee80211_queue_work(wl->hw, &wl->tx_work); -drop_packet: - /* We can not transmit this packet. Drop it. */ - dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -3686,18 +3688,12 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, u8 algorithm; u8 index; int err; - unsigned long flags; static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ mutex_lock(&wl->mutex); - write_lock_irqsave(&wl->tx_lock, flags); - /* mutex -> Every config operation must take it. - * tx_lock -> We modify the dev->key array, which is accessed - * in the TX handler. - */ dev = wl->current_dev; err = -ENODEV; @@ -3789,7 +3785,6 @@ out_unlock: sta ? sta->addr : bcast_addr); b43_dump_keymemory(dev); } - write_unlock_irqrestore(&wl->tx_lock, flags); mutex_unlock(&wl->mutex); return err; @@ -3846,9 +3841,10 @@ redo: if (!dev || b43_status(dev) < B43_STAT_STARTED) return dev; - /* Disable periodic work. Unlock to avoid deadlocks. */ + /* Cancel work. Unlock to avoid deadlocks. */ mutex_unlock(&wl->mutex); cancel_delayed_work_sync(&dev->periodic_work); + cancel_work_sync(&wl->tx_work); mutex_lock(&wl->mutex); dev = wl->current_dev; if (!dev || b43_status(dev) < B43_STAT_STARTED) { @@ -3883,6 +3879,10 @@ redo: } B43_WARN_ON(b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)); + /* Drain the TX queue */ + while (skb_queue_len(&wl->tx_queue)) + dev_kfree_skb(skb_dequeue(&wl->tx_queue)); + b43_pio_stop(dev); b43_mac_suspend(dev); free_irq(dev->dev->irq, dev); @@ -4866,7 +4866,6 @@ static int b43_wireless_init(struct ssb_device *dev) /* Initialize struct b43_wl */ wl->hw = hw; - rwlock_init(&wl->tx_lock); spin_lock_init(&wl->leds_lock); spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); @@ -4874,6 +4873,8 @@ static int b43_wireless_init(struct ssb_device *dev) INIT_LIST_HEAD(&wl->devlist); INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); + INIT_WORK(&wl->tx_work, b43_tx_work); + skb_queue_head_init(&wl->tx_queue); ssb_set_devtypedata(dev, wl); b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n", -- cgit v1.2.3 From 637dae3f637eb7dab447e74362e0dfeded775c7c Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:55:00 +0200 Subject: b43: Remove DMA/PIO queue locks This removes the DMA/PIO queue locks. Locking is handled by wl->mutex now. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/dma.c | 30 +++++------------------------- drivers/net/wireless/b43/dma.h | 3 --- drivers/net/wireless/b43/pio.c | 38 ++++++++------------------------------ drivers/net/wireless/b43/pio.h | 2 -- 4 files changed, 13 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 25ced8bdec8..a467ee260a1 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -856,7 +856,6 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, } else B43_WARN_ON(1); } - spin_lock_init(&ring->lock); #ifdef CONFIG_B43_DEBUG ring->last_injected_overflow = jiffies; #endif @@ -1315,7 +1314,6 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) struct b43_dmaring *ring; struct ieee80211_hdr *hdr; int err = 0; - unsigned long flags; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); hdr = (struct ieee80211_hdr *)skb->data; @@ -1331,8 +1329,6 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) dev, skb_get_queue_mapping(skb)); } - spin_lock_irqsave(&ring->lock, flags); - B43_WARN_ON(!ring->tx); if (unlikely(ring->stopped)) { @@ -1343,7 +1339,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) if (b43_debug(dev, B43_DBG_DMAVERBOSE)) b43err(dev->wl, "Packet after queue stopped\n"); err = -ENOSPC; - goto out_unlock; + goto out; } if (unlikely(WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME))) { @@ -1351,7 +1347,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) * full, but queues not stopped. */ b43err(dev->wl, "DMA queue overflow\n"); err = -ENOSPC; - goto out_unlock; + goto out; } /* Assign the queue number to the ring (if not already done before) @@ -1365,11 +1361,11 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) * anymore and must not transmit it unencrypted. */ dev_kfree_skb_any(skb); err = 0; - goto out_unlock; + goto out; } if (unlikely(err)) { b43err(dev->wl, "DMA tx mapping failure\n"); - goto out_unlock; + goto out; } ring->nr_tx_packets++; if ((free_slots(ring) < TX_SLOTS_PER_FRAME) || @@ -1381,8 +1377,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); } } -out_unlock: - spin_unlock_irqrestore(&ring->lock, flags); +out: return err; } @@ -1401,8 +1396,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, if (unlikely(!ring)) return; - spin_lock_irq(&ring->lock); - B43_WARN_ON(!ring->tx); ops = ring->ops; while (1) { @@ -1461,8 +1454,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); } } - - spin_unlock_irq(&ring->lock); } void b43_dma_get_tx_stats(struct b43_wldev *dev, @@ -1470,17 +1461,14 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43_dmaring *ring; - unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { ring = select_ring_by_priority(dev, i); - spin_lock_irqsave(&ring->lock, flags); stats[i].len = ring->used_slots / TX_SLOTS_PER_FRAME; stats[i].limit = ring->nr_slots / TX_SLOTS_PER_FRAME; stats[i].count = ring->nr_tx_packets; - spin_unlock_irqrestore(&ring->lock, flags); } } @@ -1591,22 +1579,14 @@ void b43_dma_rx(struct b43_dmaring *ring) static void b43_dma_tx_suspend_ring(struct b43_dmaring *ring) { - unsigned long flags; - - spin_lock_irqsave(&ring->lock, flags); B43_WARN_ON(!ring->tx); ring->ops->tx_suspend(ring); - spin_unlock_irqrestore(&ring->lock, flags); } static void b43_dma_tx_resume_ring(struct b43_dmaring *ring) { - unsigned long flags; - - spin_lock_irqsave(&ring->lock, flags); B43_WARN_ON(!ring->tx); ring->ops->tx_resume(ring); - spin_unlock_irqrestore(&ring->lock, flags); } void b43_dma_tx_suspend(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index 05dde646d83..f0b0838fb5b 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -2,7 +2,6 @@ #define B43_DMA_H_ #include -#include #include "b43.h" @@ -244,8 +243,6 @@ struct b43_dmaring { /* The QOS priority assigned to this ring. Only used for TX rings. * This is the mac80211 "queue" value. */ u8 queue_prio; - /* Lock, only used for TX. */ - spinlock_t lock; struct b43_wldev *dev; #ifdef CONFIG_B43_DEBUG /* Maximum number of used slots. */ diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index ce6f36eb88c..4635baa9b99 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -144,7 +144,6 @@ static struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev, q = kzalloc(sizeof(*q), GFP_KERNEL); if (!q) return NULL; - spin_lock_init(&q->lock); q->dev = dev; q->rev = dev->dev->id.revision; q->mmio_base = index_to_pioqueue_base(dev, index) + @@ -179,7 +178,6 @@ static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev, q = kzalloc(sizeof(*q), GFP_KERNEL); if (!q) return NULL; - spin_lock_init(&q->lock); q->dev = dev; q->rev = dev->dev->id.revision; q->mmio_base = index_to_pioqueue_base(dev, index) + @@ -494,7 +492,6 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) { struct b43_pio_txqueue *q; struct ieee80211_hdr *hdr; - unsigned long flags; unsigned int hdrlen, total_len; int err = 0; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -512,20 +509,18 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); } - spin_lock_irqsave(&q->lock, flags); - hdrlen = b43_txhdr_size(dev); total_len = roundup(skb->len + hdrlen, 4); if (unlikely(total_len > q->buffer_size)) { err = -ENOBUFS; b43dbg(dev->wl, "PIO: TX packet longer than queue.\n"); - goto out_unlock; + goto out; } if (unlikely(q->free_packet_slots == 0)) { err = -ENOBUFS; b43warn(dev->wl, "PIO: TX packet overflow.\n"); - goto out_unlock; + goto out; } B43_WARN_ON(q->buffer_used > q->buffer_size); @@ -534,7 +529,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) err = -EBUSY; ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; - goto out_unlock; + goto out; } /* Assign the queue number to the ring (if not already done before) @@ -548,11 +543,11 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) * anymore and must not transmit it unencrypted. */ dev_kfree_skb_any(skb); err = 0; - goto out_unlock; + goto out; } if (unlikely(err)) { b43err(dev->wl, "PIO transmission failure\n"); - goto out_unlock; + goto out; } q->nr_tx_packets++; @@ -564,9 +559,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) q->stopped = 1; } -out_unlock: - spin_unlock_irqrestore(&q->lock, flags); - +out: return err; } @@ -583,8 +576,6 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, return; B43_WARN_ON(!pack); - spin_lock_irq(&q->lock); - info = IEEE80211_SKB_CB(pack->skb); b43_fill_txstatus_report(dev, info, status); @@ -602,8 +593,6 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, ieee80211_wake_queue(dev->wl->hw, q->queue_prio); q->stopped = 0; } - - spin_unlock_irq(&q->lock); } void b43_pio_get_tx_stats(struct b43_wldev *dev, @@ -611,17 +600,14 @@ void b43_pio_get_tx_stats(struct b43_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43_pio_txqueue *q; - unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { q = select_queue_by_priority(dev, i); - spin_lock_irqsave(&q->lock, flags); stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; stats[i].limit = B43_PIO_MAX_NR_TXPACKETS; stats[i].count = q->nr_tx_packets; - spin_unlock_irqrestore(&q->lock, flags); } } @@ -768,9 +754,9 @@ static void b43_pio_rx_work(struct work_struct *work) bool stop; do { - spin_lock_irq(&q->lock); + mutex_lock(&q->dev->wl->mutex); stop = (pio_rx_frame(q) == 0); - spin_unlock_irq(&q->lock); + mutex_unlock(&q->dev->wl->mutex); cond_resched(); if (stop) break; @@ -787,9 +773,6 @@ void b43_pio_rx(struct b43_pio_rxqueue *q) static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) { - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); if (q->rev >= 8) { b43_piotx_write32(q, B43_PIO8_TXCTL, b43_piotx_read32(q, B43_PIO8_TXCTL) @@ -799,14 +782,10 @@ static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) b43_piotx_read16(q, B43_PIO_TXCTL) | B43_PIO_TXCTL_SUSPREQ); } - spin_unlock_irqrestore(&q->lock, flags); } static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q) { - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); if (q->rev >= 8) { b43_piotx_write32(q, B43_PIO8_TXCTL, b43_piotx_read32(q, B43_PIO8_TXCTL) @@ -816,7 +795,6 @@ static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q) b43_piotx_read16(q, B43_PIO_TXCTL) & ~B43_PIO_TXCTL_SUSPREQ); } - spin_unlock_irqrestore(&q->lock, flags); } void b43_pio_tx_suspend(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index 6c174c91ca2..a976bbdd6f4 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -70,7 +70,6 @@ struct b43_pio_txpacket { struct b43_pio_txqueue { struct b43_wldev *dev; - spinlock_t lock; u16 mmio_base; /* The device queue buffer size in bytes. */ @@ -103,7 +102,6 @@ struct b43_pio_txqueue { struct b43_pio_rxqueue { struct b43_wldev *dev; - spinlock_t lock; u16 mmio_base; /* Work to reduce latency issues on RX. */ -- cgit v1.2.3 From 77ca07ffe1797a0f2f41aa4997c9a5ae433a0be8 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:56:19 +0200 Subject: b43: Remove PIO RX workqueue This removes the PIO RX work. It's not needed anymore, because we can sleep in the threaded interrupt handler. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 1 - drivers/net/wireless/b43/pio.c | 36 +++++++----------------------------- drivers/net/wireless/b43/pio.h | 4 ---- 3 files changed, 7 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index fca2fe947d7..23de3db4f6d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3883,7 +3883,6 @@ redo: while (skb_queue_len(&wl->tx_queue)) dev_kfree_skb(skb_dequeue(&wl->tx_queue)); - b43_pio_stop(dev); b43_mac_suspend(dev); free_irq(dev->dev->irq, dev); b43dbg(wl, "Wireless interface stopped\n"); diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 4635baa9b99..3498b68385e 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -32,9 +32,6 @@ #include -static void b43_pio_rx_work(struct work_struct *work); - - static u16 generate_cookie(struct b43_pio_txqueue *q, struct b43_pio_txpacket *pack) { @@ -182,7 +179,6 @@ static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev, q->rev = dev->dev->id.revision; q->mmio_base = index_to_pioqueue_base(dev, index) + pio_rxqueue_offset(dev); - INIT_WORK(&q->rx_work, b43_pio_rx_work); /* Enable Direct FIFO RX (PIO) on the engine. */ b43_dma_direct_fifo_rx(dev, index, 1); @@ -247,13 +243,6 @@ void b43_pio_free(struct b43_wldev *dev) destroy_queue_tx(pio, tx_queue_AC_BK); } -void b43_pio_stop(struct b43_wldev *dev) -{ - if (!b43_using_pio_transfers(dev)) - return; - cancel_work_sync(&dev->pio.rx_queue->rx_work); -} - int b43_pio_init(struct b43_wldev *dev) { struct b43_pio *pio = &dev->pio; @@ -745,30 +734,19 @@ rx_error: return 1; } -/* RX workqueue. We can sleep, yay! */ -static void b43_pio_rx_work(struct work_struct *work) +void b43_pio_rx(struct b43_pio_rxqueue *q) { - struct b43_pio_rxqueue *q = container_of(work, struct b43_pio_rxqueue, - rx_work); - unsigned int budget = 50; + unsigned int count = 0; bool stop; - do { - mutex_lock(&q->dev->wl->mutex); + while (1) { stop = (pio_rx_frame(q) == 0); - mutex_unlock(&q->dev->wl->mutex); - cond_resched(); if (stop) break; - } while (--budget); -} - -/* Called with IRQs disabled. */ -void b43_pio_rx(struct b43_pio_rxqueue *q) -{ - /* Due to latency issues we must run the RX path in - * a workqueue to be able to schedule between packets. */ - ieee80211_queue_work(q->dev->wl->hw, &q->rx_work); + cond_resched(); + if (WARN_ON_ONCE(++count > 10000)) + break; + } } static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index a976bbdd6f4..7dd649c9dda 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -104,9 +104,6 @@ struct b43_pio_rxqueue { struct b43_wldev *dev; u16 mmio_base; - /* Work to reduce latency issues on RX. */ - struct work_struct rx_work; - /* Shortcut to the 802.11 core revision. This is to * avoid horrible pointer dereferencing in the fastpaths. */ u8 rev; @@ -160,7 +157,6 @@ static inline void b43_piorx_write32(struct b43_pio_rxqueue *q, int b43_pio_init(struct b43_wldev *dev); -void b43_pio_stop(struct b43_wldev *dev); void b43_pio_free(struct b43_wldev *dev); int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb); -- cgit v1.2.3 From 69eddc8a37a33479205ac3a3d8575fad1466da90 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:57:26 +0200 Subject: b43: remove SHM spinlock This removes the SHM spinlock. SHM is protected by wl->mutex. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 2 -- drivers/net/wireless/b43/debugfs.c | 14 +++------- drivers/net/wireless/b43/main.c | 55 +++----------------------------------- drivers/net/wireless/b43/main.h | 4 --- 4 files changed, 8 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 1cd470d6e2d..09cfe68537b 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -635,8 +635,6 @@ struct b43_wl { rwlock_t tx_lock; /* Lock for LEDs access. */ spinlock_t leds_lock; - /* Lock for SHM access. */ - spinlock_t shm_lock; /* We can only have one operating interface (802.11 core) * at a time. General information about this interface follows. diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index bf23a3a863f..8f64943e3f6 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -125,7 +125,6 @@ static int shm16write__write_file(struct b43_wldev *dev, unsigned int routing, addr, mask, set; u16 val; int res; - unsigned long flags; res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", &routing, &addr, &mask, &set); @@ -142,15 +141,13 @@ static int shm16write__write_file(struct b43_wldev *dev, if ((mask > 0xFFFF) || (set > 0xFFFF)) return -E2BIG; - spin_lock_irqsave(&dev->wl->shm_lock, flags); if (mask == 0) val = 0; else - val = __b43_shm_read16(dev, routing, addr); + val = b43_shm_read16(dev, routing, addr); val &= mask; val |= set; - __b43_shm_write16(dev, routing, addr, val); - spin_unlock_irqrestore(&dev->wl->shm_lock, flags); + b43_shm_write16(dev, routing, addr, val); return 0; } @@ -204,7 +201,6 @@ static int shm32write__write_file(struct b43_wldev *dev, unsigned int routing, addr, mask, set; u32 val; int res; - unsigned long flags; res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", &routing, &addr, &mask, &set); @@ -221,15 +217,13 @@ static int shm32write__write_file(struct b43_wldev *dev, if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF)) return -E2BIG; - spin_lock_irqsave(&dev->wl->shm_lock, flags); if (mask == 0) val = 0; else - val = __b43_shm_read32(dev, routing, addr); + val = b43_shm_read32(dev, routing, addr); val &= mask; val |= set; - __b43_shm_write32(dev, routing, addr, val); - spin_unlock_irqrestore(&dev->wl->shm_lock, flags); + b43_shm_write32(dev, routing, addr, val); return 0; } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 23de3db4f6d..0a4d0b3eceb 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -390,7 +390,7 @@ static inline void b43_shm_control_word(struct b43_wldev *dev, b43_write32(dev, B43_MMIO_SHM_CONTROL, control); } -u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) +u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) { u32 ret; @@ -413,20 +413,7 @@ out: return ret; } -u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) -{ - struct b43_wl *wl = dev->wl; - unsigned long flags; - u32 ret; - - spin_lock_irqsave(&wl->shm_lock, flags); - ret = __b43_shm_read32(dev, routing, offset); - spin_unlock_irqrestore(&wl->shm_lock, flags); - - return ret; -} - -u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) +u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) { u16 ret; @@ -447,20 +434,7 @@ out: return ret; } -u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) -{ - struct b43_wl *wl = dev->wl; - unsigned long flags; - u16 ret; - - spin_lock_irqsave(&wl->shm_lock, flags); - ret = __b43_shm_read16(dev, routing, offset); - spin_unlock_irqrestore(&wl->shm_lock, flags); - - return ret; -} - -void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) +void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) { if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); @@ -480,17 +454,7 @@ void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value b43_write32(dev, B43_MMIO_SHM_DATA, value); } -void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) -{ - struct b43_wl *wl = dev->wl; - unsigned long flags; - - spin_lock_irqsave(&wl->shm_lock, flags); - __b43_shm_write32(dev, routing, offset, value); - spin_unlock_irqrestore(&wl->shm_lock, flags); -} - -void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) +void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) { if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); @@ -506,16 +470,6 @@ void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value b43_write16(dev, B43_MMIO_SHM_DATA, value); } -void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) -{ - struct b43_wl *wl = dev->wl; - unsigned long flags; - - spin_lock_irqsave(&wl->shm_lock, flags); - __b43_shm_write16(dev, routing, offset, value); - spin_unlock_irqrestore(&wl->shm_lock, flags); -} - /* Read HostFlags */ u64 b43_hf_read(struct b43_wldev *dev) { @@ -4866,7 +4820,6 @@ static int b43_wireless_init(struct ssb_device *dev) /* Initialize struct b43_wl */ wl->hw = hw; spin_lock_init(&wl->leds_lock); - spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); spin_lock_init(&wl->hardirq_lock); INIT_LIST_HEAD(&wl->devlist); diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 0406e06781d..40db03678d9 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -112,13 +112,9 @@ void b43_tsf_read(struct b43_wldev *dev, u64 * tsf); void b43_tsf_write(struct b43_wldev *dev, u64 tsf); u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); -u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); -u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); -void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); -void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); u64 b43_hf_read(struct b43_wldev *dev); void b43_hf_write(struct b43_wldev *dev, u64 value); -- cgit v1.2.3 From e6c463e3a3d067f5da2c79d5acdb2f626754cdb3 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 5 Sep 2009 11:18:47 +0200 Subject: ssb: Fail ssb modinit, if attach of the buses failed. SSB modinit should not succeed, if busattach failed. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 65a1ed951a1..8d16cb258cc 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -1358,8 +1358,10 @@ static int __init ssb_modinit(void) ssb_buses_lock(); err = ssb_attach_queued_buses(); ssb_buses_unlock(); - if (err) + if (err) { bus_unregister(&ssb_bustype); + goto out; + } err = b43_pci_ssb_bridge_init(); if (err) { @@ -1375,7 +1377,7 @@ static int __init ssb_modinit(void) /* don't fail SSB init because of this */ err = 0; } - +out: return err; } /* ssb must be initialized after PCI but before the ssb drivers. -- cgit v1.2.3 From 7f42c37aa676825fea329a7bec2fefe51033b3e9 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Sat, 5 Sep 2009 16:07:43 +0200 Subject: ath,ar9170: move CTL_ defines into regd.h The ar9170 driver needs the defines for conformance test limit groups and cannot include regd_common.h Signed-off-by: Joerg Albert Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.h | 6 ++++++ drivers/net/wireless/ath/regd_common.h | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 4d3c53674e5..c1dd857697a 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -22,6 +22,12 @@ #include "ath.h" +enum ctl_group { + CTL_FCC = 0x10, + CTL_MKK = 0x40, + CTL_ETSI = 0x30, +}; + #define NO_CTL 0xff #define SD_NO_CTL 0xE0 #define NO_CTL 0xff diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index ad6d938d3cf..9847af72208 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -154,12 +154,6 @@ enum EnumRd { DEBUG_REG_DMN = 0x01ff, }; -enum ctl_group { - CTL_FCC = 0x10, - CTL_MKK = 0x40, - CTL_ETSI = 0x30, -}; - /* Regpair to CTL band mapping */ static struct reg_dmn_pair_mapping regDomainPairs[] = { /* regpair, 5 GHz CTL, 2 GHz CTL */ -- cgit v1.2.3 From fea6734a0e444c31c99a1271154bb0281d7908d8 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Sat, 5 Sep 2009 16:07:47 +0200 Subject: ath,ar9170: implemented conformance test limit calc. for tx power apply the conformance test limits (CTL) stored in the eeprom upon the values calculated for the tx power (ar->power_*). This is based on the implementation in the vendor driver (hal/hpmain.c, line 3700 ff.) with one difference: If any ctl mode isn't found in the eeprom, we fall back to the "lower", legacy modes (5GHT20,11A or 2GHT20,11G,11B). Otus only did 5GHT20->11A. Currently CTL are applied for the FCC group only. Signed-off-by: Joerg Albert Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/phy.c | 165 +++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index 108ebfe21fc..b3e5cf3735b 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -556,7 +556,6 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) if (err) return err; - /* TODO: (heavy clip) regulatory domain power level fine-tuning. */ err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz); if (err) return err; @@ -1238,6 +1237,164 @@ static int ar9170_set_freq_cal_data(struct ar9170 *ar, return ar9170_regwrite_result(); } +static u8 ar9170_get_max_edge_power(struct ar9170 *ar, + struct ar9170_calctl_edges edges[], + u32 freq) +{ +/* TODO: move somewhere else */ +#define AR5416_MAX_RATE_POWER 63 + + int i; + u8 rc = AR5416_MAX_RATE_POWER; + u8 f; + if (freq < 3000) + f = freq - 2300; + else + f = (freq - 4800) / 5; + + for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { + if (edges[i].channel == 0xff) + break; + if (f == edges[i].channel) { + /* exact freq match */ + rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS; + break; + } + if (i > 0 && f < edges[i].channel) { + if (f > edges[i-1].channel && + edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { + /* lower channel has the inband flag set */ + rc = edges[i-1].power_flags & + ~AR9170_CALCTL_EDGE_FLAGS; + } + break; + } + } + + if (i == AR5416_NUM_BAND_EDGES) { + if (f > edges[i-1].channel && + edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { + /* lower channel has the inband flag set */ + rc = edges[i-1].power_flags & + ~AR9170_CALCTL_EDGE_FLAGS; + } + } + return rc; +} + +/* calculate the conformance test limits and apply them to ar->power* + * (derived from otus hal/hpmain.c, line 3706 ff.) + */ +static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) +{ + u8 ctl_grp; /* CTL group */ + u8 ctl_idx; /* CTL index */ + int i, j; + struct ctl_modes { + u8 ctl_mode; + u8 max_power; + u8 *pwr_cal_data; + int pwr_cal_len; + } *modes; + + /* order is relevant in the mode_list_*: we fall back to the + * lower indices if any mode is missed in the EEPROM. + */ + struct ctl_modes mode_list_2ghz[] = { + { CTL_11B, 0, ar->power_2G_cck, 4 }, + { CTL_11G, 0, ar->power_2G_ofdm, 4 }, + { CTL_2GHT20, 0, ar->power_2G_ht20, 8 }, + { CTL_2GHT40, 0, ar->power_2G_ht40, 8 }, + }; + struct ctl_modes mode_list_5ghz[] = { + { CTL_11A, 0, ar->power_5G_leg, 4 }, + { CTL_5GHT20, 0, ar->power_5G_ht20, 8 }, + { CTL_5GHT40, 0, ar->power_5G_ht40, 8 }, + }; + int nr_modes; + +#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n]) + + /* TODO: investigate the differences between OTUS' + * hpreg.c::zfHpGetRegulatoryDomain() and + * ath/regd.c::ath_regd_get_band_ctl() - + * e.g. for FCC3_WORLD the OTUS procedure + * always returns CTL_FCC, while the one in ath/ delivers + * CTL_ETSI for 2GHz and CTL_FCC for 5GHz. + */ + ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory, + ar->hw->conf.channel->band); + + /* ctl group not found - either invalid band (NO_CTL) or ww roaming */ + if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL) + ctl_grp = CTL_FCC; + + if (ctl_grp != CTL_FCC) + /* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */ + return; + + if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) { + modes = mode_list_2ghz; + nr_modes = ARRAY_SIZE(mode_list_2ghz); + } else { + modes = mode_list_5ghz; + nr_modes = ARRAY_SIZE(mode_list_5ghz); + } + + for (i = 0; i < nr_modes; i++) { + u8 c = ctl_grp | modes[i].ctl_mode; + for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++) + if (c == ar->eeprom.ctl_index[ctl_idx]) + break; + if (ctl_idx < AR5416_NUM_CTLS) { + int f_off = 0; + + /* adjust freq for 40MHz */ + if (modes[i].ctl_mode == CTL_2GHT40 || + modes[i].ctl_mode == CTL_5GHT40) { + if (bw == AR9170_BW_40_BELOW) + f_off = -10; + else + f_off = 10; + } + + modes[i].max_power = + ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1), + freq+f_off); + + /* TODO: check if the regulatory max. power is + * controlled by cfg80211 for DFS + * (hpmain applies it to max_power itself for DFS freq) + */ + + } else { + /* Workaround in otus driver, hpmain.c, line 3906: + * if no data for 5GHT20 are found, take the + * legacy 5G value. + * We extend this here to fallback from any other *HT or + * 11G, too. + */ + int k = i; + + modes[i].max_power = AR5416_MAX_RATE_POWER; + while (k-- > 0) { + if (modes[k].max_power != + AR5416_MAX_RATE_POWER) { + modes[i].max_power = modes[k].max_power; + break; + } + } + } + + /* apply max power to pwr_cal_data (ar->power_*) */ + for (j = 0; j < modes[i].pwr_cal_len; j++) { + modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j], + modes[i].max_power); + } + } +#undef EDGES +} + static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) { struct ar9170_calibration_target_power_legacy *ctpl; @@ -1340,6 +1497,12 @@ static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) ctph[idx + 1].power[n]); } + + /* calc. conformance test limits and apply to ar->power*[] */ + ar9170_calc_ctl(ar, freq, bw); + + /* TODO: (heavy clip) regulatory domain power level fine-tuning. */ + /* set ACK/CTS TX power */ ar9170_regwrite_begin(ar); -- cgit v1.2.3 From fd413da852991e96c555ad7253cc481bc133e221 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 6 Sep 2009 14:49:43 +0200 Subject: b43: PCMCIA is not experimental anymore PCMCIA support works well and is not experimental anymore. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 2af3b352232..83e38134acc 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -42,8 +42,8 @@ config B43_PCICORE_AUTOSELECT default y config B43_PCMCIA - bool "Broadcom 43xx PCMCIA device support (EXPERIMENTAL)" - depends on B43 && SSB_PCMCIAHOST_POSSIBLE && EXPERIMENTAL + bool "Broadcom 43xx PCMCIA device support" + depends on B43 && SSB_PCMCIAHOST_POSSIBLE select SSB_PCMCIAHOST ---help--- Broadcom 43xx PCMCIA device support. -- cgit v1.2.3 From 4789666e13fb0b2d45feb1b4a5119a1b997ec84c Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 6 Sep 2009 15:14:23 +0200 Subject: rt2x00: Hardcode TX ack timeout and consume time The calculated values for the ACK timeout and ACK consume time are different then the values as used by the Legacy drivers. After testing from James Ledwith it appeared that the calculated values caused a high amount of TX failures, and the values from the Legacy drivers were the most optimal to prevent TX failure due to excessive retries. The symptoms of this problem: - Rate control module always falls back to 1Mbs - Low throughput when bitrate was fixed Possible side-effects (not confirmed but highly likely) - Problems with DHCP - Broken connections due to lack of probe response This should fix at least: Kernel bugzilla reports: [13362], [13009], [9273] Fedora bugzilla reports: [443203] but possible some additional bugs as well. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 5 ++--- drivers/net/wireless/rt2x00/rt2500pci.c | 5 ++--- drivers/net/wireless/rt2x00/rt2500usb.c | 4 ---- drivers/net/wireless/rt2x00/rt2800usb.c | 3 +-- drivers/net/wireless/rt2x00/rt2x00.h | 3 --- drivers/net/wireless/rt2x00/rt2x00config.c | 11 ----------- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 8 files changed, 7 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 164df9347a2..798f625e38f 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -331,9 +331,8 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, preamble_mask = erp->short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); - rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, - erp->ack_consume_time); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, 0x1ff); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, 0x13a); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 4186582f277..2e872ac6982 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -337,9 +337,8 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, preamble_mask = erp->short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); - rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, - erp->ack_consume_time); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, 0x162); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, 0xa2); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index b04f59bab3b..22dd6d9e298 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -488,10 +488,6 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev, { u16 reg; - rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); - rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, erp->ack_timeout); - rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, !!erp->short_preamble); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 639dc6cc04b..a084077a1c6 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -580,8 +580,7 @@ static void rt2800usb_config_erp(struct rt2x00_dev *rt2x00dev, u32 reg; rt2x00usb_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); - rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, - DIV_ROUND_UP(erp->ack_timeout, erp->slot_time)); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20); rt2x00usb_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); rt2x00usb_register_read(rt2x00dev, AUTO_RSP_CFG, ®); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 555a777db6d..27bc6b7fbfd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -417,9 +417,6 @@ struct rt2x00lib_erp { int short_preamble; int cts_protection; - int ack_timeout; - int ack_consume_time; - u32 basic_rates; int slot_time; diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 3501788ab49..40a201e2e15 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -94,17 +94,6 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS; erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS; - erp.ack_timeout = PLCP + erp.difs + GET_DURATION(ACK_SIZE, 10); - erp.ack_consume_time = SIFS + PLCP + GET_DURATION(ACK_SIZE, 10); - - if (bss_conf->use_short_preamble) { - erp.ack_timeout += SHORT_PREAMBLE; - erp.ack_consume_time += SHORT_PREAMBLE; - } else { - erp.ack_timeout += PREAMBLE; - erp.ack_consume_time += PREAMBLE; - } - erp.basic_rates = bss_conf->basic_rates; erp.beacon_int = bss_conf->beacon_int; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index f4b4b86da4d..b20e3eac9d6 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -598,7 +598,7 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, u32 reg; rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 90e11726305..1cbd9b4a3ef 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -561,7 +561,7 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, u32 reg; rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); -- cgit v1.2.3 From b0544eb6019a33e836141156a8fbe74a9f8367b4 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 6 Sep 2009 15:42:45 +0200 Subject: b43: Really disable QoS, if requested Currently, when QoS-disable is requested, we would leave QoS enabled in firmware, but only queue frames on one queue. Change that and also tell firmware about disabled QoS, so it completely ignores all the QoS parameters. Also don't upload the parameters, if QoS is disabled. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 0a4d0b3eceb..d29323d5083 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3093,7 +3093,6 @@ static int b43_op_tx(struct ieee80211_hw *hw, return NETDEV_TX_OK; } -/* Locking: wl->irq_lock */ static void b43_qos_params_upload(struct b43_wldev *dev, const struct ieee80211_tx_queue_params *p, u16 shm_offset) @@ -3102,6 +3101,9 @@ static void b43_qos_params_upload(struct b43_wldev *dev, int bslots, tmp; unsigned int i; + if (!dev->qos_enabled) + return; + bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min; memset(¶ms, 0, sizeof(params)); @@ -3147,6 +3149,9 @@ static void b43_qos_upload_all(struct b43_wldev *dev) struct b43_qos_params *params; unsigned int i; + if (!dev->qos_enabled) + return; + BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != ARRAY_SIZE(wl->qos_params)); @@ -3206,6 +3211,16 @@ static void b43_qos_clear(struct b43_wl *wl) /* Initialize the core's QOS capabilities */ static void b43_qos_init(struct b43_wldev *dev) { + if (!dev->qos_enabled) { + /* Disable QOS support. */ + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_EDCF); + b43_write16(dev, B43_MMIO_IFSCTL, + b43_read16(dev, B43_MMIO_IFSCTL) + & ~B43_MMIO_IFSCTL_USE_EDCF); + b43dbg(dev->wl, "QoS disabled\n"); + return; + } + /* Upload the current QOS parameters. */ b43_qos_upload_all(dev); @@ -3214,6 +3229,7 @@ static void b43_qos_init(struct b43_wldev *dev) b43_write16(dev, B43_MMIO_IFSCTL, b43_read16(dev, B43_MMIO_IFSCTL) | B43_MMIO_IFSCTL_USE_EDCF); + b43dbg(dev->wl, "QoS enabled\n"); } static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, -- cgit v1.2.3 From cde1b55b43b71cabb1a94278a809bca21b9df791 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 6 Sep 2009 16:18:58 +0200 Subject: b43: Fix sparse warning in hw-tkip code This fixes a sparse warning in the hardware-TKIP code: drivers/net/wireless/b43/xmit.c:272:18: warning: incorrect type in assignment (different base types) drivers/net/wireless/b43/xmit.c:272:18: expected unsigned short [unsigned] [short] drivers/net/wireless/b43/xmit.c:272:18: got restricted unsigned short [usertype] The code should work correctly with and without this patch applied. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/xmit.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index e7075d2c775..14f541248b5 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -267,11 +267,11 @@ int b43_generate_txhdr(struct b43_wldev *dev, */ ieee80211_get_tkip_key(info->control.hw_key, skb_frag, IEEE80211_TKIP_P1_KEY, (u8*)phase1key); - /* phase1key is in host endian */ - for (i = 0; i < 5; i++) - phase1key[i] = cpu_to_le16(phase1key[i]); - - memcpy(txhdr->iv, phase1key, 10); + /* phase1key is in host endian. Copy to little-endian txhdr->iv. */ + for (i = 0; i < 5; i++) { + txhdr->iv[i * 2 + 0] = phase1key[i]; + txhdr->iv[i * 2 + 1] = phase1key[i] >> 8; + } /* iv16 */ memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3); } else { -- cgit v1.2.3 From 7b6840ab5f836a18c4ea98173f73c8d046930efb Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 7 Sep 2009 17:46:49 +0530 Subject: ath9k: Disable ASPM when btcoex is active Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 14 ++++++++++++++ drivers/net/wireless/ath/ath9k/hw.h | 5 +++++ drivers/net/wireless/ath/ath9k/main.c | 1 + 3 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 011b14f35e5..97a09dba76d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -16,6 +16,7 @@ #include #include +#include #include "ath9k.h" #include "initvals.h" @@ -4298,3 +4299,16 @@ void ath_gen_timer_isr(struct ath_hw *ah) timer->trigger(timer->arg); } } + +/* + * Primitive to disable ASPM + */ +void ath_pcie_aspm_disable(struct ath_softc *sc) +{ + struct pci_dev *pdev = to_pci_dev(sc->dev); + u8 aspm; + + pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm); + aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1); + pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); +} diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 5ca6ffa7091..a592f1a46ec 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -665,4 +665,9 @@ void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); void ath_gen_timer_isr(struct ath_hw *hw); u32 ath9k_hw_gettsf32(struct ath_hw *ah); +#define ATH_PCIE_CAP_LINK_CTRL 0x70 +#define ATH_PCIE_CAP_LINK_L0S 1 +#define ATH_PCIE_CAP_LINK_L1 2 + +void ath_pcie_aspm_disable(struct ath_softc *sc); #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a69fda8a910..ce011ab5e89 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2010,6 +2010,7 @@ static int ath9k_start(struct ieee80211_hw *hw) AR_STOMP_LOW_WLAN_WGHT); ath9k_hw_btcoex_enable(sc->sc_ah); + ath_pcie_aspm_disable(sc); if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) ath_btcoex_timer_resume(sc, &sc->btcoex_info); } -- cgit v1.2.3 From f020979d5d7c9816c071d0aedf60a889fa4fae40 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 7 Sep 2009 17:46:50 +0530 Subject: ath9k: Remove unnecessary casting to u8 in pci_read_config_byte() call Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 8bb286df71b..8b288141d4c 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -35,8 +35,7 @@ static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz) { u8 u8tmp; - pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, - (u8 *)&u8tmp); + pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp); *csz = (int)u8tmp; /* -- cgit v1.2.3 From 24ea602e183ca20a7577ebe253323d0e5d0f9847 Mon Sep 17 00:00:00 2001 From: Albert Herranz Date: Tue, 8 Sep 2009 19:30:12 +0200 Subject: ssb: Implement SDIO host bus support Add support for communicating with a Sonics Silicon Backplane through a SDIO interface, as found in the Nintendo Wii WLAN daughter card. The Nintendo Wii WLAN card includes a custom Broadcom 4318 chip with a SDIO host interface. Signed-off-by: Albert Herranz Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/Kconfig | 14 ++ drivers/ssb/Makefile | 1 + drivers/ssb/main.c | 58 ++++- drivers/ssb/scan.c | 11 + drivers/ssb/sdio.c | 610 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/ssb/ssb_private.h | 40 +++ 6 files changed, 733 insertions(+), 1 deletion(-) create mode 100644 drivers/ssb/sdio.c (limited to 'drivers') diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index 540a2948596..2d8cc455dbc 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -66,6 +66,20 @@ config SSB_PCMCIAHOST If unsure, say N +config SSB_SDIOHOST_POSSIBLE + bool + depends on SSB && (MMC = y || MMC = SSB) + default y + +config SSB_SDIOHOST + bool "Support for SSB on SDIO-bus host" + depends on SSB_SDIOHOST_POSSIBLE + help + Support for a Sonics Silicon Backplane on top + of a SDIO device. + + If unsure, say N + config SSB_SILENT bool "No SSB kernel messages" depends on SSB && EMBEDDED diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile index cfbb74f2982..656e58b9261 100644 --- a/drivers/ssb/Makefile +++ b/drivers/ssb/Makefile @@ -6,6 +6,7 @@ ssb-$(CONFIG_SSB_SPROM) += sprom.o # host support ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o +ssb-$(CONFIG_SSB_SDIOHOST) += sdio.o # built-in drivers ssb-y += driver_chipcommon.o diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 8d16cb258cc..579b114be41 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -88,6 +89,25 @@ found: } #endif /* CONFIG_SSB_PCMCIAHOST */ +#ifdef CONFIG_SSB_SDIOHOST +struct ssb_bus *ssb_sdio_func_to_bus(struct sdio_func *func) +{ + struct ssb_bus *bus; + + ssb_buses_lock(); + list_for_each_entry(bus, &buses, list) { + if (bus->bustype == SSB_BUSTYPE_SDIO && + bus->host_sdio == func) + goto found; + } + bus = NULL; +found: + ssb_buses_unlock(); + + return bus; +} +#endif /* CONFIG_SSB_SDIOHOST */ + int ssb_for_each_bus_call(unsigned long data, int (*func)(struct ssb_bus *bus, unsigned long data)) { @@ -467,6 +487,12 @@ static int ssb_devices_register(struct ssb_bus *bus) #ifdef CONFIG_SSB_PCMCIAHOST sdev->irq = bus->host_pcmcia->irq.AssignedIRQ; dev->parent = &bus->host_pcmcia->dev; +#endif + break; + case SSB_BUSTYPE_SDIO: +#ifdef CONFIG_SSB_SDIO + sdev->irq = bus->host_sdio->dev.irq; + dev->parent = &bus->host_sdio->dev; #endif break; case SSB_BUSTYPE_SSB: @@ -724,12 +750,18 @@ static int ssb_bus_register(struct ssb_bus *bus, err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); if (err) goto out; + + /* Init SDIO-host device (if any), before the scan */ + err = ssb_sdio_init(bus); + if (err) + goto err_disable_xtal; + ssb_buses_lock(); bus->busnumber = next_busnumber; /* Scan for devices (cores) */ err = ssb_bus_scan(bus, baseaddr); if (err) - goto err_disable_xtal; + goto err_sdio_exit; /* Init PCI-host device (if any) */ err = ssb_pci_init(bus); @@ -776,6 +808,8 @@ err_pci_exit: ssb_pci_exit(bus); err_unmap: ssb_iounmap(bus); +err_sdio_exit: + ssb_sdio_exit(bus); err_disable_xtal: ssb_buses_unlock(); ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); @@ -825,6 +859,28 @@ int ssb_bus_pcmciabus_register(struct ssb_bus *bus, EXPORT_SYMBOL(ssb_bus_pcmciabus_register); #endif /* CONFIG_SSB_PCMCIAHOST */ +#ifdef CONFIG_SSB_SDIOHOST +int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func, + unsigned int quirks) +{ + int err; + + bus->bustype = SSB_BUSTYPE_SDIO; + bus->host_sdio = func; + bus->ops = &ssb_sdio_ops; + bus->quirks = quirks; + + err = ssb_bus_register(bus, ssb_sdio_get_invariants, ~0); + if (!err) { + ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " + "SDIO device %s\n", sdio_func_id(func)); + } + + return err; +} +EXPORT_SYMBOL(ssb_bus_sdiobus_register); +#endif /* CONFIG_SSB_PCMCIAHOST */ + int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr, ssb_invariants_func_t get_invariants) diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c index 63ee5cfbefb..b74212d698c 100644 --- a/drivers/ssb/scan.c +++ b/drivers/ssb/scan.c @@ -175,6 +175,9 @@ static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx, } else ssb_pcmcia_switch_segment(bus, 0); break; + case SSB_BUSTYPE_SDIO: + offset += current_coreidx * SSB_CORE_SIZE; + return ssb_sdio_scan_read32(bus, offset); } return readl(bus->mmio + offset); } @@ -188,6 +191,8 @@ static int scan_switchcore(struct ssb_bus *bus, u8 coreidx) return ssb_pci_switch_coreidx(bus, coreidx); case SSB_BUSTYPE_PCMCIA: return ssb_pcmcia_switch_coreidx(bus, coreidx); + case SSB_BUSTYPE_SDIO: + return ssb_sdio_scan_switch_coreidx(bus, coreidx); } return 0; } @@ -206,6 +211,8 @@ void ssb_iounmap(struct ssb_bus *bus) SSB_BUG_ON(1); /* Can't reach this code. */ #endif break; + case SSB_BUSTYPE_SDIO: + break; } bus->mmio = NULL; bus->mapped_device = NULL; @@ -230,6 +237,10 @@ static void __iomem *ssb_ioremap(struct ssb_bus *bus, SSB_BUG_ON(1); /* Can't reach this code. */ #endif break; + case SSB_BUSTYPE_SDIO: + /* Nothing to ioremap in the SDIO case, just fake it */ + mmio = (void __iomem *)baseaddr; + break; } return mmio; diff --git a/drivers/ssb/sdio.c b/drivers/ssb/sdio.c new file mode 100644 index 00000000000..114051056b5 --- /dev/null +++ b/drivers/ssb/sdio.c @@ -0,0 +1,610 @@ +/* + * Sonics Silicon Backplane + * SDIO-Hostbus related functions + * + * Copyright 2009 Albert Herranz + * + * Based on drivers/ssb/pcmcia.c + * Copyright 2006 Johannes Berg + * Copyright 2007-2008 Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + * + */ + +#include +#include +#include +#include +#include + +#include "ssb_private.h" + +/* Define the following to 1 to enable a printk on each coreswitch. */ +#define SSB_VERBOSE_SDIOCORESWITCH_DEBUG 1 + + +/* Hardware invariants CIS tuples */ +#define SSB_SDIO_CIS 0x80 +#define SSB_SDIO_CIS_SROMREV 0x00 +#define SSB_SDIO_CIS_ID 0x01 +#define SSB_SDIO_CIS_BOARDREV 0x02 +#define SSB_SDIO_CIS_PA 0x03 +#define SSB_SDIO_CIS_PA_PA0B0_LO 0 +#define SSB_SDIO_CIS_PA_PA0B0_HI 1 +#define SSB_SDIO_CIS_PA_PA0B1_LO 2 +#define SSB_SDIO_CIS_PA_PA0B1_HI 3 +#define SSB_SDIO_CIS_PA_PA0B2_LO 4 +#define SSB_SDIO_CIS_PA_PA0B2_HI 5 +#define SSB_SDIO_CIS_PA_ITSSI 6 +#define SSB_SDIO_CIS_PA_MAXPOW 7 +#define SSB_SDIO_CIS_OEMNAME 0x04 +#define SSB_SDIO_CIS_CCODE 0x05 +#define SSB_SDIO_CIS_ANTENNA 0x06 +#define SSB_SDIO_CIS_ANTGAIN 0x07 +#define SSB_SDIO_CIS_BFLAGS 0x08 +#define SSB_SDIO_CIS_LEDS 0x09 + +#define CISTPL_FUNCE_LAN_NODE_ID 0x04 /* same as in PCMCIA */ + + +/* + * Function 1 miscellaneous registers. + * + * Definitions match src/include/sbsdio.h from the + * Android Open Source Project + * http://android.git.kernel.org/?p=platform/system/wlan/broadcom.git + * + */ +#define SBSDIO_FUNC1_SBADDRLOW 0x1000a /* SB Address window Low (b15) */ +#define SBSDIO_FUNC1_SBADDRMID 0x1000b /* SB Address window Mid (b23-b16) */ +#define SBSDIO_FUNC1_SBADDRHIGH 0x1000c /* SB Address window High (b24-b31) */ + +/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */ +#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid address bits in SBADDRLOW */ +#define SBSDIO_SBADDRMID_MASK 0xff /* Valid address bits in SBADDRMID */ +#define SBSDIO_SBADDRHIGH_MASK 0xff /* Valid address bits in SBADDRHIGH */ + +#define SBSDIO_SB_OFT_ADDR_MASK 0x7FFF /* sb offset addr is <= 15 bits, 32k */ + +/* REVISIT: this flag doesn't seem to matter */ +#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x8000 /* forces 32-bit SB access */ + + +/* + * Address map within the SDIO function address space (128K). + * + * Start End Description + * ------- ------- ------------------------------------------ + * 0x00000 0x0ffff selected backplane address window (64K) + * 0x10000 0x1ffff backplane control registers (max 64K) + * + * The current address window is configured by writing to registers + * SBADDRLOW, SBADDRMID and SBADDRHIGH. + * + * In order to access the contents of a 32-bit Silicon Backplane address + * the backplane address window must be first loaded with the highest + * 16 bits of the target address. Then, an access must be done to the + * SDIO function address space using the lower 15 bits of the address. + * Bit 15 of the address must be set when doing 32 bit accesses. + * + * 10987654321098765432109876543210 + * WWWWWWWWWWWWWWWWW SB Address Window + * OOOOOOOOOOOOOOOO Offset within SB Address Window + * a 32-bit access flag + */ + + +/* + * SSB I/O via SDIO. + * + * NOTE: SDIO address @addr is 17 bits long (SDIO address space is 128K). + */ + +static inline struct device *ssb_sdio_dev(struct ssb_bus *bus) +{ + return &bus->host_sdio->dev; +} + +/* host claimed */ +static int ssb_sdio_writeb(struct ssb_bus *bus, unsigned int addr, u8 val) +{ + int error = 0; + + sdio_writeb(bus->host_sdio, val, addr, &error); + if (unlikely(error)) { + dev_dbg(ssb_sdio_dev(bus), "%08X <- %02x, error %d\n", + addr, val, error); + } + + return error; +} + +#if 0 +static u8 ssb_sdio_readb(struct ssb_bus *bus, unsigned int addr) +{ + u8 val; + int error = 0; + + val = sdio_readb(bus->host_sdio, addr, &error); + if (unlikely(error)) { + dev_dbg(ssb_sdio_dev(bus), "%08X -> %02x, error %d\n", + addr, val, error); + } + + return val; +} +#endif + +/* host claimed */ +static int ssb_sdio_set_sbaddr_window(struct ssb_bus *bus, u32 address) +{ + int error; + + error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRLOW, + (address >> 8) & SBSDIO_SBADDRLOW_MASK); + if (error) + goto out; + error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRMID, + (address >> 16) & SBSDIO_SBADDRMID_MASK); + if (error) + goto out; + error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRHIGH, + (address >> 24) & SBSDIO_SBADDRHIGH_MASK); + if (error) + goto out; + bus->sdio_sbaddr = address; +out: + if (error) { + dev_dbg(ssb_sdio_dev(bus), "failed to set address window" + " to 0x%08x, error %d\n", address, error); + } + + return error; +} + +/* for enumeration use only */ +u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset) +{ + u32 val; + int error; + + sdio_claim_host(bus->host_sdio); + val = sdio_readl(bus->host_sdio, offset, &error); + sdio_release_host(bus->host_sdio); + if (unlikely(error)) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } + + return val; +} + +/* for enumeration use only */ +int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx) +{ + u32 sbaddr; + int error; + + sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; + sdio_claim_host(bus->host_sdio); + error = ssb_sdio_set_sbaddr_window(bus, sbaddr); + sdio_release_host(bus->host_sdio); + if (error) { + dev_err(ssb_sdio_dev(bus), "failed to switch to core %u," + " error %d\n", coreidx, error); + goto out; + } +out: + return error; +} + +/* host must be already claimed */ +int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev) +{ + u8 coreidx = dev->core_index; + u32 sbaddr; + int error = 0; + + sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; + if (unlikely(bus->sdio_sbaddr != sbaddr)) { +#if SSB_VERBOSE_SDIOCORESWITCH_DEBUG + dev_info(ssb_sdio_dev(bus), + "switching to %s core, index %d\n", + ssb_core_name(dev->id.coreid), coreidx); +#endif + error = ssb_sdio_set_sbaddr_window(bus, sbaddr); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "failed to switch to" + " core %u, error %d\n", coreidx, error); + goto out; + } + bus->mapped_device = dev; + } + +out: + return error; +} + +static u8 ssb_sdio_read8(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + u8 val = 0xff; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + val = sdio_readb(bus->host_sdio, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %02x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); + + return val; +} + +static u16 ssb_sdio_read16(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + u16 val = 0xffff; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + val = sdio_readw(bus->host_sdio, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %04x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); + + return val; +} + +static u32 ssb_sdio_read32(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + u32 val = 0xffffffff; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ + val = sdio_readl(bus->host_sdio, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); + + return val; +} + +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_sdio_block_read(struct ssb_device *dev, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + size_t saved_count = count; + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) { + error = -EIO; + memset(buffer, 0xff, count); + goto err_out; + } + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + + switch (reg_width) { + case sizeof(u8): { + error = sdio_readsb(bus->host_sdio, buffer, offset, count); + break; + } + case sizeof(u16): { + SSB_WARN_ON(count & 1); + error = sdio_readsb(bus->host_sdio, buffer, offset, count); + break; + } + case sizeof(u32): { + SSB_WARN_ON(count & 3); + offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ + error = sdio_readsb(bus->host_sdio, buffer, offset, count); + break; + } + default: + SSB_WARN_ON(1); + } + if (!error) + goto out; + +err_out: + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%u), error %d\n", + bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error); +out: + sdio_release_host(bus->host_sdio); +} +#endif /* CONFIG_SSB_BLOCKIO */ + +static void ssb_sdio_write8(struct ssb_device *dev, u16 offset, u8 val) +{ + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + sdio_writeb(bus->host_sdio, val, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %02x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); +} + +static void ssb_sdio_write16(struct ssb_device *dev, u16 offset, u16 val) +{ + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + sdio_writew(bus->host_sdio, val, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %04x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); +} + +static void ssb_sdio_write32(struct ssb_device *dev, u16 offset, u32 val) +{ + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ + sdio_writel(bus->host_sdio, val, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %08x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } + if (bus->quirks & SSB_QUIRK_SDIO_READ_AFTER_WRITE32) + sdio_readl(bus->host_sdio, 0, &error); +out: + sdio_release_host(bus->host_sdio); +} + +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_sdio_block_write(struct ssb_device *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + size_t saved_count = count; + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) { + error = -EIO; + memset((void *)buffer, 0xff, count); + goto err_out; + } + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + + switch (reg_width) { + case sizeof(u8): + error = sdio_writesb(bus->host_sdio, offset, + (void *)buffer, count); + break; + case sizeof(u16): + SSB_WARN_ON(count & 1); + error = sdio_writesb(bus->host_sdio, offset, + (void *)buffer, count); + break; + case sizeof(u32): + SSB_WARN_ON(count & 3); + offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ + error = sdio_writesb(bus->host_sdio, offset, + (void *)buffer, count); + break; + default: + SSB_WARN_ON(1); + } + if (!error) + goto out; + +err_out: + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%u), error %d\n", + bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error); +out: + sdio_release_host(bus->host_sdio); +} + +#endif /* CONFIG_SSB_BLOCKIO */ + +/* Not "static", as it's used in main.c */ +const struct ssb_bus_ops ssb_sdio_ops = { + .read8 = ssb_sdio_read8, + .read16 = ssb_sdio_read16, + .read32 = ssb_sdio_read32, + .write8 = ssb_sdio_write8, + .write16 = ssb_sdio_write16, + .write32 = ssb_sdio_write32, +#ifdef CONFIG_SSB_BLOCKIO + .block_read = ssb_sdio_block_read, + .block_write = ssb_sdio_block_write, +#endif +}; + +#define GOTO_ERROR_ON(condition, description) do { \ + if (unlikely(condition)) { \ + error_description = description; \ + goto error; \ + } \ + } while (0) + +int ssb_sdio_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv) +{ + struct ssb_sprom *sprom = &iv->sprom; + struct ssb_boardinfo *bi = &iv->boardinfo; + const char *error_description = "none"; + struct sdio_func_tuple *tuple; + void *mac; + + memset(sprom, 0xFF, sizeof(*sprom)); + sprom->boardflags_lo = 0; + sprom->boardflags_hi = 0; + + tuple = bus->host_sdio->tuples; + while (tuple) { + switch (tuple->code) { + case 0x22: /* extended function */ + switch (tuple->data[0]) { + case CISTPL_FUNCE_LAN_NODE_ID: + GOTO_ERROR_ON((tuple->size != 7) && + (tuple->data[1] != 6), + "mac tpl size"); + /* fetch the MAC address. */ + mac = tuple->data + 2; + memcpy(sprom->il0mac, mac, ETH_ALEN); + memcpy(sprom->et1mac, mac, ETH_ALEN); + break; + default: + break; + } + break; + case 0x80: /* vendor specific tuple */ + switch (tuple->data[0]) { + case SSB_SDIO_CIS_SROMREV: + GOTO_ERROR_ON(tuple->size != 2, + "sromrev tpl size"); + sprom->revision = tuple->data[1]; + break; + case SSB_SDIO_CIS_ID: + GOTO_ERROR_ON((tuple->size != 5) && + (tuple->size != 7), + "id tpl size"); + bi->vendor = tuple->data[1] | + (tuple->data[2]<<8); + break; + case SSB_SDIO_CIS_BOARDREV: + GOTO_ERROR_ON(tuple->size != 2, + "boardrev tpl size"); + sprom->board_rev = tuple->data[1]; + break; + case SSB_SDIO_CIS_PA: + GOTO_ERROR_ON((tuple->size != 9) && + (tuple->size != 10), + "pa tpl size"); + sprom->pa0b0 = tuple->data[1] | + ((u16)tuple->data[2] << 8); + sprom->pa0b1 = tuple->data[3] | + ((u16)tuple->data[4] << 8); + sprom->pa0b2 = tuple->data[5] | + ((u16)tuple->data[6] << 8); + sprom->itssi_a = tuple->data[7]; + sprom->itssi_bg = tuple->data[7]; + sprom->maxpwr_a = tuple->data[8]; + sprom->maxpwr_bg = tuple->data[8]; + break; + case SSB_SDIO_CIS_OEMNAME: + /* Not present */ + break; + case SSB_SDIO_CIS_CCODE: + GOTO_ERROR_ON(tuple->size != 2, + "ccode tpl size"); + sprom->country_code = tuple->data[1]; + break; + case SSB_SDIO_CIS_ANTENNA: + GOTO_ERROR_ON(tuple->size != 2, + "ant tpl size"); + sprom->ant_available_a = tuple->data[1]; + sprom->ant_available_bg = tuple->data[1]; + break; + case SSB_SDIO_CIS_ANTGAIN: + GOTO_ERROR_ON(tuple->size != 2, + "antg tpl size"); + sprom->antenna_gain.ghz24.a0 = tuple->data[1]; + sprom->antenna_gain.ghz24.a1 = tuple->data[1]; + sprom->antenna_gain.ghz24.a2 = tuple->data[1]; + sprom->antenna_gain.ghz24.a3 = tuple->data[1]; + sprom->antenna_gain.ghz5.a0 = tuple->data[1]; + sprom->antenna_gain.ghz5.a1 = tuple->data[1]; + sprom->antenna_gain.ghz5.a2 = tuple->data[1]; + sprom->antenna_gain.ghz5.a3 = tuple->data[1]; + break; + case SSB_SDIO_CIS_BFLAGS: + GOTO_ERROR_ON((tuple->size != 3) && + (tuple->size != 5), + "bfl tpl size"); + sprom->boardflags_lo = tuple->data[1] | + ((u16)tuple->data[2] << 8); + break; + case SSB_SDIO_CIS_LEDS: + GOTO_ERROR_ON(tuple->size != 5, + "leds tpl size"); + sprom->gpio0 = tuple->data[1]; + sprom->gpio1 = tuple->data[2]; + sprom->gpio2 = tuple->data[3]; + sprom->gpio3 = tuple->data[4]; + break; + default: + break; + } + break; + default: + break; + } + tuple = tuple->next; + } + + return 0; +error: + dev_err(ssb_sdio_dev(bus), "failed to fetch device invariants: %s\n", + error_description); + return -ENODEV; +} + +void ssb_sdio_exit(struct ssb_bus *bus) +{ + if (bus->bustype != SSB_BUSTYPE_SDIO) + return; + /* Nothing to do here. */ +} + +int ssb_sdio_init(struct ssb_bus *bus) +{ + if (bus->bustype != SSB_BUSTYPE_SDIO) + return 0; + + bus->sdio_sbaddr = ~0; + + return 0; +} diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 57fa482abb9..25433565dfd 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -114,6 +114,46 @@ static inline int ssb_pcmcia_init(struct ssb_bus *bus) } #endif /* CONFIG_SSB_PCMCIAHOST */ +/* sdio.c */ +#ifdef CONFIG_SSB_SDIOHOST +extern int ssb_sdio_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv); + +extern u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset); +extern int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev); +extern int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx); +extern int ssb_sdio_hardware_setup(struct ssb_bus *bus); +extern void ssb_sdio_exit(struct ssb_bus *bus); +extern int ssb_sdio_init(struct ssb_bus *bus); + +extern const struct ssb_bus_ops ssb_sdio_ops; +#else /* CONFIG_SSB_SDIOHOST */ +static inline u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset) +{ + return 0; +} +static inline int ssb_sdio_switch_core(struct ssb_bus *bus, + struct ssb_device *dev) +{ + return 0; +} +static inline int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx) +{ + return 0; +} +static inline int ssb_sdio_hardware_setup(struct ssb_bus *bus) +{ + return 0; +} +static inline void ssb_sdio_exit(struct ssb_bus *bus) +{ +} +static inline int ssb_sdio_init(struct ssb_bus *bus) +{ + return 0; +} +#endif /* CONFIG_SSB_SDIOHOST */ + /* scan.c */ extern const char *ssb_core_name(u16 coreid); -- cgit v1.2.3 From 98a1e2a9260d30ad691fbd1ed778a05e38fe655b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 8 Sep 2009 19:33:31 +0200 Subject: b44/b43/b43legacy: Fix switch warnings introduced by SSB-SDIO This fixes some gcc warnings for switch statements. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/b44.c | 10 ++++++++-- drivers/net/wireless/b43/main.c | 8 ++++++-- drivers/net/wireless/b43legacy/main.c | 8 ++++++-- 3 files changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 951735c9ec0..0189dcd36f3 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1303,10 +1303,13 @@ static void b44_chip_reset(struct b44 *bp, int reset_kind) & MDIO_CTRL_MAXF_MASK))); break; case SSB_BUSTYPE_PCI: - case SSB_BUSTYPE_PCMCIA: bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | (0x0d & MDIO_CTRL_MAXF_MASK))); break; + case SSB_BUSTYPE_PCMCIA: + case SSB_BUSTYPE_SDIO: + WARN_ON(1); /* A device with this bus does not exist. */ + break; } br32(bp, B44_MDIO_CTRL); @@ -1764,10 +1767,13 @@ static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *inf case SSB_BUSTYPE_PCI: strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info)); break; - case SSB_BUSTYPE_PCMCIA: case SSB_BUSTYPE_SSB: strlcpy(info->bus_info, "SSB", sizeof(info->bus_info)); break; + case SSB_BUSTYPE_PCMCIA: + case SSB_BUSTYPE_SDIO: + WARN_ON(1); /* A device with this bus does not exist. */ + break; } } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index d29323d5083..7a9a3fa5542 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4092,16 +4092,20 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) bus->pcicore.dev->id.revision <= 5) { /* IMCFGLO timeouts workaround. */ tmp = ssb_read32(dev->dev, SSB_IMCFGLO); - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; switch (bus->bustype) { case SSB_BUSTYPE_PCI: case SSB_BUSTYPE_PCMCIA: + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 0x32; break; case SSB_BUSTYPE_SSB: + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 0x53; break; + default: + break; } ssb_write32(dev->dev, SSB_IMCFGLO, tmp); } diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index b166a6f9f05..1d9223b3d4c 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3106,16 +3106,20 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev) bus->pcicore.dev->id.revision <= 5) { /* IMCFGLO timeouts workaround. */ tmp = ssb_read32(dev->dev, SSB_IMCFGLO); - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; switch (bus->bustype) { case SSB_BUSTYPE_PCI: case SSB_BUSTYPE_PCMCIA: + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 0x32; break; case SSB_BUSTYPE_SSB: + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 0x53; break; + default: + break; } ssb_write32(dev->dev, SSB_IMCFGLO, tmp); } -- cgit v1.2.3 From 4d8cd26849737e141ff0aa23fedacef4ea76ea4f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 8 Sep 2009 12:09:47 -0700 Subject: wireless: mark prism54 as deprecated and mark for removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The preferred module is p54pci which also supports FullMAC PCI / Cardbus devices. We schedule removal for 2.6.34. Reason to remove this is no one really is testing prism54 anymore, and while it works p54pci provides support for the same hardware. It should be noted I have been told some FullMAC devices may not have worked with the SoftMAC driver but to date we have yet to recieve a single bug report regarding this. If there are users out there please let us know! Cc: aquilaver@yahoo.com Cc: linux-kernel@vger.kernel.org Cc: Dan Williams Cc: Kai Engert Cc: Jean Tourrilhes Cc: Tim de Waal Cc: Roy Marples Cc: Alan Cox Cc: Christian Lamparter Cc: Björn Steinbrink Cc: Tim Gardner Cc: Larry Finger Cc: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 57 +++++++++++++------------------------------- 1 file changed, 16 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index a8871a84d87..ad89d23968d 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -275,51 +275,26 @@ config PCMCIA_WL3501 micro support for ethtool. config PRISM54 - tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus' + tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)' depends on PCI && EXPERIMENTAL && WLAN_80211 select WIRELESS_EXT select FW_LOADER ---help--- - Enable PCI and Cardbus support for the following chipset based cards: - - ISL3880 - Prism GT 802.11 b/g - ISL3877 - Prism Indigo 802.11 a - ISL3890 - Prism Duette 802.11 a/b/g - - For a complete list of supported cards visit . - Here is the latest confirmed list of supported cards: - - 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 (version 1) - Allnet ALL0271 PCI Card - Compex WL54G Cardbus Card - Corega CG-WLCB54GT Cardbus Card - D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650 - I-O Data WN-G54/CB Cardbus Card - Kobishi XG-300 aka Z-Com Cardbus Card - Netgear WG511 Cardbus Card - Ovislink WL-5400PCI PCI Card - Peabird WLG-PCI PCI Card - Sitecom WL-100i Cardbus Card - Sitecom WL-110i PCI Card - SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card - SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card - SMC2835W-V2 - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card - Z-Com XG-900 PCI Card - Zyxel G-100 Cardbus Card - - If you enable this you will need a firmware file as well. - You will need to copy this to /usr/lib/hotplug/firmware/isl3890. - You can get this non-GPL'd firmware file from the Prism54 project page: - - You will also need the /etc/hotplug/firmware.agent script from - a current hotplug package. - - Note: You need a motherboard with DMA support to use any of these cards - - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . - The module will be called prism54. + This enables support for FullMAC PCI/Cardbus prism54 devices. This + driver is now deprecated in favor for the SoftMAC driver, p54pci. + p54pci supports FullMAC PCI/Cardbus devices as well. For details on + the scheduled removal of this driver on the kernel see the feature + removal schedule: + + Documentation/feature-removal-schedule.txt + + For more information refer to the p54 wiki: + + http://wireless.kernel.org/en/users/Drivers/p54 + + Note: You need a motherboard with DMA support to use any of these cards + + When built as module you get the module prism54 config USB_ZD1201 tristate "USB ZD1201 based Wireless device support" -- cgit v1.2.3 From aeac355d23fb13a2082a8740ae7cf9408a71ec2c Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 9 Sep 2009 15:25:49 +0530 Subject: ath9k: Store subsystem id in struct hw_version This subsystem id will be used later to turn on the btcoex support. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 2 +- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 7 ++++--- drivers/net/wireless/ath/ath9k/pci.c | 4 +++- 5 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 7dc6301ae20..2ad7d0280f7 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -119,7 +119,7 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->bus_ops = &ath_ahb_bus_ops; sc->irq = irq; - ret = ath_init_device(AR5416_AR9100_DEVID, sc); + ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto err_free_hw; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 1c68a9da22d..1d59f10f68d 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -658,7 +658,7 @@ extern struct ieee80211_ops ath9k_ops; irqreturn_t ath_isr(int irq, void *dev); void ath_cleanup(struct ath_softc *sc); -int ath_init_device(u16 devid, struct ath_softc *sc); +int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid); void ath_detach(struct ath_softc *sc); const char *ath_mac_bb_name(u32 mac_bb_version); const char *ath_rf_name(u16 rf_version); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index a592f1a46ec..64ea547adef 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -390,6 +390,7 @@ struct ath9k_hw_version { u16 phyRev; u16 analog5GhzRev; u16 analog2GhzRev; + u16 subsysid; }; /* Generic TSF timer definitions */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ce011ab5e89..3dc7b5a13e6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1310,7 +1310,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, * to allow the separation between hardware specific * variables (now in ath_hw) and driver specific variables. */ -static int ath_init_softc(u16 devid, struct ath_softc *sc) +static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) { struct ath_hw *ah = NULL; int r = 0, i; @@ -1348,6 +1348,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) ah->ah_sc = sc; ah->hw_version.devid = devid; + ah->hw_version.subsysid = subsysid; sc->sc_ah = ah; r = ath9k_hw_init(ah); @@ -1577,7 +1578,7 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) } /* Device driver core initialization */ -int ath_init_device(u16 devid, struct ath_softc *sc) +int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid) { struct ieee80211_hw *hw = sc->hw; int error = 0, i; @@ -1585,7 +1586,7 @@ int ath_init_device(u16 devid, struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); - error = ath_init_softc(devid, sc); + error = ath_init_softc(devid, sc, subsysid); if (error != 0) return error; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 8b288141d4c..903dd8ad9d4 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -88,6 +88,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct ath_softc *sc; struct ieee80211_hw *hw; u8 csz; + u16 subsysid; u32 val; int ret = 0; struct ath_hw *ah; @@ -178,7 +179,8 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->mem = mem; sc->bus_ops = &ath_pci_bus_ops; - ret = ath_init_device(id->device, sc); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); + ret = ath_init_device(id->device, sc, subsysid); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto bad3; -- cgit v1.2.3 From fe12946e66575677879941a14f75b70ca2d2962a Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 9 Sep 2009 15:25:50 +0530 Subject: ath9k: Enable btcoex based on the subsystem id of the device Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.c | 23 +++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/btcoex.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 3 ++- drivers/net/wireless/ath/ath9k/hw.h | 4 ++++ 4 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index e8bfb01ee78..55f607b7699 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -19,6 +19,29 @@ static const struct ath_btcoex_config ath_bt_config = { 0, true, true, ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true }; +static const u16 ath_subsysid_tbl[] = { + AR9280_COEX2WIRE_SUBSYSID, + AT9285_COEX3WIRE_SA_SUBSYSID, + AT9285_COEX3WIRE_DA_SUBSYSID +}; + +/* + * Checks the subsystem id of the device to see if it + * supports btcoex + */ +bool ath_btcoex_supported(u16 subsysid) +{ + int i; + + if (!subsysid) + return false; + + for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++) + if (subsysid == ath_subsysid_tbl[i]) + return true; + + return false; +} /* * Detects if there is any priority bt traffic diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 45568196c59..f1baf66e2ec 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -79,6 +79,7 @@ struct ath_btcoex_info { struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/ }; +bool ath_btcoex_supported(u16 subsysid); int ath9k_hw_btcoex_init(struct ath_hw *ah); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 97a09dba76d..8d77817f67a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3690,7 +3690,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->num_antcfg_2ghz = ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); - if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) { + if (AR_SREV_9280_10_OR_LATER(ah) && + ath_btcoex_supported(ah->hw_version.subsysid)) { btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO; btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 64ea547adef..9106a0b537d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -45,6 +45,10 @@ #define AR5416_DEVID_AR9287_PCI 0x002D #define AR5416_DEVID_AR9287_PCIE 0x002E +#define AR9280_COEX2WIRE_SUBSYSID 0x309b +#define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa +#define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab + /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) #define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) -- cgit v1.2.3 From f42cc2c2909f24faa1381ae139067edeba8c796d Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 9 Sep 2009 15:25:51 +0530 Subject: ath9k: Get rid of the modparam btcoex_enable Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8d77817f67a..c39693ba06a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -21,10 +21,6 @@ #include "ath9k.h" #include "initvals.h" -static int btcoex_enable; -module_param(btcoex_enable, bool, 0); -MODULE_PARM_DESC(btcoex_enable, "Enable Bluetooth coexistence support"); - #define ATH9K_CLOCK_RATE_CCK 22 #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 -- cgit v1.2.3 From 8c8f9ba7051b017e44124666b41c1dc70333a77c Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 9 Sep 2009 15:25:52 +0530 Subject: ath9k: Initialize the priority gpio for BT coex 3-wire Oops, a stupid mistake in the original patch which adds coex 3-wire support. Bluetooth priority gpio needs to be gpio 7. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index f1baf66e2ec..297b027fd3c 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -19,6 +19,7 @@ #define ATH_WLANACTIVE_GPIO 5 #define ATH_BTACTIVE_GPIO 6 +#define ATH_BTPRIORITY_GPIO 7 #define ATH_BTCOEX_DEF_BT_PERIOD 45 #define ATH_BTCOEX_DEF_DUTY_CYCLE 55 diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c39693ba06a..b6c6cca0781 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3691,10 +3691,12 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO; btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; - if (AR_SREV_9285(ah)) + if (AR_SREV_9285(ah)) { btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_3WIRE; - else + btcoex_info->btpriority_gpio = ATH_BTPRIORITY_GPIO; + } else { btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_2WIRE; + } } else { btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_NONE; } -- cgit v1.2.3