diff options
52 files changed, 1673 insertions, 539 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 09e031c55887..ad522e3d3d86 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
@@ -6,6 +6,35 @@ be removed from this file. | |||
6 | 6 | ||
7 | --------------------------- | 7 | --------------------------- |
8 | 8 | ||
9 | What: PRISM54 | ||
10 | When: 2.6.34 | ||
11 | |||
12 | Why: prism54 FullMAC PCI / Cardbus devices used to be supported only by the | ||
13 | prism54 wireless driver. After Intersil stopped selling these | ||
14 | devices in preference for the newer more flexible SoftMAC devices | ||
15 | a SoftMAC device driver was required and prism54 did not support | ||
16 | them. The p54pci driver now exists and has been present in the kernel for | ||
17 | a while. This driver supports both SoftMAC devices and FullMAC devices. | ||
18 | The main difference between these devices was the amount of memory which | ||
19 | could be used for the firmware. The SoftMAC devices support a smaller | ||
20 | amount of memory. Because of this the SoftMAC firmware fits into FullMAC | ||
21 | devices's memory. p54pci supports not only PCI / Cardbus but also USB | ||
22 | and SPI. Since p54pci supports all devices prism54 supports | ||
23 | you will have a conflict. I'm not quite sure how distributions are | ||
24 | handling this conflict right now. prism54 was kept around due to | ||
25 | claims users may experience issues when using the SoftMAC driver. | ||
26 | Time has passed users have not reported issues. If you use prism54 | ||
27 | and for whatever reason you cannot use p54pci please let us know! | ||
28 | E-mail us at: linux-wireless@vger.kernel.org | ||
29 | |||
30 | For more information see the p54 wiki page: | ||
31 | |||
32 | http://wireless.kernel.org/en/users/Drivers/p54 | ||
33 | |||
34 | Who: Luis R. Rodriguez <lrodriguez@atheros.com> | ||
35 | |||
36 | --------------------------- | ||
37 | |||
9 | What: IRQF_SAMPLE_RANDOM | 38 | What: IRQF_SAMPLE_RANDOM |
10 | Check: IRQF_SAMPLE_RANDOM | 39 | Check: IRQF_SAMPLE_RANDOM |
11 | When: July 2009 | 40 | When: July 2009 |
diff --git a/MAINTAINERS b/MAINTAINERS index 0ab47e7fc2ec..6e2e12fd9ef8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -876,6 +876,7 @@ M: "Luis R. Rodriguez" <lrodriguez@atheros.com> | |||
876 | M: Bob Copeland <me@bobcopeland.com> | 876 | M: Bob Copeland <me@bobcopeland.com> |
877 | L: linux-wireless@vger.kernel.org | 877 | L: linux-wireless@vger.kernel.org |
878 | L: ath5k-devel@lists.ath5k.org | 878 | L: ath5k-devel@lists.ath5k.org |
879 | W: http://wireless.kernel.org/en/users/Drivers/ath5k | ||
879 | S: Maintained | 880 | S: Maintained |
880 | F: drivers/net/wireless/ath/ath5k/ | 881 | F: drivers/net/wireless/ath/ath5k/ |
881 | 882 | ||
@@ -887,6 +888,7 @@ M: Vasanthakumar Thiagarajan <vasanth@atheros.com> | |||
887 | M: Senthil Balasubramanian <senthilkumar@atheros.com> | 888 | M: Senthil Balasubramanian <senthilkumar@atheros.com> |
888 | L: linux-wireless@vger.kernel.org | 889 | L: linux-wireless@vger.kernel.org |
889 | L: ath9k-devel@lists.ath9k.org | 890 | L: ath9k-devel@lists.ath9k.org |
891 | W: http://wireless.kernel.org/en/users/Drivers/ath9k | ||
890 | S: Supported | 892 | S: Supported |
891 | F: drivers/net/wireless/ath/ath9k/ | 893 | F: drivers/net/wireless/ath/ath9k/ |
892 | 894 | ||
diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 951735c9ec0b..0189dcd36f31 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) | |||
1303 | & MDIO_CTRL_MAXF_MASK))); | 1303 | & MDIO_CTRL_MAXF_MASK))); |
1304 | break; | 1304 | break; |
1305 | case SSB_BUSTYPE_PCI: | 1305 | case SSB_BUSTYPE_PCI: |
1306 | case SSB_BUSTYPE_PCMCIA: | ||
1307 | bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | | 1306 | bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | |
1308 | (0x0d & MDIO_CTRL_MAXF_MASK))); | 1307 | (0x0d & MDIO_CTRL_MAXF_MASK))); |
1309 | break; | 1308 | break; |
1309 | case SSB_BUSTYPE_PCMCIA: | ||
1310 | case SSB_BUSTYPE_SDIO: | ||
1311 | WARN_ON(1); /* A device with this bus does not exist. */ | ||
1312 | break; | ||
1310 | } | 1313 | } |
1311 | 1314 | ||
1312 | br32(bp, B44_MDIO_CTRL); | 1315 | br32(bp, B44_MDIO_CTRL); |
@@ -1764,10 +1767,13 @@ static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *inf | |||
1764 | case SSB_BUSTYPE_PCI: | 1767 | case SSB_BUSTYPE_PCI: |
1765 | strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info)); | 1768 | strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info)); |
1766 | break; | 1769 | break; |
1767 | case SSB_BUSTYPE_PCMCIA: | ||
1768 | case SSB_BUSTYPE_SSB: | 1770 | case SSB_BUSTYPE_SSB: |
1769 | strlcpy(info->bus_info, "SSB", sizeof(info->bus_info)); | 1771 | strlcpy(info->bus_info, "SSB", sizeof(info->bus_info)); |
1770 | break; | 1772 | break; |
1773 | case SSB_BUSTYPE_PCMCIA: | ||
1774 | case SSB_BUSTYPE_SDIO: | ||
1775 | WARN_ON(1); /* A device with this bus does not exist. */ | ||
1776 | break; | ||
1771 | } | 1777 | } |
1772 | } | 1778 | } |
1773 | 1779 | ||
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index a8871a84d87e..ad89d23968df 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -275,51 +275,26 @@ config PCMCIA_WL3501 | |||
275 | micro support for ethtool. | 275 | micro support for ethtool. |
276 | 276 | ||
277 | config PRISM54 | 277 | config PRISM54 |
278 | tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus' | 278 | tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)' |
279 | depends on PCI && EXPERIMENTAL && WLAN_80211 | 279 | depends on PCI && EXPERIMENTAL && WLAN_80211 |
280 | select WIRELESS_EXT | 280 | select WIRELESS_EXT |
281 | select FW_LOADER | 281 | select FW_LOADER |
282 | ---help--- | 282 | ---help--- |
283 | Enable PCI and Cardbus support for the following chipset based cards: | 283 | This enables support for FullMAC PCI/Cardbus prism54 devices. This |
284 | 284 | driver is now deprecated in favor for the SoftMAC driver, p54pci. | |
285 | ISL3880 - Prism GT 802.11 b/g | 285 | p54pci supports FullMAC PCI/Cardbus devices as well. For details on |
286 | ISL3877 - Prism Indigo 802.11 a | 286 | the scheduled removal of this driver on the kernel see the feature |
287 | ISL3890 - Prism Duette 802.11 a/b/g | 287 | removal schedule: |
288 | 288 | ||
289 | For a complete list of supported cards visit <http://prism54.org>. | 289 | Documentation/feature-removal-schedule.txt |
290 | Here is the latest confirmed list of supported cards: | 290 | |
291 | 291 | For more information refer to the p54 wiki: | |
292 | 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 (version 1) | 292 | |
293 | Allnet ALL0271 PCI Card | 293 | http://wireless.kernel.org/en/users/Drivers/p54 |
294 | Compex WL54G Cardbus Card | 294 | |
295 | Corega CG-WLCB54GT Cardbus Card | 295 | Note: You need a motherboard with DMA support to use any of these cards |
296 | D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650 | 296 | |
297 | I-O Data WN-G54/CB Cardbus Card | 297 | When built as module you get the module prism54 |
298 | Kobishi XG-300 aka Z-Com Cardbus Card | ||
299 | Netgear WG511 Cardbus Card | ||
300 | Ovislink WL-5400PCI PCI Card | ||
301 | Peabird WLG-PCI PCI Card | ||
302 | Sitecom WL-100i Cardbus Card | ||
303 | Sitecom WL-110i PCI Card | ||
304 | SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card | ||
305 | SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card | ||
306 | SMC2835W-V2 - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card | ||
307 | Z-Com XG-900 PCI Card | ||
308 | Zyxel G-100 Cardbus Card | ||
309 | |||
310 | If you enable this you will need a firmware file as well. | ||
311 | You will need to copy this to /usr/lib/hotplug/firmware/isl3890. | ||
312 | You can get this non-GPL'd firmware file from the Prism54 project page: | ||
313 | <http://prism54.org> | ||
314 | You will also need the /etc/hotplug/firmware.agent script from | ||
315 | a current hotplug package. | ||
316 | |||
317 | Note: You need a motherboard with DMA support to use any of these cards | ||
318 | |||
319 | If you want to compile the driver as a module ( = code which can be | ||
320 | inserted in and removed from the running kernel whenever you want), | ||
321 | say M here and read <file:Documentation/kbuild/modules.txt>. | ||
322 | The module will be called prism54. | ||
323 | 298 | ||
324 | config USB_ZD1201 | 299 | config USB_ZD1201 |
325 | tristate "USB ZD1201 based Wireless device support" | 300 | tristate "USB ZD1201 based Wireless device support" |
diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index df86f70cd817..b3e5cf3735b0 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[] = { | |||
396 | { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, } | 396 | { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, } |
397 | }; | 397 | }; |
398 | 398 | ||
399 | /* | ||
400 | * look up a certain register in ar5416_phy_init[] and return the init. value | ||
401 | * for the band and bandwidth given. Return 0 if register address not found. | ||
402 | */ | ||
403 | static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz) | ||
404 | { | ||
405 | unsigned int i; | ||
406 | for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { | ||
407 | if (ar5416_phy_init[i].reg != reg) | ||
408 | continue; | ||
409 | |||
410 | if (is_2ghz) { | ||
411 | if (is_40mhz) | ||
412 | return ar5416_phy_init[i]._2ghz_40; | ||
413 | else | ||
414 | return ar5416_phy_init[i]._2ghz_20; | ||
415 | } else { | ||
416 | if (is_40mhz) | ||
417 | return ar5416_phy_init[i]._5ghz_40; | ||
418 | else | ||
419 | return ar5416_phy_init[i]._5ghz_20; | ||
420 | } | ||
421 | } | ||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * initialize some phy regs from eeprom values in modal_header[] | ||
427 | * acc. to band and bandwith | ||
428 | */ | ||
429 | static int ar9170_init_phy_from_eeprom(struct ar9170 *ar, | ||
430 | bool is_2ghz, bool is_40mhz) | ||
431 | { | ||
432 | static const u8 xpd2pd[16] = { | ||
433 | 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2, | ||
434 | 0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2 | ||
435 | }; | ||
436 | u32 defval, newval; | ||
437 | /* pointer to the modal_header acc. to band */ | ||
438 | struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz]; | ||
439 | |||
440 | ar9170_regwrite_begin(ar); | ||
441 | |||
442 | /* ant common control (index 0) */ | ||
443 | newval = le32_to_cpu(m->antCtrlCommon); | ||
444 | ar9170_regwrite(0x1c5964, newval); | ||
445 | |||
446 | /* ant control chain 0 (index 1) */ | ||
447 | newval = le32_to_cpu(m->antCtrlChain[0]); | ||
448 | ar9170_regwrite(0x1c5960, newval); | ||
449 | |||
450 | /* ant control chain 2 (index 2) */ | ||
451 | newval = le32_to_cpu(m->antCtrlChain[1]); | ||
452 | ar9170_regwrite(0x1c7960, newval); | ||
453 | |||
454 | /* SwSettle (index 3) */ | ||
455 | if (!is_40mhz) { | ||
456 | defval = ar9170_get_default_phy_reg_val(0x1c5844, | ||
457 | is_2ghz, is_40mhz); | ||
458 | newval = (defval & ~0x3f80) | | ||
459 | ((m->switchSettling & 0x7f) << 7); | ||
460 | ar9170_regwrite(0x1c5844, newval); | ||
461 | } | ||
462 | |||
463 | /* adcDesired, pdaDesired (index 4) */ | ||
464 | defval = ar9170_get_default_phy_reg_val(0x1c5850, is_2ghz, is_40mhz); | ||
465 | newval = (defval & ~0xffff) | ((u8)m->pgaDesiredSize << 8) | | ||
466 | ((u8)m->adcDesiredSize); | ||
467 | ar9170_regwrite(0x1c5850, newval); | ||
468 | |||
469 | /* TxEndToXpaOff, TxFrameToXpaOn (index 5) */ | ||
470 | defval = ar9170_get_default_phy_reg_val(0x1c5834, is_2ghz, is_40mhz); | ||
471 | newval = (m->txEndToXpaOff << 24) | (m->txEndToXpaOff << 16) | | ||
472 | (m->txFrameToXpaOn << 8) | m->txFrameToXpaOn; | ||
473 | ar9170_regwrite(0x1c5834, newval); | ||
474 | |||
475 | /* TxEndToRxOn (index 6) */ | ||
476 | defval = ar9170_get_default_phy_reg_val(0x1c5828, is_2ghz, is_40mhz); | ||
477 | newval = (defval & ~0xff0000) | (m->txEndToRxOn << 16); | ||
478 | ar9170_regwrite(0x1c5828, newval); | ||
479 | |||
480 | /* thresh62 (index 7) */ | ||
481 | defval = ar9170_get_default_phy_reg_val(0x1c8864, is_2ghz, is_40mhz); | ||
482 | newval = (defval & ~0x7f000) | (m->thresh62 << 12); | ||
483 | ar9170_regwrite(0x1c8864, newval); | ||
484 | |||
485 | /* tx/rx attenuation chain 0 (index 8) */ | ||
486 | defval = ar9170_get_default_phy_reg_val(0x1c5848, is_2ghz, is_40mhz); | ||
487 | newval = (defval & ~0x3f000) | ((m->txRxAttenCh[0] & 0x3f) << 12); | ||
488 | ar9170_regwrite(0x1c5848, newval); | ||
489 | |||
490 | /* tx/rx attenuation chain 2 (index 9) */ | ||
491 | defval = ar9170_get_default_phy_reg_val(0x1c7848, is_2ghz, is_40mhz); | ||
492 | newval = (defval & ~0x3f000) | ((m->txRxAttenCh[1] & 0x3f) << 12); | ||
493 | ar9170_regwrite(0x1c7848, newval); | ||
494 | |||
495 | /* tx/rx margin chain 0 (index 10) */ | ||
496 | defval = ar9170_get_default_phy_reg_val(0x1c620c, is_2ghz, is_40mhz); | ||
497 | newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[0] & 0x3f) << 18); | ||
498 | /* bsw margin chain 0 for 5GHz only */ | ||
499 | if (!is_2ghz) | ||
500 | newval = (newval & ~0x3c00) | ((m->bswMargin[0] & 0xf) << 10); | ||
501 | ar9170_regwrite(0x1c620c, newval); | ||
502 | |||
503 | /* tx/rx margin chain 2 (index 11) */ | ||
504 | defval = ar9170_get_default_phy_reg_val(0x1c820c, is_2ghz, is_40mhz); | ||
505 | newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[1] & 0x3f) << 18); | ||
506 | ar9170_regwrite(0x1c820c, newval); | ||
507 | |||
508 | /* iqCall, iqCallq chain 0 (index 12) */ | ||
509 | defval = ar9170_get_default_phy_reg_val(0x1c5920, is_2ghz, is_40mhz); | ||
510 | newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[0] & 0x3f) << 5) | | ||
511 | ((u8)m->iqCalQCh[0] & 0x1f); | ||
512 | ar9170_regwrite(0x1c5920, newval); | ||
513 | |||
514 | /* iqCall, iqCallq chain 2 (index 13) */ | ||
515 | defval = ar9170_get_default_phy_reg_val(0x1c7920, is_2ghz, is_40mhz); | ||
516 | newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[1] & 0x3f) << 5) | | ||
517 | ((u8)m->iqCalQCh[1] & 0x1f); | ||
518 | ar9170_regwrite(0x1c7920, newval); | ||
519 | |||
520 | /* xpd gain mask (index 14) */ | ||
521 | defval = ar9170_get_default_phy_reg_val(0x1c6258, is_2ghz, is_40mhz); | ||
522 | newval = (defval & ~0xf0000) | (xpd2pd[m->xpdGain & 0xf] << 16); | ||
523 | ar9170_regwrite(0x1c6258, newval); | ||
524 | ar9170_regwrite_finish(); | ||
525 | |||
526 | return ar9170_regwrite_result(); | ||
527 | } | ||
528 | |||
399 | int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) | 529 | int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) |
400 | { | 530 | { |
401 | int i, err; | 531 | int i, err; |
@@ -426,7 +556,9 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) | |||
426 | if (err) | 556 | if (err) |
427 | return err; | 557 | return err; |
428 | 558 | ||
429 | /* XXX: use EEPROM data here! */ | 559 | err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz); |
560 | if (err) | ||
561 | return err; | ||
430 | 562 | ||
431 | err = ar9170_init_power_cal(ar); | 563 | err = ar9170_init_power_cal(ar); |
432 | if (err) | 564 | if (err) |
@@ -987,6 +1119,282 @@ static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2) | |||
987 | #undef SHIFT | 1119 | #undef SHIFT |
988 | } | 1120 | } |
989 | 1121 | ||
1122 | static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array) | ||
1123 | { | ||
1124 | int i; | ||
1125 | |||
1126 | for (i = 0; i < 3; i++) | ||
1127 | if (x <= x_array[i + 1]) | ||
1128 | break; | ||
1129 | |||
1130 | return ar9170_interpolate_u8(x, | ||
1131 | x_array[i], | ||
1132 | y_array[i], | ||
1133 | x_array[i + 1], | ||
1134 | y_array[i + 1]); | ||
1135 | } | ||
1136 | |||
1137 | static int ar9170_set_freq_cal_data(struct ar9170 *ar, | ||
1138 | struct ieee80211_channel *channel) | ||
1139 | { | ||
1140 | u8 *cal_freq_pier; | ||
1141 | u8 vpds[2][AR5416_PD_GAIN_ICEPTS]; | ||
1142 | u8 pwrs[2][AR5416_PD_GAIN_ICEPTS]; | ||
1143 | int chain, idx, i; | ||
1144 | u8 f; | ||
1145 | |||
1146 | switch (channel->band) { | ||
1147 | case IEEE80211_BAND_2GHZ: | ||
1148 | f = channel->center_freq - 2300; | ||
1149 | cal_freq_pier = ar->eeprom.cal_freq_pier_2G; | ||
1150 | i = AR5416_NUM_2G_CAL_PIERS - 1; | ||
1151 | break; | ||
1152 | |||
1153 | case IEEE80211_BAND_5GHZ: | ||
1154 | f = (channel->center_freq - 4800) / 5; | ||
1155 | cal_freq_pier = ar->eeprom.cal_freq_pier_5G; | ||
1156 | i = AR5416_NUM_5G_CAL_PIERS - 1; | ||
1157 | break; | ||
1158 | |||
1159 | default: | ||
1160 | return -EINVAL; | ||
1161 | break; | ||
1162 | } | ||
1163 | |||
1164 | for (; i >= 0; i--) { | ||
1165 | if (cal_freq_pier[i] != 0xff) | ||
1166 | break; | ||
1167 | } | ||
1168 | if (i < 0) | ||
1169 | return -EINVAL; | ||
1170 | |||
1171 | idx = ar9170_find_freq_idx(i, cal_freq_pier, f); | ||
1172 | |||
1173 | ar9170_regwrite_begin(ar); | ||
1174 | |||
1175 | for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) { | ||
1176 | for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) { | ||
1177 | struct ar9170_calibration_data_per_freq *cal_pier_data; | ||
1178 | int j; | ||
1179 | |||
1180 | switch (channel->band) { | ||
1181 | case IEEE80211_BAND_2GHZ: | ||
1182 | cal_pier_data = &ar->eeprom. | ||
1183 | cal_pier_data_2G[chain][idx]; | ||
1184 | break; | ||
1185 | |||
1186 | case IEEE80211_BAND_5GHZ: | ||
1187 | cal_pier_data = &ar->eeprom. | ||
1188 | cal_pier_data_5G[chain][idx]; | ||
1189 | break; | ||
1190 | |||
1191 | default: | ||
1192 | return -EINVAL; | ||
1193 | } | ||
1194 | |||
1195 | for (j = 0; j < 2; j++) { | ||
1196 | vpds[j][i] = ar9170_interpolate_u8(f, | ||
1197 | cal_freq_pier[idx], | ||
1198 | cal_pier_data->vpd_pdg[j][i], | ||
1199 | cal_freq_pier[idx + 1], | ||
1200 | cal_pier_data[1].vpd_pdg[j][i]); | ||
1201 | |||
1202 | pwrs[j][i] = ar9170_interpolate_u8(f, | ||
1203 | cal_freq_pier[idx], | ||
1204 | cal_pier_data->pwr_pdg[j][i], | ||
1205 | cal_freq_pier[idx + 1], | ||
1206 | cal_pier_data[1].pwr_pdg[j][i]) / 2; | ||
1207 | } | ||
1208 | } | ||
1209 | |||
1210 | for (i = 0; i < 76; i++) { | ||
1211 | u32 phy_data; | ||
1212 | u8 tmp; | ||
1213 | |||
1214 | if (i < 25) { | ||
1215 | tmp = ar9170_interpolate_val(i, &pwrs[0][0], | ||
1216 | &vpds[0][0]); | ||
1217 | } else { | ||
1218 | tmp = ar9170_interpolate_val(i - 12, | ||
1219 | &pwrs[1][0], | ||
1220 | &vpds[1][0]); | ||
1221 | } | ||
1222 | |||
1223 | phy_data |= tmp << ((i & 3) << 3); | ||
1224 | if ((i & 3) == 3) { | ||
1225 | ar9170_regwrite(0x1c6280 + chain * 0x1000 + | ||
1226 | (i & ~3), phy_data); | ||
1227 | phy_data = 0; | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | for (i = 19; i < 32; i++) | ||
1232 | ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2), | ||
1233 | 0x0); | ||
1234 | } | ||
1235 | |||
1236 | ar9170_regwrite_finish(); | ||
1237 | return ar9170_regwrite_result(); | ||
1238 | } | ||
1239 | |||
1240 | static u8 ar9170_get_max_edge_power(struct ar9170 *ar, | ||
1241 | struct ar9170_calctl_edges edges[], | ||
1242 | u32 freq) | ||
1243 | { | ||
1244 | /* TODO: move somewhere else */ | ||
1245 | #define AR5416_MAX_RATE_POWER 63 | ||
1246 | |||
1247 | int i; | ||
1248 | u8 rc = AR5416_MAX_RATE_POWER; | ||
1249 | u8 f; | ||
1250 | if (freq < 3000) | ||
1251 | f = freq - 2300; | ||
1252 | else | ||
1253 | f = (freq - 4800) / 5; | ||
1254 | |||
1255 | for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { | ||
1256 | if (edges[i].channel == 0xff) | ||
1257 | break; | ||
1258 | if (f == edges[i].channel) { | ||
1259 | /* exact freq match */ | ||
1260 | rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS; | ||
1261 | break; | ||
1262 | } | ||
1263 | if (i > 0 && f < edges[i].channel) { | ||
1264 | if (f > edges[i-1].channel && | ||
1265 | edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { | ||
1266 | /* lower channel has the inband flag set */ | ||
1267 | rc = edges[i-1].power_flags & | ||
1268 | ~AR9170_CALCTL_EDGE_FLAGS; | ||
1269 | } | ||
1270 | break; | ||
1271 | } | ||
1272 | } | ||
1273 | |||
1274 | if (i == AR5416_NUM_BAND_EDGES) { | ||
1275 | if (f > edges[i-1].channel && | ||
1276 | edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { | ||
1277 | /* lower channel has the inband flag set */ | ||
1278 | rc = edges[i-1].power_flags & | ||
1279 | ~AR9170_CALCTL_EDGE_FLAGS; | ||
1280 | } | ||
1281 | } | ||
1282 | return rc; | ||
1283 | } | ||
1284 | |||
1285 | /* calculate the conformance test limits and apply them to ar->power* | ||
1286 | * (derived from otus hal/hpmain.c, line 3706 ff.) | ||
1287 | */ | ||
1288 | static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) | ||
1289 | { | ||
1290 | u8 ctl_grp; /* CTL group */ | ||
1291 | u8 ctl_idx; /* CTL index */ | ||
1292 | int i, j; | ||
1293 | struct ctl_modes { | ||
1294 | u8 ctl_mode; | ||
1295 | u8 max_power; | ||
1296 | u8 *pwr_cal_data; | ||
1297 | int pwr_cal_len; | ||
1298 | } *modes; | ||
1299 | |||
1300 | /* order is relevant in the mode_list_*: we fall back to the | ||
1301 | * lower indices if any mode is missed in the EEPROM. | ||
1302 | */ | ||
1303 | struct ctl_modes mode_list_2ghz[] = { | ||
1304 | { CTL_11B, 0, ar->power_2G_cck, 4 }, | ||
1305 | { CTL_11G, 0, ar->power_2G_ofdm, 4 }, | ||
1306 | { CTL_2GHT20, 0, ar->power_2G_ht20, 8 }, | ||
1307 | { CTL_2GHT40, 0, ar->power_2G_ht40, 8 }, | ||
1308 | }; | ||
1309 | struct ctl_modes mode_list_5ghz[] = { | ||
1310 | { CTL_11A, 0, ar->power_5G_leg, 4 }, | ||
1311 | { CTL_5GHT20, 0, ar->power_5G_ht20, 8 }, | ||
1312 | { CTL_5GHT40, 0, ar->power_5G_ht40, 8 }, | ||
1313 | }; | ||
1314 | int nr_modes; | ||
1315 | |||
1316 | #define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n]) | ||
1317 | |||
1318 | /* TODO: investigate the differences between OTUS' | ||
1319 | * hpreg.c::zfHpGetRegulatoryDomain() and | ||
1320 | * ath/regd.c::ath_regd_get_band_ctl() - | ||
1321 | * e.g. for FCC3_WORLD the OTUS procedure | ||
1322 | * always returns CTL_FCC, while the one in ath/ delivers | ||
1323 | * CTL_ETSI for 2GHz and CTL_FCC for 5GHz. | ||
1324 | */ | ||
1325 | ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory, | ||
1326 | ar->hw->conf.channel->band); | ||
1327 | |||
1328 | /* ctl group not found - either invalid band (NO_CTL) or ww roaming */ | ||
1329 | if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL) | ||
1330 | ctl_grp = CTL_FCC; | ||
1331 | |||
1332 | if (ctl_grp != CTL_FCC) | ||
1333 | /* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */ | ||
1334 | return; | ||
1335 | |||
1336 | if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) { | ||
1337 | modes = mode_list_2ghz; | ||
1338 | nr_modes = ARRAY_SIZE(mode_list_2ghz); | ||
1339 | } else { | ||
1340 | modes = mode_list_5ghz; | ||
1341 | nr_modes = ARRAY_SIZE(mode_list_5ghz); | ||
1342 | } | ||
1343 | |||
1344 | for (i = 0; i < nr_modes; i++) { | ||
1345 | u8 c = ctl_grp | modes[i].ctl_mode; | ||
1346 | for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++) | ||
1347 | if (c == ar->eeprom.ctl_index[ctl_idx]) | ||
1348 | break; | ||
1349 | if (ctl_idx < AR5416_NUM_CTLS) { | ||
1350 | int f_off = 0; | ||
1351 | |||
1352 | /* adjust freq for 40MHz */ | ||
1353 | if (modes[i].ctl_mode == CTL_2GHT40 || | ||
1354 | modes[i].ctl_mode == CTL_5GHT40) { | ||
1355 | if (bw == AR9170_BW_40_BELOW) | ||
1356 | f_off = -10; | ||
1357 | else | ||
1358 | f_off = 10; | ||
1359 | } | ||
1360 | |||
1361 | modes[i].max_power = | ||
1362 | ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1), | ||
1363 | freq+f_off); | ||
1364 | |||
1365 | /* TODO: check if the regulatory max. power is | ||
1366 | * controlled by cfg80211 for DFS | ||
1367 | * (hpmain applies it to max_power itself for DFS freq) | ||
1368 | */ | ||
1369 | |||
1370 | } else { | ||
1371 | /* Workaround in otus driver, hpmain.c, line 3906: | ||
1372 | * if no data for 5GHT20 are found, take the | ||
1373 | * legacy 5G value. | ||
1374 | * We extend this here to fallback from any other *HT or | ||
1375 | * 11G, too. | ||
1376 | */ | ||
1377 | int k = i; | ||
1378 | |||
1379 | modes[i].max_power = AR5416_MAX_RATE_POWER; | ||
1380 | while (k-- > 0) { | ||
1381 | if (modes[k].max_power != | ||
1382 | AR5416_MAX_RATE_POWER) { | ||
1383 | modes[i].max_power = modes[k].max_power; | ||
1384 | break; | ||
1385 | } | ||
1386 | } | ||
1387 | } | ||
1388 | |||
1389 | /* apply max power to pwr_cal_data (ar->power_*) */ | ||
1390 | for (j = 0; j < modes[i].pwr_cal_len; j++) { | ||
1391 | modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j], | ||
1392 | modes[i].max_power); | ||
1393 | } | ||
1394 | } | ||
1395 | #undef EDGES | ||
1396 | } | ||
1397 | |||
990 | static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) | 1398 | static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) |
991 | { | 1399 | { |
992 | struct ar9170_calibration_target_power_legacy *ctpl; | 1400 | struct ar9170_calibration_target_power_legacy *ctpl; |
@@ -1089,6 +1497,12 @@ static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) | |||
1089 | ctph[idx + 1].power[n]); | 1497 | ctph[idx + 1].power[n]); |
1090 | } | 1498 | } |
1091 | 1499 | ||
1500 | |||
1501 | /* calc. conformance test limits and apply to ar->power*[] */ | ||
1502 | ar9170_calc_ctl(ar, freq, bw); | ||
1503 | |||
1504 | /* TODO: (heavy clip) regulatory domain power level fine-tuning. */ | ||
1505 | |||
1092 | /* set ACK/CTS TX power */ | 1506 | /* set ACK/CTS TX power */ |
1093 | ar9170_regwrite_begin(ar); | 1507 | ar9170_regwrite_begin(ar); |
1094 | 1508 | ||
@@ -1207,6 +1621,10 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, | |||
1207 | if (err) | 1621 | if (err) |
1208 | return err; | 1622 | return err; |
1209 | 1623 | ||
1624 | err = ar9170_set_freq_cal_data(ar, channel); | ||
1625 | if (err) | ||
1626 | return err; | ||
1627 | |||
1210 | err = ar9170_set_power_cal(ar, channel->center_freq, bw); | 1628 | err = ar9170_set_power_cal(ar, channel->center_freq, bw); |
1211 | if (err) | 1629 | if (err) |
1212 | return err; | 1630 | return err; |
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 5618fc25d52f..2ad7d0280f7a 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c | |||
@@ -119,17 +119,15 @@ static int ath_ahb_probe(struct platform_device *pdev) | |||
119 | sc->bus_ops = &ath_ahb_bus_ops; | 119 | sc->bus_ops = &ath_ahb_bus_ops; |
120 | sc->irq = irq; | 120 | sc->irq = irq; |
121 | 121 | ||
122 | ret = ath_init_device(AR5416_AR9100_DEVID, sc); | 122 | ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0); |
123 | if (ret != 0) { | 123 | if (ret) { |
124 | dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret); | 124 | dev_err(&pdev->dev, "failed to initialize device\n"); |
125 | ret = -ENODEV; | ||
126 | goto err_free_hw; | 125 | goto err_free_hw; |
127 | } | 126 | } |
128 | 127 | ||
129 | ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); | 128 | ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); |
130 | if (ret) { | 129 | if (ret) { |
131 | dev_err(&pdev->dev, "request_irq failed, err=%d\n", ret); | 130 | dev_err(&pdev->dev, "request_irq failed\n"); |
132 | ret = -EIO; | ||
133 | goto err_detach; | 131 | goto err_detach; |
134 | } | 132 | } |
135 | 133 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 1c68a9da22d4..1d59f10f68da 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; | |||
658 | 658 | ||
659 | irqreturn_t ath_isr(int irq, void *dev); | 659 | irqreturn_t ath_isr(int irq, void *dev); |
660 | void ath_cleanup(struct ath_softc *sc); | 660 | void ath_cleanup(struct ath_softc *sc); |
661 | int ath_init_device(u16 devid, struct ath_softc *sc); | 661 | int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid); |
662 | void ath_detach(struct ath_softc *sc); | 662 | void ath_detach(struct ath_softc *sc); |
663 | const char *ath_mac_bb_name(u32 mac_bb_version); | 663 | const char *ath_mac_bb_name(u32 mac_bb_version); |
664 | const char *ath_rf_name(u16 rf_version); | 664 | const char *ath_rf_name(u16 rf_version); |
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index e8bfb01ee78a..55f607b7699e 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c | |||
@@ -19,6 +19,29 @@ | |||
19 | static const struct ath_btcoex_config ath_bt_config = { 0, true, true, | 19 | static const struct ath_btcoex_config ath_bt_config = { 0, true, true, |
20 | ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true }; | 20 | ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true }; |
21 | 21 | ||
22 | static const u16 ath_subsysid_tbl[] = { | ||
23 | AR9280_COEX2WIRE_SUBSYSID, | ||
24 | AT9285_COEX3WIRE_SA_SUBSYSID, | ||
25 | AT9285_COEX3WIRE_DA_SUBSYSID | ||
26 | }; | ||
27 | |||
28 | /* | ||
29 | * Checks the subsystem id of the device to see if it | ||
30 | * supports btcoex | ||
31 | */ | ||
32 | bool ath_btcoex_supported(u16 subsysid) | ||
33 | { | ||
34 | int i; | ||
35 | |||
36 | if (!subsysid) | ||
37 | return false; | ||
38 | |||
39 | for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++) | ||
40 | if (subsysid == ath_subsysid_tbl[i]) | ||
41 | return true; | ||
42 | |||
43 | return false; | ||
44 | } | ||
22 | 45 | ||
23 | /* | 46 | /* |
24 | * Detects if there is any priority bt traffic | 47 | * 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 45568196c59a..297b027fd3c3 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #define ATH_WLANACTIVE_GPIO 5 | 20 | #define ATH_WLANACTIVE_GPIO 5 |
21 | #define ATH_BTACTIVE_GPIO 6 | 21 | #define ATH_BTACTIVE_GPIO 6 |
22 | #define ATH_BTPRIORITY_GPIO 7 | ||
22 | 23 | ||
23 | #define ATH_BTCOEX_DEF_BT_PERIOD 45 | 24 | #define ATH_BTCOEX_DEF_BT_PERIOD 45 |
24 | #define ATH_BTCOEX_DEF_DUTY_CYCLE 55 | 25 | #define ATH_BTCOEX_DEF_DUTY_CYCLE 55 |
@@ -79,6 +80,7 @@ struct ath_btcoex_info { | |||
79 | struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/ | 80 | struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/ |
80 | }; | 81 | }; |
81 | 82 | ||
83 | bool ath_btcoex_supported(u16 subsysid); | ||
82 | int ath9k_hw_btcoex_init(struct ath_hw *ah); | 84 | int ath9k_hw_btcoex_init(struct ath_hw *ah); |
83 | void ath9k_hw_btcoex_enable(struct ath_hw *ah); | 85 | void ath9k_hw_btcoex_enable(struct ath_hw *ah); |
84 | void ath9k_hw_btcoex_disable(struct ath_hw *ah); | 86 | 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 71f27f324cea..b6c6cca07812 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -16,14 +16,11 @@ | |||
16 | 16 | ||
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <asm/unaligned.h> | 18 | #include <asm/unaligned.h> |
19 | #include <linux/pci.h> | ||
19 | 20 | ||
20 | #include "ath9k.h" | 21 | #include "ath9k.h" |
21 | #include "initvals.h" | 22 | #include "initvals.h" |
22 | 23 | ||
23 | static int btcoex_enable; | ||
24 | module_param(btcoex_enable, bool, 0); | ||
25 | MODULE_PARM_DESC(btcoex_enable, "Enable Bluetooth coexistence support"); | ||
26 | |||
27 | #define ATH9K_CLOCK_RATE_CCK 22 | 24 | #define ATH9K_CLOCK_RATE_CCK 22 |
28 | #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 | 25 | #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 |
29 | #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 | 26 | #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 |
@@ -3689,14 +3686,17 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
3689 | pCap->num_antcfg_2ghz = | 3686 | pCap->num_antcfg_2ghz = |
3690 | ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); | 3687 | ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); |
3691 | 3688 | ||
3692 | if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) { | 3689 | if (AR_SREV_9280_10_OR_LATER(ah) && |
3690 | ath_btcoex_supported(ah->hw_version.subsysid)) { | ||
3693 | btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO; | 3691 | btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO; |
3694 | btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; | 3692 | btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; |
3695 | 3693 | ||
3696 | if (AR_SREV_9285(ah)) | 3694 | if (AR_SREV_9285(ah)) { |
3697 | btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_3WIRE; | 3695 | btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_3WIRE; |
3698 | else | 3696 | btcoex_info->btpriority_gpio = ATH_BTPRIORITY_GPIO; |
3697 | } else { | ||
3699 | btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_2WIRE; | 3698 | btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_2WIRE; |
3699 | } | ||
3700 | } else { | 3700 | } else { |
3701 | btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_NONE; | 3701 | btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_NONE; |
3702 | } | 3702 | } |
@@ -3967,7 +3967,8 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) | |||
3967 | { | 3967 | { |
3968 | u32 phybits; | 3968 | u32 phybits; |
3969 | 3969 | ||
3970 | REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR); | 3970 | REG_WRITE(ah, AR_RX_FILTER, bits); |
3971 | |||
3971 | phybits = 0; | 3972 | phybits = 0; |
3972 | if (bits & ATH9K_RX_FILTER_PHYRADAR) | 3973 | if (bits & ATH9K_RX_FILTER_PHYRADAR) |
3973 | phybits |= AR_PHY_ERR_RADAR; | 3974 | phybits |= AR_PHY_ERR_RADAR; |
@@ -4297,3 +4298,16 @@ void ath_gen_timer_isr(struct ath_hw *ah) | |||
4297 | timer->trigger(timer->arg); | 4298 | timer->trigger(timer->arg); |
4298 | } | 4299 | } |
4299 | } | 4300 | } |
4301 | |||
4302 | /* | ||
4303 | * Primitive to disable ASPM | ||
4304 | */ | ||
4305 | void ath_pcie_aspm_disable(struct ath_softc *sc) | ||
4306 | { | ||
4307 | struct pci_dev *pdev = to_pci_dev(sc->dev); | ||
4308 | u8 aspm; | ||
4309 | |||
4310 | pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm); | ||
4311 | aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1); | ||
4312 | pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); | ||
4313 | } | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 5ca6ffa70912..9106a0b537dd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -45,6 +45,10 @@ | |||
45 | #define AR5416_DEVID_AR9287_PCI 0x002D | 45 | #define AR5416_DEVID_AR9287_PCI 0x002D |
46 | #define AR5416_DEVID_AR9287_PCIE 0x002E | 46 | #define AR5416_DEVID_AR9287_PCIE 0x002E |
47 | 47 | ||
48 | #define AR9280_COEX2WIRE_SUBSYSID 0x309b | ||
49 | #define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa | ||
50 | #define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab | ||
51 | |||
48 | /* Register read/write primitives */ | 52 | /* Register read/write primitives */ |
49 | #define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) | 53 | #define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) |
50 | #define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) | 54 | #define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) |
@@ -390,6 +394,7 @@ struct ath9k_hw_version { | |||
390 | u16 phyRev; | 394 | u16 phyRev; |
391 | u16 analog5GhzRev; | 395 | u16 analog5GhzRev; |
392 | u16 analog2GhzRev; | 396 | u16 analog2GhzRev; |
397 | u16 subsysid; | ||
393 | }; | 398 | }; |
394 | 399 | ||
395 | /* Generic TSF timer definitions */ | 400 | /* Generic TSF timer definitions */ |
@@ -665,4 +670,9 @@ void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); | |||
665 | void ath_gen_timer_isr(struct ath_hw *hw); | 670 | void ath_gen_timer_isr(struct ath_hw *hw); |
666 | u32 ath9k_hw_gettsf32(struct ath_hw *ah); | 671 | u32 ath9k_hw_gettsf32(struct ath_hw *ah); |
667 | 672 | ||
673 | #define ATH_PCIE_CAP_LINK_CTRL 0x70 | ||
674 | #define ATH_PCIE_CAP_LINK_L0S 1 | ||
675 | #define ATH_PCIE_CAP_LINK_L1 2 | ||
676 | |||
677 | void ath_pcie_aspm_disable(struct ath_softc *sc); | ||
668 | #endif | 678 | #endif |
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 7b3982295a43..f56e77da6c3e 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 { | |||
568 | ATH9K_RX_FILTER_PROBEREQ = 0x00000080, | 568 | ATH9K_RX_FILTER_PROBEREQ = 0x00000080, |
569 | ATH9K_RX_FILTER_PHYERR = 0x00000100, | 569 | ATH9K_RX_FILTER_PHYERR = 0x00000100, |
570 | ATH9K_RX_FILTER_MYBEACON = 0x00000200, | 570 | ATH9K_RX_FILTER_MYBEACON = 0x00000200, |
571 | ATH9K_RX_FILTER_COMP_BAR = 0x00000400, | ||
571 | ATH9K_RX_FILTER_PSPOLL = 0x00004000, | 572 | ATH9K_RX_FILTER_PSPOLL = 0x00004000, |
572 | ATH9K_RX_FILTER_PHYRADAR = 0x00002000, | 573 | ATH9K_RX_FILTER_PHYRADAR = 0x00002000, |
573 | ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000, | 574 | 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 c2efdf2d72d3..3dc7b5a13e64 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, | |||
1310 | * to allow the separation between hardware specific | 1310 | * to allow the separation between hardware specific |
1311 | * variables (now in ath_hw) and driver specific variables. | 1311 | * variables (now in ath_hw) and driver specific variables. |
1312 | */ | 1312 | */ |
1313 | static int ath_init_softc(u16 devid, struct ath_softc *sc) | 1313 | static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) |
1314 | { | 1314 | { |
1315 | struct ath_hw *ah = NULL; | 1315 | struct ath_hw *ah = NULL; |
1316 | int r = 0, i; | 1316 | int r = 0, i; |
@@ -1348,6 +1348,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) | |||
1348 | 1348 | ||
1349 | ah->ah_sc = sc; | 1349 | ah->ah_sc = sc; |
1350 | ah->hw_version.devid = devid; | 1350 | ah->hw_version.devid = devid; |
1351 | ah->hw_version.subsysid = subsysid; | ||
1351 | sc->sc_ah = ah; | 1352 | sc->sc_ah = ah; |
1352 | 1353 | ||
1353 | r = ath9k_hw_init(ah); | 1354 | r = ath9k_hw_init(ah); |
@@ -1577,7 +1578,7 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
1577 | } | 1578 | } |
1578 | 1579 | ||
1579 | /* Device driver core initialization */ | 1580 | /* Device driver core initialization */ |
1580 | int ath_init_device(u16 devid, struct ath_softc *sc) | 1581 | int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid) |
1581 | { | 1582 | { |
1582 | struct ieee80211_hw *hw = sc->hw; | 1583 | struct ieee80211_hw *hw = sc->hw; |
1583 | int error = 0, i; | 1584 | int error = 0, i; |
@@ -1585,7 +1586,7 @@ int ath_init_device(u16 devid, struct ath_softc *sc) | |||
1585 | 1586 | ||
1586 | DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); | 1587 | DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); |
1587 | 1588 | ||
1588 | error = ath_init_softc(devid, sc); | 1589 | error = ath_init_softc(devid, sc, subsysid); |
1589 | if (error != 0) | 1590 | if (error != 0) |
1590 | return error; | 1591 | return error; |
1591 | 1592 | ||
@@ -1879,7 +1880,7 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
1879 | 1880 | ||
1880 | if (chan->band == IEEE80211_BAND_2GHZ) { | 1881 | if (chan->band == IEEE80211_BAND_2GHZ) { |
1881 | ichan->chanmode = CHANNEL_G; | 1882 | ichan->chanmode = CHANNEL_G; |
1882 | ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; | 1883 | ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; |
1883 | } else { | 1884 | } else { |
1884 | ichan->chanmode = CHANNEL_A; | 1885 | ichan->chanmode = CHANNEL_A; |
1885 | ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; | 1886 | ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; |
@@ -2010,6 +2011,7 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
2010 | AR_STOMP_LOW_WLAN_WGHT); | 2011 | AR_STOMP_LOW_WLAN_WGHT); |
2011 | ath9k_hw_btcoex_enable(sc->sc_ah); | 2012 | ath9k_hw_btcoex_enable(sc->sc_ah); |
2012 | 2013 | ||
2014 | ath_pcie_aspm_disable(sc); | ||
2013 | if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) | 2015 | if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) |
2014 | ath_btcoex_timer_resume(sc, &sc->btcoex_info); | 2016 | ath_btcoex_timer_resume(sc, &sc->btcoex_info); |
2015 | } | 2017 | } |
@@ -2433,7 +2435,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, | |||
2433 | ath9k_hw_setrxfilter(sc->sc_ah, rfilt); | 2435 | ath9k_hw_setrxfilter(sc->sc_ah, rfilt); |
2434 | ath9k_ps_restore(sc); | 2436 | ath9k_ps_restore(sc); |
2435 | 2437 | ||
2436 | DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); | 2438 | DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", rfilt); |
2437 | } | 2439 | } |
2438 | 2440 | ||
2439 | static void ath9k_sta_notify(struct ieee80211_hw *hw, | 2441 | static void ath9k_sta_notify(struct ieee80211_hw *hw, |
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 685a8cebb468..903dd8ad9d43 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) | |||
35 | { | 35 | { |
36 | u8 u8tmp; | 36 | u8 u8tmp; |
37 | 37 | ||
38 | pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, | 38 | pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp); |
39 | (u8 *)&u8tmp); | ||
40 | *csz = (int)u8tmp; | 39 | *csz = (int)u8tmp; |
41 | 40 | ||
42 | /* | 41 | /* |
@@ -89,6 +88,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
89 | struct ath_softc *sc; | 88 | struct ath_softc *sc; |
90 | struct ieee80211_hw *hw; | 89 | struct ieee80211_hw *hw; |
91 | u8 csz; | 90 | u8 csz; |
91 | u16 subsysid; | ||
92 | u32 val; | 92 | u32 val; |
93 | int ret = 0; | 93 | int ret = 0; |
94 | struct ath_hw *ah; | 94 | struct ath_hw *ah; |
@@ -160,8 +160,9 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
160 | 160 | ||
161 | hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + | 161 | hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + |
162 | sizeof(struct ath_softc), &ath9k_ops); | 162 | sizeof(struct ath_softc), &ath9k_ops); |
163 | if (hw == NULL) { | 163 | if (!hw) { |
164 | printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n"); | 164 | dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); |
165 | ret = -ENOMEM; | ||
165 | goto bad2; | 166 | goto bad2; |
166 | } | 167 | } |
167 | 168 | ||
@@ -178,17 +179,18 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
178 | sc->mem = mem; | 179 | sc->mem = mem; |
179 | sc->bus_ops = &ath_pci_bus_ops; | 180 | sc->bus_ops = &ath_pci_bus_ops; |
180 | 181 | ||
181 | if (ath_init_device(id->device, sc) != 0) { | 182 | pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); |
182 | ret = -ENODEV; | 183 | ret = ath_init_device(id->device, sc, subsysid); |
184 | if (ret) { | ||
185 | dev_err(&pdev->dev, "failed to initialize device\n"); | ||
183 | goto bad3; | 186 | goto bad3; |
184 | } | 187 | } |
185 | 188 | ||
186 | /* setup interrupt service routine */ | 189 | /* setup interrupt service routine */ |
187 | 190 | ||
188 | if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) { | 191 | ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); |
189 | printk(KERN_ERR "%s: request_irq failed\n", | 192 | if (ret) { |
190 | wiphy_name(hw->wiphy)); | 193 | dev_err(&pdev->dev, "request_irq failed\n"); |
191 | ret = -EIO; | ||
192 | goto bad4; | 194 | goto bad4; |
193 | } | 195 | } |
194 | 196 | ||
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 52e62daad3ce..ec0abf823995 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) | |||
423 | if (sc->rx.rxfilter & FIF_PSPOLL) | 423 | if (sc->rx.rxfilter & FIF_PSPOLL) |
424 | rfilt |= ATH9K_RX_FILTER_PSPOLL; | 424 | rfilt |= ATH9K_RX_FILTER_PSPOLL; |
425 | 425 | ||
426 | if (conf_is_ht(&sc->hw->conf)) | ||
427 | rfilt |= ATH9K_RX_FILTER_COMP_BAR; | ||
428 | |||
426 | if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) { | 429 | if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) { |
427 | /* TODO: only needed if more than one BSSID is in use in | 430 | /* TODO: only needed if more than one BSSID is in use in |
428 | * station/adhoc mode */ | 431 | * station/adhoc mode */ |
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 3ddb243f0000..e5c29eb86e80 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h | |||
@@ -1325,7 +1325,6 @@ enum { | |||
1325 | #define AR_CFP_VAL 0x0000FFFF | 1325 | #define AR_CFP_VAL 0x0000FFFF |
1326 | 1326 | ||
1327 | #define AR_RX_FILTER 0x803C | 1327 | #define AR_RX_FILTER 0x803C |
1328 | #define AR_RX_COMPR_BAR 0x00000400 | ||
1329 | 1328 | ||
1330 | #define AR_MCAST_FIL0 0x8040 | 1329 | #define AR_MCAST_FIL0 0x8040 |
1331 | #define AR_MCAST_FIL1 0x8044 | 1330 | #define AR_MCAST_FIL1 0x8044 |
diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 4d3c53674e5a..c1dd857697a7 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h | |||
@@ -22,6 +22,12 @@ | |||
22 | 22 | ||
23 | #include "ath.h" | 23 | #include "ath.h" |
24 | 24 | ||
25 | enum ctl_group { | ||
26 | CTL_FCC = 0x10, | ||
27 | CTL_MKK = 0x40, | ||
28 | CTL_ETSI = 0x30, | ||
29 | }; | ||
30 | |||
25 | #define NO_CTL 0xff | 31 | #define NO_CTL 0xff |
26 | #define SD_NO_CTL 0xE0 | 32 | #define SD_NO_CTL 0xE0 |
27 | #define NO_CTL 0xff | 33 | #define NO_CTL 0xff |
diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index ad6d938d3cf6..9847af72208c 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h | |||
@@ -154,12 +154,6 @@ enum EnumRd { | |||
154 | DEBUG_REG_DMN = 0x01ff, | 154 | DEBUG_REG_DMN = 0x01ff, |
155 | }; | 155 | }; |
156 | 156 | ||
157 | enum ctl_group { | ||
158 | CTL_FCC = 0x10, | ||
159 | CTL_MKK = 0x40, | ||
160 | CTL_ETSI = 0x30, | ||
161 | }; | ||
162 | |||
163 | /* Regpair to CTL band mapping */ | 157 | /* Regpair to CTL band mapping */ |
164 | static struct reg_dmn_pair_mapping regDomainPairs[] = { | 158 | static struct reg_dmn_pair_mapping regDomainPairs[] = { |
165 | /* regpair, 5 GHz CTL, 2 GHz CTL */ | 159 | /* regpair, 5 GHz CTL, 2 GHz CTL */ |
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 2af3b3522322..83e38134accb 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig | |||
@@ -42,8 +42,8 @@ config B43_PCICORE_AUTOSELECT | |||
42 | default y | 42 | default y |
43 | 43 | ||
44 | config B43_PCMCIA | 44 | config B43_PCMCIA |
45 | bool "Broadcom 43xx PCMCIA device support (EXPERIMENTAL)" | 45 | bool "Broadcom 43xx PCMCIA device support" |
46 | depends on B43 && SSB_PCMCIAHOST_POSSIBLE && EXPERIMENTAL | 46 | depends on B43 && SSB_PCMCIAHOST_POSSIBLE |
47 | select SSB_PCMCIAHOST | 47 | select SSB_PCMCIAHOST |
48 | ---help--- | 48 | ---help--- |
49 | Broadcom 43xx PCMCIA device support. | 49 | Broadcom 43xx PCMCIA device support. |
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index a1b3b731935b..09cfe68537b6 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -616,6 +616,12 @@ struct b43_wl { | |||
616 | /* Pointer to the ieee80211 hardware data structure */ | 616 | /* Pointer to the ieee80211 hardware data structure */ |
617 | struct ieee80211_hw *hw; | 617 | struct ieee80211_hw *hw; |
618 | 618 | ||
619 | /* Global driver mutex. Every operation must run with this mutex locked. */ | ||
620 | struct mutex mutex; | ||
621 | /* Hard-IRQ spinlock. This lock protects things used in the hard-IRQ | ||
622 | * handler, only. This basically is just the IRQ mask register. */ | ||
623 | spinlock_t hardirq_lock; | ||
624 | |||
619 | /* The number of queues that were registered with the mac80211 subsystem | 625 | /* The number of queues that were registered with the mac80211 subsystem |
620 | * initially. This is a backup copy of hw->queues in case hw->queues has | 626 | * initially. This is a backup copy of hw->queues in case hw->queues has |
621 | * to be dynamically lowered at runtime (Firmware does not support QoS). | 627 | * to be dynamically lowered at runtime (Firmware does not support QoS). |
@@ -623,16 +629,12 @@ struct b43_wl { | |||
623 | * from the mac80211 subsystem. */ | 629 | * from the mac80211 subsystem. */ |
624 | u16 mac80211_initially_registered_queues; | 630 | u16 mac80211_initially_registered_queues; |
625 | 631 | ||
626 | struct mutex mutex; | ||
627 | spinlock_t irq_lock; | ||
628 | /* R/W lock for data transmission. | 632 | /* R/W lock for data transmission. |
629 | * Transmissions on 2+ queues can run concurrently, but somebody else | 633 | * Transmissions on 2+ queues can run concurrently, but somebody else |
630 | * might sync with TX by write_lock_irqsave()'ing. */ | 634 | * might sync with TX by write_lock_irqsave()'ing. */ |
631 | rwlock_t tx_lock; | 635 | rwlock_t tx_lock; |
632 | /* Lock for LEDs access. */ | 636 | /* Lock for LEDs access. */ |
633 | spinlock_t leds_lock; | 637 | spinlock_t leds_lock; |
634 | /* Lock for SHM access. */ | ||
635 | spinlock_t shm_lock; | ||
636 | 638 | ||
637 | /* We can only have one operating interface (802.11 core) | 639 | /* We can only have one operating interface (802.11 core) |
638 | * at a time. General information about this interface follows. | 640 | * at a time. General information about this interface follows. |
@@ -665,8 +667,7 @@ struct b43_wl { | |||
665 | bool radiotap_enabled; | 667 | bool radiotap_enabled; |
666 | bool radio_enabled; | 668 | bool radio_enabled; |
667 | 669 | ||
668 | /* The beacon we are currently using (AP or IBSS mode). | 670 | /* The beacon we are currently using (AP or IBSS mode). */ |
669 | * This beacon stuff is protected by the irq_lock. */ | ||
670 | struct sk_buff *current_beacon; | 671 | struct sk_buff *current_beacon; |
671 | bool beacon0_uploaded; | 672 | bool beacon0_uploaded; |
672 | bool beacon1_uploaded; | 673 | bool beacon1_uploaded; |
@@ -680,6 +681,11 @@ struct b43_wl { | |||
680 | * This is scheduled when we determine that the actual TX output | 681 | * This is scheduled when we determine that the actual TX output |
681 | * power doesn't match what we want. */ | 682 | * power doesn't match what we want. */ |
682 | struct work_struct txpower_adjust_work; | 683 | struct work_struct txpower_adjust_work; |
684 | |||
685 | /* Packet transmit work */ | ||
686 | struct work_struct tx_work; | ||
687 | /* Queue of packets to be transmitted. */ | ||
688 | struct sk_buff_head tx_queue; | ||
683 | }; | 689 | }; |
684 | 690 | ||
685 | /* The type of the firmware file. */ | 691 | /* The type of the firmware file. */ |
@@ -754,14 +760,6 @@ enum { | |||
754 | smp_wmb(); \ | 760 | smp_wmb(); \ |
755 | } while (0) | 761 | } while (0) |
756 | 762 | ||
757 | /* XXX--- HOW LOCKING WORKS IN B43 ---XXX | ||
758 | * | ||
759 | * You should always acquire both, wl->mutex and wl->irq_lock unless: | ||
760 | * - You don't need to acquire wl->irq_lock, if the interface is stopped. | ||
761 | * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet | ||
762 | * and packet TX path (and _ONLY_ there.) | ||
763 | */ | ||
764 | |||
765 | /* Data structure for one wireless device (802.11 core) */ | 763 | /* Data structure for one wireless device (802.11 core) */ |
766 | struct b43_wldev { | 764 | struct b43_wldev { |
767 | struct ssb_device *dev; | 765 | struct ssb_device *dev; |
@@ -807,14 +805,12 @@ struct b43_wldev { | |||
807 | u32 dma_reason[6]; | 805 | u32 dma_reason[6]; |
808 | /* The currently active generic-interrupt mask. */ | 806 | /* The currently active generic-interrupt mask. */ |
809 | u32 irq_mask; | 807 | u32 irq_mask; |
808 | |||
810 | /* Link Quality calculation context. */ | 809 | /* Link Quality calculation context. */ |
811 | struct b43_noise_calculation noisecalc; | 810 | struct b43_noise_calculation noisecalc; |
812 | /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ | 811 | /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ |
813 | int mac_suspended; | 812 | int mac_suspended; |
814 | 813 | ||
815 | /* Interrupt Service Routine tasklet (bottom-half) */ | ||
816 | struct tasklet_struct isr_tasklet; | ||
817 | |||
818 | /* Periodic tasks */ | 814 | /* Periodic tasks */ |
819 | struct delayed_work periodic_work; | 815 | struct delayed_work periodic_work; |
820 | unsigned int periodic_state; | 816 | unsigned int periodic_state; |
diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 45e3d6af69f5..8f64943e3f60 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c | |||
@@ -46,8 +46,6 @@ struct b43_debugfs_fops { | |||
46 | struct file_operations fops; | 46 | struct file_operations fops; |
47 | /* Offset of struct b43_dfs_file in struct b43_dfsentry */ | 47 | /* Offset of struct b43_dfs_file in struct b43_dfsentry */ |
48 | size_t file_struct_offset; | 48 | size_t file_struct_offset; |
49 | /* Take wl->irq_lock before calling read/write? */ | ||
50 | bool take_irqlock; | ||
51 | }; | 49 | }; |
52 | 50 | ||
53 | static inline | 51 | static inline |
@@ -127,7 +125,6 @@ static int shm16write__write_file(struct b43_wldev *dev, | |||
127 | unsigned int routing, addr, mask, set; | 125 | unsigned int routing, addr, mask, set; |
128 | u16 val; | 126 | u16 val; |
129 | int res; | 127 | int res; |
130 | unsigned long flags; | ||
131 | 128 | ||
132 | res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", | 129 | res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", |
133 | &routing, &addr, &mask, &set); | 130 | &routing, &addr, &mask, &set); |
@@ -144,15 +141,13 @@ static int shm16write__write_file(struct b43_wldev *dev, | |||
144 | if ((mask > 0xFFFF) || (set > 0xFFFF)) | 141 | if ((mask > 0xFFFF) || (set > 0xFFFF)) |
145 | return -E2BIG; | 142 | return -E2BIG; |
146 | 143 | ||
147 | spin_lock_irqsave(&dev->wl->shm_lock, flags); | ||
148 | if (mask == 0) | 144 | if (mask == 0) |
149 | val = 0; | 145 | val = 0; |
150 | else | 146 | else |
151 | val = __b43_shm_read16(dev, routing, addr); | 147 | val = b43_shm_read16(dev, routing, addr); |
152 | val &= mask; | 148 | val &= mask; |
153 | val |= set; | 149 | val |= set; |
154 | __b43_shm_write16(dev, routing, addr, val); | 150 | b43_shm_write16(dev, routing, addr, val); |
155 | spin_unlock_irqrestore(&dev->wl->shm_lock, flags); | ||
156 | 151 | ||
157 | return 0; | 152 | return 0; |
158 | } | 153 | } |
@@ -206,7 +201,6 @@ static int shm32write__write_file(struct b43_wldev *dev, | |||
206 | unsigned int routing, addr, mask, set; | 201 | unsigned int routing, addr, mask, set; |
207 | u32 val; | 202 | u32 val; |
208 | int res; | 203 | int res; |
209 | unsigned long flags; | ||
210 | 204 | ||
211 | res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", | 205 | res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", |
212 | &routing, &addr, &mask, &set); | 206 | &routing, &addr, &mask, &set); |
@@ -223,15 +217,13 @@ static int shm32write__write_file(struct b43_wldev *dev, | |||
223 | if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF)) | 217 | if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF)) |
224 | return -E2BIG; | 218 | return -E2BIG; |
225 | 219 | ||
226 | spin_lock_irqsave(&dev->wl->shm_lock, flags); | ||
227 | if (mask == 0) | 220 | if (mask == 0) |
228 | val = 0; | 221 | val = 0; |
229 | else | 222 | else |
230 | val = __b43_shm_read32(dev, routing, addr); | 223 | val = b43_shm_read32(dev, routing, addr); |
231 | val &= mask; | 224 | val &= mask; |
232 | val |= set; | 225 | val |= set; |
233 | __b43_shm_write32(dev, routing, addr, val); | 226 | b43_shm_write32(dev, routing, addr, val); |
234 | spin_unlock_irqrestore(&dev->wl->shm_lock, flags); | ||
235 | 227 | ||
236 | return 0; | 228 | return 0; |
237 | } | 229 | } |
@@ -372,14 +364,12 @@ static ssize_t txstat_read_file(struct b43_wldev *dev, | |||
372 | { | 364 | { |
373 | struct b43_txstatus_log *log = &dev->dfsentry->txstatlog; | 365 | struct b43_txstatus_log *log = &dev->dfsentry->txstatlog; |
374 | ssize_t count = 0; | 366 | ssize_t count = 0; |
375 | unsigned long flags; | ||
376 | int i, idx; | 367 | int i, idx; |
377 | struct b43_txstatus *stat; | 368 | struct b43_txstatus *stat; |
378 | 369 | ||
379 | spin_lock_irqsave(&log->lock, flags); | ||
380 | if (log->end < 0) { | 370 | if (log->end < 0) { |
381 | fappend("Nothing transmitted, yet\n"); | 371 | fappend("Nothing transmitted, yet\n"); |
382 | goto out_unlock; | 372 | goto out; |
383 | } | 373 | } |
384 | fappend("b43 TX status reports:\n\n" | 374 | fappend("b43 TX status reports:\n\n" |
385 | "index | cookie | seq | phy_stat | frame_count | " | 375 | "index | cookie | seq | phy_stat | frame_count | " |
@@ -409,13 +399,11 @@ static ssize_t txstat_read_file(struct b43_wldev *dev, | |||
409 | break; | 399 | break; |
410 | i++; | 400 | i++; |
411 | } | 401 | } |
412 | out_unlock: | 402 | out: |
413 | spin_unlock_irqrestore(&log->lock, flags); | ||
414 | 403 | ||
415 | return count; | 404 | return count; |
416 | } | 405 | } |
417 | 406 | ||
418 | /* wl->irq_lock is locked */ | ||
419 | static int restart_write_file(struct b43_wldev *dev, | 407 | static int restart_write_file(struct b43_wldev *dev, |
420 | const char *buf, size_t count) | 408 | const char *buf, size_t count) |
421 | { | 409 | { |
@@ -556,12 +544,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, | |||
556 | goto out_unlock; | 544 | goto out_unlock; |
557 | } | 545 | } |
558 | memset(buf, 0, bufsize); | 546 | memset(buf, 0, bufsize); |
559 | if (dfops->take_irqlock) { | 547 | ret = dfops->read(dev, buf, bufsize); |
560 | spin_lock_irq(&dev->wl->irq_lock); | ||
561 | ret = dfops->read(dev, buf, bufsize); | ||
562 | spin_unlock_irq(&dev->wl->irq_lock); | ||
563 | } else | ||
564 | ret = dfops->read(dev, buf, bufsize); | ||
565 | if (ret <= 0) { | 548 | if (ret <= 0) { |
566 | free_pages((unsigned long)buf, buforder); | 549 | free_pages((unsigned long)buf, buforder); |
567 | err = ret; | 550 | err = ret; |
@@ -623,12 +606,7 @@ static ssize_t b43_debugfs_write(struct file *file, | |||
623 | err = -EFAULT; | 606 | err = -EFAULT; |
624 | goto out_freepage; | 607 | goto out_freepage; |
625 | } | 608 | } |
626 | if (dfops->take_irqlock) { | 609 | err = dfops->write(dev, buf, count); |
627 | spin_lock_irq(&dev->wl->irq_lock); | ||
628 | err = dfops->write(dev, buf, count); | ||
629 | spin_unlock_irq(&dev->wl->irq_lock); | ||
630 | } else | ||
631 | err = dfops->write(dev, buf, count); | ||
632 | if (err) | 610 | if (err) |
633 | goto out_freepage; | 611 | goto out_freepage; |
634 | 612 | ||
@@ -641,7 +619,7 @@ out_unlock: | |||
641 | } | 619 | } |
642 | 620 | ||
643 | 621 | ||
644 | #define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \ | 622 | #define B43_DEBUGFS_FOPS(name, _read, _write) \ |
645 | static struct b43_debugfs_fops fops_##name = { \ | 623 | static struct b43_debugfs_fops fops_##name = { \ |
646 | .read = _read, \ | 624 | .read = _read, \ |
647 | .write = _write, \ | 625 | .write = _write, \ |
@@ -652,20 +630,19 @@ out_unlock: | |||
652 | }, \ | 630 | }, \ |
653 | .file_struct_offset = offsetof(struct b43_dfsentry, \ | 631 | .file_struct_offset = offsetof(struct b43_dfsentry, \ |
654 | file_##name), \ | 632 | file_##name), \ |
655 | .take_irqlock = _take_irqlock, \ | ||
656 | } | 633 | } |
657 | 634 | ||
658 | B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file, 1); | 635 | B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file); |
659 | B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file, 1); | 636 | B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file); |
660 | B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file, 1); | 637 | B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file); |
661 | B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file, 1); | 638 | B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file); |
662 | B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file, 1); | 639 | B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file); |
663 | B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file, 1); | 640 | B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file); |
664 | B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1); | 641 | B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file); |
665 | B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1); | 642 | B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file); |
666 | B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); | 643 | B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL); |
667 | B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); | 644 | B43_DEBUGFS_FOPS(restart, NULL, restart_write_file); |
668 | B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0); | 645 | B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL); |
669 | 646 | ||
670 | 647 | ||
671 | bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) | 648 | bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) |
@@ -738,7 +715,6 @@ void b43_debugfs_add_device(struct b43_wldev *dev) | |||
738 | return; | 715 | return; |
739 | } | 716 | } |
740 | log->end = -1; | 717 | log->end = -1; |
741 | spin_lock_init(&log->lock); | ||
742 | 718 | ||
743 | dev->dfsentry = e; | 719 | dev->dfsentry = e; |
744 | 720 | ||
@@ -822,7 +798,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev) | |||
822 | kfree(e); | 798 | kfree(e); |
823 | } | 799 | } |
824 | 800 | ||
825 | /* Called with IRQs disabled. */ | ||
826 | void b43_debugfs_log_txstat(struct b43_wldev *dev, | 801 | void b43_debugfs_log_txstat(struct b43_wldev *dev, |
827 | const struct b43_txstatus *status) | 802 | const struct b43_txstatus *status) |
828 | { | 803 | { |
@@ -834,14 +809,12 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev, | |||
834 | if (!e) | 809 | if (!e) |
835 | return; | 810 | return; |
836 | log = &e->txstatlog; | 811 | log = &e->txstatlog; |
837 | spin_lock(&log->lock); /* IRQs are already disabled. */ | ||
838 | i = log->end + 1; | 812 | i = log->end + 1; |
839 | if (i == B43_NR_LOGGED_TXSTATUS) | 813 | if (i == B43_NR_LOGGED_TXSTATUS) |
840 | i = 0; | 814 | i = 0; |
841 | log->end = i; | 815 | log->end = i; |
842 | cur = &(log->log[i]); | 816 | cur = &(log->log[i]); |
843 | memcpy(cur, status, sizeof(*cur)); | 817 | memcpy(cur, status, sizeof(*cur)); |
844 | spin_unlock(&log->lock); | ||
845 | } | 818 | } |
846 | 819 | ||
847 | void b43_debugfs_init(void) | 820 | void b43_debugfs_init(void) |
diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h index b9d4de4a979c..e47b4b488b04 100644 --- a/drivers/net/wireless/b43/debugfs.h +++ b/drivers/net/wireless/b43/debugfs.h | |||
@@ -23,9 +23,10 @@ struct dentry; | |||
23 | #define B43_NR_LOGGED_TXSTATUS 100 | 23 | #define B43_NR_LOGGED_TXSTATUS 100 |
24 | 24 | ||
25 | struct b43_txstatus_log { | 25 | struct b43_txstatus_log { |
26 | /* This structure is protected by wl->mutex */ | ||
27 | |||
26 | struct b43_txstatus *log; | 28 | struct b43_txstatus *log; |
27 | int end; | 29 | int end; |
28 | spinlock_t lock; | ||
29 | }; | 30 | }; |
30 | 31 | ||
31 | struct b43_dfs_file { | 32 | struct b43_dfs_file { |
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 289aaf6dfe79..a467ee260a19 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, | |||
856 | } else | 856 | } else |
857 | B43_WARN_ON(1); | 857 | B43_WARN_ON(1); |
858 | } | 858 | } |
859 | spin_lock_init(&ring->lock); | ||
860 | #ifdef CONFIG_B43_DEBUG | 859 | #ifdef CONFIG_B43_DEBUG |
861 | ring->last_injected_overflow = jiffies; | 860 | ring->last_injected_overflow = jiffies; |
862 | #endif | 861 | #endif |
@@ -1315,7 +1314,6 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
1315 | struct b43_dmaring *ring; | 1314 | struct b43_dmaring *ring; |
1316 | struct ieee80211_hdr *hdr; | 1315 | struct ieee80211_hdr *hdr; |
1317 | int err = 0; | 1316 | int err = 0; |
1318 | unsigned long flags; | ||
1319 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1317 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1320 | 1318 | ||
1321 | hdr = (struct ieee80211_hdr *)skb->data; | 1319 | hdr = (struct ieee80211_hdr *)skb->data; |
@@ -1331,8 +1329,6 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
1331 | dev, skb_get_queue_mapping(skb)); | 1329 | dev, skb_get_queue_mapping(skb)); |
1332 | } | 1330 | } |
1333 | 1331 | ||
1334 | spin_lock_irqsave(&ring->lock, flags); | ||
1335 | |||
1336 | B43_WARN_ON(!ring->tx); | 1332 | B43_WARN_ON(!ring->tx); |
1337 | 1333 | ||
1338 | if (unlikely(ring->stopped)) { | 1334 | if (unlikely(ring->stopped)) { |
@@ -1343,7 +1339,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
1343 | if (b43_debug(dev, B43_DBG_DMAVERBOSE)) | 1339 | if (b43_debug(dev, B43_DBG_DMAVERBOSE)) |
1344 | b43err(dev->wl, "Packet after queue stopped\n"); | 1340 | b43err(dev->wl, "Packet after queue stopped\n"); |
1345 | err = -ENOSPC; | 1341 | err = -ENOSPC; |
1346 | goto out_unlock; | 1342 | goto out; |
1347 | } | 1343 | } |
1348 | 1344 | ||
1349 | if (unlikely(WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME))) { | 1345 | 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) | |||
1351 | * full, but queues not stopped. */ | 1347 | * full, but queues not stopped. */ |
1352 | b43err(dev->wl, "DMA queue overflow\n"); | 1348 | b43err(dev->wl, "DMA queue overflow\n"); |
1353 | err = -ENOSPC; | 1349 | err = -ENOSPC; |
1354 | goto out_unlock; | 1350 | goto out; |
1355 | } | 1351 | } |
1356 | 1352 | ||
1357 | /* Assign the queue number to the ring (if not already done before) | 1353 | /* 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) | |||
1365 | * anymore and must not transmit it unencrypted. */ | 1361 | * anymore and must not transmit it unencrypted. */ |
1366 | dev_kfree_skb_any(skb); | 1362 | dev_kfree_skb_any(skb); |
1367 | err = 0; | 1363 | err = 0; |
1368 | goto out_unlock; | 1364 | goto out; |
1369 | } | 1365 | } |
1370 | if (unlikely(err)) { | 1366 | if (unlikely(err)) { |
1371 | b43err(dev->wl, "DMA tx mapping failure\n"); | 1367 | b43err(dev->wl, "DMA tx mapping failure\n"); |
1372 | goto out_unlock; | 1368 | goto out; |
1373 | } | 1369 | } |
1374 | ring->nr_tx_packets++; | 1370 | ring->nr_tx_packets++; |
1375 | if ((free_slots(ring) < TX_SLOTS_PER_FRAME) || | 1371 | if ((free_slots(ring) < TX_SLOTS_PER_FRAME) || |
@@ -1381,13 +1377,11 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
1381 | b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); | 1377 | b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); |
1382 | } | 1378 | } |
1383 | } | 1379 | } |
1384 | out_unlock: | 1380 | out: |
1385 | spin_unlock_irqrestore(&ring->lock, flags); | ||
1386 | 1381 | ||
1387 | return err; | 1382 | return err; |
1388 | } | 1383 | } |
1389 | 1384 | ||
1390 | /* Called with IRQs disabled. */ | ||
1391 | void b43_dma_handle_txstatus(struct b43_wldev *dev, | 1385 | void b43_dma_handle_txstatus(struct b43_wldev *dev, |
1392 | const struct b43_txstatus *status) | 1386 | const struct b43_txstatus *status) |
1393 | { | 1387 | { |
@@ -1402,8 +1396,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, | |||
1402 | if (unlikely(!ring)) | 1396 | if (unlikely(!ring)) |
1403 | return; | 1397 | return; |
1404 | 1398 | ||
1405 | spin_lock(&ring->lock); /* IRQs are already disabled. */ | ||
1406 | |||
1407 | B43_WARN_ON(!ring->tx); | 1399 | B43_WARN_ON(!ring->tx); |
1408 | ops = ring->ops; | 1400 | ops = ring->ops; |
1409 | while (1) { | 1401 | while (1) { |
@@ -1462,8 +1454,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, | |||
1462 | b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); | 1454 | b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); |
1463 | } | 1455 | } |
1464 | } | 1456 | } |
1465 | |||
1466 | spin_unlock(&ring->lock); | ||
1467 | } | 1457 | } |
1468 | 1458 | ||
1469 | void b43_dma_get_tx_stats(struct b43_wldev *dev, | 1459 | void b43_dma_get_tx_stats(struct b43_wldev *dev, |
@@ -1471,17 +1461,14 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, | |||
1471 | { | 1461 | { |
1472 | const int nr_queues = dev->wl->hw->queues; | 1462 | const int nr_queues = dev->wl->hw->queues; |
1473 | struct b43_dmaring *ring; | 1463 | struct b43_dmaring *ring; |
1474 | unsigned long flags; | ||
1475 | int i; | 1464 | int i; |
1476 | 1465 | ||
1477 | for (i = 0; i < nr_queues; i++) { | 1466 | for (i = 0; i < nr_queues; i++) { |
1478 | ring = select_ring_by_priority(dev, i); | 1467 | ring = select_ring_by_priority(dev, i); |
1479 | 1468 | ||
1480 | spin_lock_irqsave(&ring->lock, flags); | ||
1481 | stats[i].len = ring->used_slots / TX_SLOTS_PER_FRAME; | 1469 | stats[i].len = ring->used_slots / TX_SLOTS_PER_FRAME; |
1482 | stats[i].limit = ring->nr_slots / TX_SLOTS_PER_FRAME; | 1470 | stats[i].limit = ring->nr_slots / TX_SLOTS_PER_FRAME; |
1483 | stats[i].count = ring->nr_tx_packets; | 1471 | stats[i].count = ring->nr_tx_packets; |
1484 | spin_unlock_irqrestore(&ring->lock, flags); | ||
1485 | } | 1472 | } |
1486 | } | 1473 | } |
1487 | 1474 | ||
@@ -1592,22 +1579,14 @@ void b43_dma_rx(struct b43_dmaring *ring) | |||
1592 | 1579 | ||
1593 | static void b43_dma_tx_suspend_ring(struct b43_dmaring *ring) | 1580 | static void b43_dma_tx_suspend_ring(struct b43_dmaring *ring) |
1594 | { | 1581 | { |
1595 | unsigned long flags; | ||
1596 | |||
1597 | spin_lock_irqsave(&ring->lock, flags); | ||
1598 | B43_WARN_ON(!ring->tx); | 1582 | B43_WARN_ON(!ring->tx); |
1599 | ring->ops->tx_suspend(ring); | 1583 | ring->ops->tx_suspend(ring); |
1600 | spin_unlock_irqrestore(&ring->lock, flags); | ||
1601 | } | 1584 | } |
1602 | 1585 | ||
1603 | static void b43_dma_tx_resume_ring(struct b43_dmaring *ring) | 1586 | static void b43_dma_tx_resume_ring(struct b43_dmaring *ring) |
1604 | { | 1587 | { |
1605 | unsigned long flags; | ||
1606 | |||
1607 | spin_lock_irqsave(&ring->lock, flags); | ||
1608 | B43_WARN_ON(!ring->tx); | 1588 | B43_WARN_ON(!ring->tx); |
1609 | ring->ops->tx_resume(ring); | 1589 | ring->ops->tx_resume(ring); |
1610 | spin_unlock_irqrestore(&ring->lock, flags); | ||
1611 | } | 1590 | } |
1612 | 1591 | ||
1613 | void b43_dma_tx_suspend(struct b43_wldev *dev) | 1592 | 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 05dde646d831..f0b0838fb5ba 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h | |||
@@ -2,7 +2,6 @@ | |||
2 | #define B43_DMA_H_ | 2 | #define B43_DMA_H_ |
3 | 3 | ||
4 | #include <linux/ieee80211.h> | 4 | #include <linux/ieee80211.h> |
5 | #include <linux/spinlock.h> | ||
6 | 5 | ||
7 | #include "b43.h" | 6 | #include "b43.h" |
8 | 7 | ||
@@ -244,8 +243,6 @@ struct b43_dmaring { | |||
244 | /* The QOS priority assigned to this ring. Only used for TX rings. | 243 | /* The QOS priority assigned to this ring. Only used for TX rings. |
245 | * This is the mac80211 "queue" value. */ | 244 | * This is the mac80211 "queue" value. */ |
246 | u8 queue_prio; | 245 | u8 queue_prio; |
247 | /* Lock, only used for TX. */ | ||
248 | spinlock_t lock; | ||
249 | struct b43_wldev *dev; | 246 | struct b43_wldev *dev; |
250 | #ifdef CONFIG_B43_DEBUG | 247 | #ifdef CONFIG_B43_DEBUG |
251 | /* Maximum number of used slots. */ | 248 | /* Maximum number of used slots. */ |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ae05f6671149..7a9a3fa55425 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 = { | |||
291 | 291 | ||
292 | static void b43_wireless_core_exit(struct b43_wldev *dev); | 292 | static void b43_wireless_core_exit(struct b43_wldev *dev); |
293 | static int b43_wireless_core_init(struct b43_wldev *dev); | 293 | static int b43_wireless_core_init(struct b43_wldev *dev); |
294 | static void b43_wireless_core_stop(struct b43_wldev *dev); | 294 | static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev); |
295 | static int b43_wireless_core_start(struct b43_wldev *dev); | 295 | static int b43_wireless_core_start(struct b43_wldev *dev); |
296 | 296 | ||
297 | static int b43_ratelimit(struct b43_wl *wl) | 297 | static int b43_ratelimit(struct b43_wl *wl) |
@@ -390,7 +390,7 @@ static inline void b43_shm_control_word(struct b43_wldev *dev, | |||
390 | b43_write32(dev, B43_MMIO_SHM_CONTROL, control); | 390 | b43_write32(dev, B43_MMIO_SHM_CONTROL, control); |
391 | } | 391 | } |
392 | 392 | ||
393 | u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) | 393 | u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) |
394 | { | 394 | { |
395 | u32 ret; | 395 | u32 ret; |
396 | 396 | ||
@@ -413,20 +413,7 @@ out: | |||
413 | return ret; | 413 | return ret; |
414 | } | 414 | } |
415 | 415 | ||
416 | u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) | 416 | u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) |
417 | { | ||
418 | struct b43_wl *wl = dev->wl; | ||
419 | unsigned long flags; | ||
420 | u32 ret; | ||
421 | |||
422 | spin_lock_irqsave(&wl->shm_lock, flags); | ||
423 | ret = __b43_shm_read32(dev, routing, offset); | ||
424 | spin_unlock_irqrestore(&wl->shm_lock, flags); | ||
425 | |||
426 | return ret; | ||
427 | } | ||
428 | |||
429 | u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) | ||
430 | { | 417 | { |
431 | u16 ret; | 418 | u16 ret; |
432 | 419 | ||
@@ -447,20 +434,7 @@ out: | |||
447 | return ret; | 434 | return ret; |
448 | } | 435 | } |
449 | 436 | ||
450 | u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) | 437 | void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) |
451 | { | ||
452 | struct b43_wl *wl = dev->wl; | ||
453 | unsigned long flags; | ||
454 | u16 ret; | ||
455 | |||
456 | spin_lock_irqsave(&wl->shm_lock, flags); | ||
457 | ret = __b43_shm_read16(dev, routing, offset); | ||
458 | spin_unlock_irqrestore(&wl->shm_lock, flags); | ||
459 | |||
460 | return ret; | ||
461 | } | ||
462 | |||
463 | void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) | ||
464 | { | 438 | { |
465 | if (routing == B43_SHM_SHARED) { | 439 | if (routing == B43_SHM_SHARED) { |
466 | B43_WARN_ON(offset & 0x0001); | 440 | B43_WARN_ON(offset & 0x0001); |
@@ -480,17 +454,7 @@ void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value | |||
480 | b43_write32(dev, B43_MMIO_SHM_DATA, value); | 454 | b43_write32(dev, B43_MMIO_SHM_DATA, value); |
481 | } | 455 | } |
482 | 456 | ||
483 | void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) | 457 | void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) |
484 | { | ||
485 | struct b43_wl *wl = dev->wl; | ||
486 | unsigned long flags; | ||
487 | |||
488 | spin_lock_irqsave(&wl->shm_lock, flags); | ||
489 | __b43_shm_write32(dev, routing, offset, value); | ||
490 | spin_unlock_irqrestore(&wl->shm_lock, flags); | ||
491 | } | ||
492 | |||
493 | void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) | ||
494 | { | 458 | { |
495 | if (routing == B43_SHM_SHARED) { | 459 | if (routing == B43_SHM_SHARED) { |
496 | B43_WARN_ON(offset & 0x0001); | 460 | B43_WARN_ON(offset & 0x0001); |
@@ -506,16 +470,6 @@ void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value | |||
506 | b43_write16(dev, B43_MMIO_SHM_DATA, value); | 470 | b43_write16(dev, B43_MMIO_SHM_DATA, value); |
507 | } | 471 | } |
508 | 472 | ||
509 | void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) | ||
510 | { | ||
511 | struct b43_wl *wl = dev->wl; | ||
512 | unsigned long flags; | ||
513 | |||
514 | spin_lock_irqsave(&wl->shm_lock, flags); | ||
515 | __b43_shm_write16(dev, routing, offset, value); | ||
516 | spin_unlock_irqrestore(&wl->shm_lock, flags); | ||
517 | } | ||
518 | |||
519 | /* Read HostFlags */ | 473 | /* Read HostFlags */ |
520 | u64 b43_hf_read(struct b43_wldev *dev) | 474 | u64 b43_hf_read(struct b43_wldev *dev) |
521 | { | 475 | { |
@@ -685,22 +639,11 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev) | |||
685 | b43_set_slot_time(dev, 20); | 639 | b43_set_slot_time(dev, 20); |
686 | } | 640 | } |
687 | 641 | ||
688 | /* Synchronize IRQ top- and bottom-half. | ||
689 | * IRQs must be masked before calling this. | ||
690 | * This must not be called with the irq_lock held. | ||
691 | */ | ||
692 | static void b43_synchronize_irq(struct b43_wldev *dev) | ||
693 | { | ||
694 | synchronize_irq(dev->dev->irq); | ||
695 | tasklet_kill(&dev->isr_tasklet); | ||
696 | } | ||
697 | |||
698 | /* DummyTransmission function, as documented on | 642 | /* DummyTransmission function, as documented on |
699 | * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission | 643 | * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission |
700 | */ | 644 | */ |
701 | void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) | 645 | void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) |
702 | { | 646 | { |
703 | struct b43_wl *wl = dev->wl; | ||
704 | struct b43_phy *phy = &dev->phy; | 647 | struct b43_phy *phy = &dev->phy; |
705 | unsigned int i, max_loop; | 648 | unsigned int i, max_loop; |
706 | u16 value; | 649 | u16 value; |
@@ -720,9 +663,6 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) | |||
720 | buffer[0] = 0x000B846E; | 663 | buffer[0] = 0x000B846E; |
721 | } | 664 | } |
722 | 665 | ||
723 | spin_lock_irq(&wl->irq_lock); | ||
724 | write_lock(&wl->tx_lock); | ||
725 | |||
726 | for (i = 0; i < 5; i++) | 666 | for (i = 0; i < 5; i++) |
727 | b43_ram_write(dev, i * 4, buffer[i]); | 667 | b43_ram_write(dev, i * 4, buffer[i]); |
728 | 668 | ||
@@ -778,9 +718,6 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) | |||
778 | } | 718 | } |
779 | if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) | 719 | if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) |
780 | b43_radio_write16(dev, 0x0051, 0x0037); | 720 | b43_radio_write16(dev, 0x0051, 0x0037); |
781 | |||
782 | write_unlock(&wl->tx_lock); | ||
783 | spin_unlock_irq(&wl->irq_lock); | ||
784 | } | 721 | } |
785 | 722 | ||
786 | static void key_write(struct b43_wldev *dev, | 723 | static void key_write(struct b43_wldev *dev, |
@@ -1620,6 +1557,27 @@ static void handle_irq_beacon(struct b43_wldev *dev) | |||
1620 | } | 1557 | } |
1621 | } | 1558 | } |
1622 | 1559 | ||
1560 | static void b43_do_beacon_update_trigger_work(struct b43_wldev *dev) | ||
1561 | { | ||
1562 | u32 old_irq_mask = dev->irq_mask; | ||
1563 | |||
1564 | /* update beacon right away or defer to irq */ | ||
1565 | handle_irq_beacon(dev); | ||
1566 | if (old_irq_mask != dev->irq_mask) { | ||
1567 | /* The handler updated the IRQ mask. */ | ||
1568 | B43_WARN_ON(!dev->irq_mask); | ||
1569 | if (b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)) { | ||
1570 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); | ||
1571 | } else { | ||
1572 | /* Device interrupts are currently disabled. That means | ||
1573 | * we just ran the hardirq handler and scheduled the | ||
1574 | * IRQ thread. The thread will write the IRQ mask when | ||
1575 | * it finished, so there's nothing to do here. Writing | ||
1576 | * the mask _here_ would incorrectly re-enable IRQs. */ | ||
1577 | } | ||
1578 | } | ||
1579 | } | ||
1580 | |||
1623 | static void b43_beacon_update_trigger_work(struct work_struct *work) | 1581 | static void b43_beacon_update_trigger_work(struct work_struct *work) |
1624 | { | 1582 | { |
1625 | struct b43_wl *wl = container_of(work, struct b43_wl, | 1583 | struct b43_wl *wl = container_of(work, struct b43_wl, |
@@ -1629,19 +1587,22 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) | |||
1629 | mutex_lock(&wl->mutex); | 1587 | mutex_lock(&wl->mutex); |
1630 | dev = wl->current_dev; | 1588 | dev = wl->current_dev; |
1631 | if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { | 1589 | if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { |
1632 | spin_lock_irq(&wl->irq_lock); | 1590 | if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { |
1633 | /* update beacon right away or defer to irq */ | 1591 | /* wl->mutex is enough. */ |
1634 | handle_irq_beacon(dev); | 1592 | b43_do_beacon_update_trigger_work(dev); |
1635 | /* The handler might have updated the IRQ mask. */ | 1593 | mmiowb(); |
1636 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); | 1594 | } else { |
1637 | mmiowb(); | 1595 | spin_lock_irq(&wl->hardirq_lock); |
1638 | spin_unlock_irq(&wl->irq_lock); | 1596 | b43_do_beacon_update_trigger_work(dev); |
1597 | mmiowb(); | ||
1598 | spin_unlock_irq(&wl->hardirq_lock); | ||
1599 | } | ||
1639 | } | 1600 | } |
1640 | mutex_unlock(&wl->mutex); | 1601 | mutex_unlock(&wl->mutex); |
1641 | } | 1602 | } |
1642 | 1603 | ||
1643 | /* Asynchronously update the packet templates in template RAM. | 1604 | /* Asynchronously update the packet templates in template RAM. |
1644 | * Locking: Requires wl->irq_lock to be locked. */ | 1605 | * Locking: Requires wl->mutex to be locked. */ |
1645 | static void b43_update_templates(struct b43_wl *wl) | 1606 | static void b43_update_templates(struct b43_wl *wl) |
1646 | { | 1607 | { |
1647 | struct sk_buff *beacon; | 1608 | struct sk_buff *beacon; |
@@ -1778,18 +1739,15 @@ out: | |||
1778 | B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK); | 1739 | B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK); |
1779 | } | 1740 | } |
1780 | 1741 | ||
1781 | /* Interrupt handler bottom-half */ | 1742 | static void b43_do_interrupt_thread(struct b43_wldev *dev) |
1782 | static void b43_interrupt_tasklet(struct b43_wldev *dev) | ||
1783 | { | 1743 | { |
1784 | u32 reason; | 1744 | u32 reason; |
1785 | u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; | 1745 | u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; |
1786 | u32 merged_dma_reason = 0; | 1746 | u32 merged_dma_reason = 0; |
1787 | int i; | 1747 | int i; |
1788 | unsigned long flags; | ||
1789 | |||
1790 | spin_lock_irqsave(&dev->wl->irq_lock, flags); | ||
1791 | 1748 | ||
1792 | B43_WARN_ON(b43_status(dev) != B43_STAT_STARTED); | 1749 | if (unlikely(b43_status(dev) != B43_STAT_STARTED)) |
1750 | return; | ||
1793 | 1751 | ||
1794 | reason = dev->irq_reason; | 1752 | reason = dev->irq_reason; |
1795 | for (i = 0; i < ARRAY_SIZE(dma_reason); i++) { | 1753 | for (i = 0; i < ARRAY_SIZE(dma_reason); i++) { |
@@ -1822,8 +1780,6 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) | |||
1822 | dma_reason[2], dma_reason[3], | 1780 | dma_reason[2], dma_reason[3], |
1823 | dma_reason[4], dma_reason[5]); | 1781 | dma_reason[4], dma_reason[5]); |
1824 | b43_controller_restart(dev, "DMA error"); | 1782 | b43_controller_restart(dev, "DMA error"); |
1825 | mmiowb(); | ||
1826 | spin_unlock_irqrestore(&dev->wl->irq_lock, flags); | ||
1827 | return; | 1783 | return; |
1828 | } | 1784 | } |
1829 | if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) { | 1785 | if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) { |
@@ -1867,47 +1823,36 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) | |||
1867 | if (reason & B43_IRQ_TX_OK) | 1823 | if (reason & B43_IRQ_TX_OK) |
1868 | handle_irq_transmit_status(dev); | 1824 | handle_irq_transmit_status(dev); |
1869 | 1825 | ||
1826 | /* Re-enable interrupts on the device by restoring the current interrupt mask. */ | ||
1870 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); | 1827 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); |
1871 | mmiowb(); | ||
1872 | spin_unlock_irqrestore(&dev->wl->irq_lock, flags); | ||
1873 | } | 1828 | } |
1874 | 1829 | ||
1875 | static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason) | 1830 | /* Interrupt thread handler. Handles device interrupts in thread context. */ |
1831 | static irqreturn_t b43_interrupt_thread_handler(int irq, void *dev_id) | ||
1876 | { | 1832 | { |
1877 | b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); | 1833 | struct b43_wldev *dev = dev_id; |
1878 | 1834 | ||
1879 | b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); | 1835 | mutex_lock(&dev->wl->mutex); |
1880 | b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]); | 1836 | b43_do_interrupt_thread(dev); |
1881 | b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); | 1837 | mmiowb(); |
1882 | b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); | 1838 | mutex_unlock(&dev->wl->mutex); |
1883 | b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); | 1839 | |
1884 | /* Unused ring | 1840 | return IRQ_HANDLED; |
1885 | b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); | ||
1886 | */ | ||
1887 | } | 1841 | } |
1888 | 1842 | ||
1889 | /* Interrupt handler top-half */ | 1843 | static irqreturn_t b43_do_interrupt(struct b43_wldev *dev) |
1890 | static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) | ||
1891 | { | 1844 | { |
1892 | irqreturn_t ret = IRQ_NONE; | ||
1893 | struct b43_wldev *dev = dev_id; | ||
1894 | u32 reason; | 1845 | u32 reason; |
1895 | 1846 | ||
1896 | B43_WARN_ON(!dev); | 1847 | /* This code runs under wl->hardirq_lock, but _only_ on non-SDIO busses. |
1848 | * On SDIO, this runs under wl->mutex. */ | ||
1897 | 1849 | ||
1898 | spin_lock(&dev->wl->irq_lock); | ||
1899 | |||
1900 | if (unlikely(b43_status(dev) < B43_STAT_STARTED)) { | ||
1901 | /* This can only happen on shared IRQ lines. */ | ||
1902 | goto out; | ||
1903 | } | ||
1904 | reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); | 1850 | reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); |
1905 | if (reason == 0xffffffff) /* shared IRQ */ | 1851 | if (reason == 0xffffffff) /* shared IRQ */ |
1906 | goto out; | 1852 | return IRQ_NONE; |
1907 | ret = IRQ_HANDLED; | ||
1908 | reason &= dev->irq_mask; | 1853 | reason &= dev->irq_mask; |
1909 | if (!reason) | 1854 | if (!reason) |
1910 | goto out; | 1855 | return IRQ_HANDLED; |
1911 | 1856 | ||
1912 | dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON) | 1857 | dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON) |
1913 | & 0x0001DC00; | 1858 | & 0x0001DC00; |
@@ -1924,15 +1869,38 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) | |||
1924 | & 0x0000DC00; | 1869 | & 0x0000DC00; |
1925 | */ | 1870 | */ |
1926 | 1871 | ||
1927 | b43_interrupt_ack(dev, reason); | 1872 | /* ACK the interrupt. */ |
1928 | /* disable all IRQs. They are enabled again in the bottom half. */ | 1873 | b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); |
1874 | b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); | ||
1875 | b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]); | ||
1876 | b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); | ||
1877 | b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); | ||
1878 | b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); | ||
1879 | /* Unused ring | ||
1880 | b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); | ||
1881 | */ | ||
1882 | |||
1883 | /* Disable IRQs on the device. The IRQ thread handler will re-enable them. */ | ||
1929 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); | 1884 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); |
1930 | /* save the reason code and call our bottom half. */ | 1885 | /* Save the reason bitmasks for the IRQ thread handler. */ |
1931 | dev->irq_reason = reason; | 1886 | dev->irq_reason = reason; |
1932 | tasklet_schedule(&dev->isr_tasklet); | 1887 | |
1933 | out: | 1888 | return IRQ_WAKE_THREAD; |
1889 | } | ||
1890 | |||
1891 | /* Interrupt handler top-half. This runs with interrupts disabled. */ | ||
1892 | static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) | ||
1893 | { | ||
1894 | struct b43_wldev *dev = dev_id; | ||
1895 | irqreturn_t ret; | ||
1896 | |||
1897 | if (unlikely(b43_status(dev) < B43_STAT_STARTED)) | ||
1898 | return IRQ_NONE; | ||
1899 | |||
1900 | spin_lock(&dev->wl->hardirq_lock); | ||
1901 | ret = b43_do_interrupt(dev); | ||
1934 | mmiowb(); | 1902 | mmiowb(); |
1935 | spin_unlock(&dev->wl->irq_lock); | 1903 | spin_unlock(&dev->wl->hardirq_lock); |
1936 | 1904 | ||
1937 | return ret; | 1905 | return ret; |
1938 | } | 1906 | } |
@@ -3038,15 +3006,12 @@ static void b43_security_init(struct b43_wldev *dev) | |||
3038 | static int b43_rng_read(struct hwrng *rng, u32 *data) | 3006 | static int b43_rng_read(struct hwrng *rng, u32 *data) |
3039 | { | 3007 | { |
3040 | struct b43_wl *wl = (struct b43_wl *)rng->priv; | 3008 | struct b43_wl *wl = (struct b43_wl *)rng->priv; |
3041 | unsigned long flags; | ||
3042 | 3009 | ||
3043 | /* Don't take wl->mutex here, as it could deadlock with | 3010 | /* FIXME: We need to take wl->mutex here to make sure the device |
3044 | * hwrng internal locking. It's not needed to take | 3011 | * is not going away from under our ass. However it could deadlock |
3045 | * wl->mutex here, anyway. */ | 3012 | * with hwrng internal locking. */ |
3046 | 3013 | ||
3047 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3048 | *data = b43_read16(wl->current_dev, B43_MMIO_RNG); | 3014 | *data = b43_read16(wl->current_dev, B43_MMIO_RNG); |
3049 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3050 | 3015 | ||
3051 | return (sizeof(u16)); | 3016 | return (sizeof(u16)); |
3052 | } | 3017 | } |
@@ -3082,46 +3047,52 @@ static int b43_rng_init(struct b43_wl *wl) | |||
3082 | return err; | 3047 | return err; |
3083 | } | 3048 | } |
3084 | 3049 | ||
3085 | static int b43_op_tx(struct ieee80211_hw *hw, | 3050 | static void b43_tx_work(struct work_struct *work) |
3086 | struct sk_buff *skb) | ||
3087 | { | 3051 | { |
3088 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3052 | struct b43_wl *wl = container_of(work, struct b43_wl, tx_work); |
3089 | struct b43_wldev *dev = wl->current_dev; | 3053 | struct b43_wldev *dev; |
3090 | unsigned long flags; | 3054 | struct sk_buff *skb; |
3091 | int err; | 3055 | int err = 0; |
3092 | 3056 | ||
3093 | if (unlikely(skb->len < 2 + 2 + 6)) { | 3057 | mutex_lock(&wl->mutex); |
3094 | /* Too short, this can't be a valid frame. */ | 3058 | dev = wl->current_dev; |
3095 | goto drop_packet; | 3059 | if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED)) { |
3060 | mutex_unlock(&wl->mutex); | ||
3061 | return; | ||
3096 | } | 3062 | } |
3097 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); | ||
3098 | if (unlikely(!dev)) | ||
3099 | goto drop_packet; | ||
3100 | 3063 | ||
3101 | /* Transmissions on seperate queues can run concurrently. */ | 3064 | while (skb_queue_len(&wl->tx_queue)) { |
3102 | read_lock_irqsave(&wl->tx_lock, flags); | 3065 | skb = skb_dequeue(&wl->tx_queue); |
3103 | 3066 | ||
3104 | err = -ENODEV; | ||
3105 | if (likely(b43_status(dev) >= B43_STAT_STARTED)) { | ||
3106 | if (b43_using_pio_transfers(dev)) | 3067 | if (b43_using_pio_transfers(dev)) |
3107 | err = b43_pio_tx(dev, skb); | 3068 | err = b43_pio_tx(dev, skb); |
3108 | else | 3069 | else |
3109 | err = b43_dma_tx(dev, skb); | 3070 | err = b43_dma_tx(dev, skb); |
3071 | if (unlikely(err)) | ||
3072 | dev_kfree_skb(skb); /* Drop it */ | ||
3110 | } | 3073 | } |
3111 | 3074 | ||
3112 | read_unlock_irqrestore(&wl->tx_lock, flags); | 3075 | mutex_unlock(&wl->mutex); |
3076 | } | ||
3113 | 3077 | ||
3114 | if (unlikely(err)) | 3078 | static int b43_op_tx(struct ieee80211_hw *hw, |
3115 | goto drop_packet; | 3079 | struct sk_buff *skb) |
3116 | return NETDEV_TX_OK; | 3080 | { |
3081 | struct b43_wl *wl = hw_to_b43_wl(hw); | ||
3082 | |||
3083 | if (unlikely(skb->len < 2 + 2 + 6)) { | ||
3084 | /* Too short, this can't be a valid frame. */ | ||
3085 | dev_kfree_skb_any(skb); | ||
3086 | return NETDEV_TX_OK; | ||
3087 | } | ||
3088 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); | ||
3089 | |||
3090 | skb_queue_tail(&wl->tx_queue, skb); | ||
3091 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
3117 | 3092 | ||
3118 | drop_packet: | ||
3119 | /* We can not transmit this packet. Drop it. */ | ||
3120 | dev_kfree_skb_any(skb); | ||
3121 | return NETDEV_TX_OK; | 3093 | return NETDEV_TX_OK; |
3122 | } | 3094 | } |
3123 | 3095 | ||
3124 | /* Locking: wl->irq_lock */ | ||
3125 | static void b43_qos_params_upload(struct b43_wldev *dev, | 3096 | static void b43_qos_params_upload(struct b43_wldev *dev, |
3126 | const struct ieee80211_tx_queue_params *p, | 3097 | const struct ieee80211_tx_queue_params *p, |
3127 | u16 shm_offset) | 3098 | u16 shm_offset) |
@@ -3130,6 +3101,9 @@ static void b43_qos_params_upload(struct b43_wldev *dev, | |||
3130 | int bslots, tmp; | 3101 | int bslots, tmp; |
3131 | unsigned int i; | 3102 | unsigned int i; |
3132 | 3103 | ||
3104 | if (!dev->qos_enabled) | ||
3105 | return; | ||
3106 | |||
3133 | bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min; | 3107 | bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min; |
3134 | 3108 | ||
3135 | memset(¶ms, 0, sizeof(params)); | 3109 | memset(¶ms, 0, sizeof(params)); |
@@ -3175,6 +3149,9 @@ static void b43_qos_upload_all(struct b43_wldev *dev) | |||
3175 | struct b43_qos_params *params; | 3149 | struct b43_qos_params *params; |
3176 | unsigned int i; | 3150 | unsigned int i; |
3177 | 3151 | ||
3152 | if (!dev->qos_enabled) | ||
3153 | return; | ||
3154 | |||
3178 | BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != | 3155 | BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != |
3179 | ARRAY_SIZE(wl->qos_params)); | 3156 | ARRAY_SIZE(wl->qos_params)); |
3180 | 3157 | ||
@@ -3234,6 +3211,16 @@ static void b43_qos_clear(struct b43_wl *wl) | |||
3234 | /* Initialize the core's QOS capabilities */ | 3211 | /* Initialize the core's QOS capabilities */ |
3235 | static void b43_qos_init(struct b43_wldev *dev) | 3212 | static void b43_qos_init(struct b43_wldev *dev) |
3236 | { | 3213 | { |
3214 | if (!dev->qos_enabled) { | ||
3215 | /* Disable QOS support. */ | ||
3216 | b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_EDCF); | ||
3217 | b43_write16(dev, B43_MMIO_IFSCTL, | ||
3218 | b43_read16(dev, B43_MMIO_IFSCTL) | ||
3219 | & ~B43_MMIO_IFSCTL_USE_EDCF); | ||
3220 | b43dbg(dev->wl, "QoS disabled\n"); | ||
3221 | return; | ||
3222 | } | ||
3223 | |||
3237 | /* Upload the current QOS parameters. */ | 3224 | /* Upload the current QOS parameters. */ |
3238 | b43_qos_upload_all(dev); | 3225 | b43_qos_upload_all(dev); |
3239 | 3226 | ||
@@ -3242,6 +3229,7 @@ static void b43_qos_init(struct b43_wldev *dev) | |||
3242 | b43_write16(dev, B43_MMIO_IFSCTL, | 3229 | b43_write16(dev, B43_MMIO_IFSCTL, |
3243 | b43_read16(dev, B43_MMIO_IFSCTL) | 3230 | b43_read16(dev, B43_MMIO_IFSCTL) |
3244 | | B43_MMIO_IFSCTL_USE_EDCF); | 3231 | | B43_MMIO_IFSCTL_USE_EDCF); |
3232 | b43dbg(dev->wl, "QoS enabled\n"); | ||
3245 | } | 3233 | } |
3246 | 3234 | ||
3247 | static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, | 3235 | static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, |
@@ -3283,22 +3271,20 @@ static int b43_op_get_tx_stats(struct ieee80211_hw *hw, | |||
3283 | struct ieee80211_tx_queue_stats *stats) | 3271 | struct ieee80211_tx_queue_stats *stats) |
3284 | { | 3272 | { |
3285 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3273 | struct b43_wl *wl = hw_to_b43_wl(hw); |
3286 | struct b43_wldev *dev = wl->current_dev; | 3274 | struct b43_wldev *dev; |
3287 | unsigned long flags; | ||
3288 | int err = -ENODEV; | 3275 | int err = -ENODEV; |
3289 | 3276 | ||
3290 | if (!dev) | 3277 | mutex_lock(&wl->mutex); |
3291 | goto out; | 3278 | dev = wl->current_dev; |
3292 | spin_lock_irqsave(&wl->irq_lock, flags); | 3279 | if (dev && b43_status(dev) >= B43_STAT_STARTED) { |
3293 | if (likely(b43_status(dev) >= B43_STAT_STARTED)) { | ||
3294 | if (b43_using_pio_transfers(dev)) | 3280 | if (b43_using_pio_transfers(dev)) |
3295 | b43_pio_get_tx_stats(dev, stats); | 3281 | b43_pio_get_tx_stats(dev, stats); |
3296 | else | 3282 | else |
3297 | b43_dma_get_tx_stats(dev, stats); | 3283 | b43_dma_get_tx_stats(dev, stats); |
3298 | err = 0; | 3284 | err = 0; |
3299 | } | 3285 | } |
3300 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 3286 | mutex_unlock(&wl->mutex); |
3301 | out: | 3287 | |
3302 | return err; | 3288 | return err; |
3303 | } | 3289 | } |
3304 | 3290 | ||
@@ -3306,11 +3292,10 @@ static int b43_op_get_stats(struct ieee80211_hw *hw, | |||
3306 | struct ieee80211_low_level_stats *stats) | 3292 | struct ieee80211_low_level_stats *stats) |
3307 | { | 3293 | { |
3308 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3294 | struct b43_wl *wl = hw_to_b43_wl(hw); |
3309 | unsigned long flags; | ||
3310 | 3295 | ||
3311 | spin_lock_irqsave(&wl->irq_lock, flags); | 3296 | mutex_lock(&wl->mutex); |
3312 | memcpy(stats, &wl->ieee_stats, sizeof(*stats)); | 3297 | memcpy(stats, &wl->ieee_stats, sizeof(*stats)); |
3313 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 3298 | mutex_unlock(&wl->mutex); |
3314 | 3299 | ||
3315 | return 0; | 3300 | return 0; |
3316 | } | 3301 | } |
@@ -3322,7 +3307,6 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw) | |||
3322 | u64 tsf; | 3307 | u64 tsf; |
3323 | 3308 | ||
3324 | mutex_lock(&wl->mutex); | 3309 | mutex_lock(&wl->mutex); |
3325 | spin_lock_irq(&wl->irq_lock); | ||
3326 | dev = wl->current_dev; | 3310 | dev = wl->current_dev; |
3327 | 3311 | ||
3328 | if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) | 3312 | if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) |
@@ -3330,7 +3314,6 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw) | |||
3330 | else | 3314 | else |
3331 | tsf = 0; | 3315 | tsf = 0; |
3332 | 3316 | ||
3333 | spin_unlock_irq(&wl->irq_lock); | ||
3334 | mutex_unlock(&wl->mutex); | 3317 | mutex_unlock(&wl->mutex); |
3335 | 3318 | ||
3336 | return tsf; | 3319 | return tsf; |
@@ -3342,13 +3325,11 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) | |||
3342 | struct b43_wldev *dev; | 3325 | struct b43_wldev *dev; |
3343 | 3326 | ||
3344 | mutex_lock(&wl->mutex); | 3327 | mutex_lock(&wl->mutex); |
3345 | spin_lock_irq(&wl->irq_lock); | ||
3346 | dev = wl->current_dev; | 3328 | dev = wl->current_dev; |
3347 | 3329 | ||
3348 | if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) | 3330 | if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) |
3349 | b43_tsf_write(dev, tsf); | 3331 | b43_tsf_write(dev, tsf); |
3350 | 3332 | ||
3351 | spin_unlock_irq(&wl->irq_lock); | ||
3352 | mutex_unlock(&wl->mutex); | 3333 | mutex_unlock(&wl->mutex); |
3353 | } | 3334 | } |
3354 | 3335 | ||
@@ -3434,7 +3415,7 @@ static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan) | |||
3434 | prev_status = b43_status(down_dev); | 3415 | prev_status = b43_status(down_dev); |
3435 | /* Shutdown the currently running core. */ | 3416 | /* Shutdown the currently running core. */ |
3436 | if (prev_status >= B43_STAT_STARTED) | 3417 | if (prev_status >= B43_STAT_STARTED) |
3437 | b43_wireless_core_stop(down_dev); | 3418 | down_dev = b43_wireless_core_stop(down_dev); |
3438 | if (prev_status >= B43_STAT_INITIALIZED) | 3419 | if (prev_status >= B43_STAT_INITIALIZED) |
3439 | b43_wireless_core_exit(down_dev); | 3420 | b43_wireless_core_exit(down_dev); |
3440 | 3421 | ||
@@ -3498,7 +3479,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) | |||
3498 | struct b43_wldev *dev; | 3479 | struct b43_wldev *dev; |
3499 | struct b43_phy *phy; | 3480 | struct b43_phy *phy; |
3500 | struct ieee80211_conf *conf = &hw->conf; | 3481 | struct ieee80211_conf *conf = &hw->conf; |
3501 | unsigned long flags; | ||
3502 | int antenna; | 3482 | int antenna; |
3503 | int err = 0; | 3483 | int err = 0; |
3504 | 3484 | ||
@@ -3529,13 +3509,11 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) | |||
3529 | 3509 | ||
3530 | /* Adjust the desired TX power level. */ | 3510 | /* Adjust the desired TX power level. */ |
3531 | if (conf->power_level != 0) { | 3511 | if (conf->power_level != 0) { |
3532 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3533 | if (conf->power_level != phy->desired_txpower) { | 3512 | if (conf->power_level != phy->desired_txpower) { |
3534 | phy->desired_txpower = conf->power_level; | 3513 | phy->desired_txpower = conf->power_level; |
3535 | b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME | | 3514 | b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME | |
3536 | B43_TXPWR_IGNORE_TSSI); | 3515 | B43_TXPWR_IGNORE_TSSI); |
3537 | } | 3516 | } |
3538 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3539 | } | 3517 | } |
3540 | 3518 | ||
3541 | /* Antennas for RX and management frame TX. */ | 3519 | /* Antennas for RX and management frame TX. */ |
@@ -3620,7 +3598,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, | |||
3620 | { | 3598 | { |
3621 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3599 | struct b43_wl *wl = hw_to_b43_wl(hw); |
3622 | struct b43_wldev *dev; | 3600 | struct b43_wldev *dev; |
3623 | unsigned long flags; | ||
3624 | 3601 | ||
3625 | mutex_lock(&wl->mutex); | 3602 | mutex_lock(&wl->mutex); |
3626 | 3603 | ||
@@ -3630,7 +3607,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, | |||
3630 | 3607 | ||
3631 | B43_WARN_ON(wl->vif != vif); | 3608 | B43_WARN_ON(wl->vif != vif); |
3632 | 3609 | ||
3633 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3634 | if (changed & BSS_CHANGED_BSSID) { | 3610 | if (changed & BSS_CHANGED_BSSID) { |
3635 | if (conf->bssid) | 3611 | if (conf->bssid) |
3636 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); | 3612 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); |
@@ -3648,7 +3624,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, | |||
3648 | if (changed & BSS_CHANGED_BSSID) | 3624 | if (changed & BSS_CHANGED_BSSID) |
3649 | b43_write_mac_bssid_templates(dev); | 3625 | b43_write_mac_bssid_templates(dev); |
3650 | } | 3626 | } |
3651 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3652 | 3627 | ||
3653 | b43_mac_suspend(dev); | 3628 | b43_mac_suspend(dev); |
3654 | 3629 | ||
@@ -3689,15 +3664,6 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3689 | return -ENOSPC; /* User disabled HW-crypto */ | 3664 | return -ENOSPC; /* User disabled HW-crypto */ |
3690 | 3665 | ||
3691 | mutex_lock(&wl->mutex); | 3666 | mutex_lock(&wl->mutex); |
3692 | spin_lock_irq(&wl->irq_lock); | ||
3693 | write_lock(&wl->tx_lock); | ||
3694 | /* Why do we need all this locking here? | ||
3695 | * mutex -> Every config operation must take it. | ||
3696 | * irq_lock -> We modify the dev->key array, which is accessed | ||
3697 | * in the IRQ handlers. | ||
3698 | * tx_lock -> We modify the dev->key array, which is accessed | ||
3699 | * in the TX handler. | ||
3700 | */ | ||
3701 | 3667 | ||
3702 | dev = wl->current_dev; | 3668 | dev = wl->current_dev; |
3703 | err = -ENODEV; | 3669 | err = -ENODEV; |
@@ -3789,8 +3755,6 @@ out_unlock: | |||
3789 | sta ? sta->addr : bcast_addr); | 3755 | sta ? sta->addr : bcast_addr); |
3790 | b43_dump_keymemory(dev); | 3756 | b43_dump_keymemory(dev); |
3791 | } | 3757 | } |
3792 | write_unlock(&wl->tx_lock); | ||
3793 | spin_unlock_irq(&wl->irq_lock); | ||
3794 | mutex_unlock(&wl->mutex); | 3758 | mutex_unlock(&wl->mutex); |
3795 | 3759 | ||
3796 | return err; | 3760 | return err; |
@@ -3801,15 +3765,15 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw, | |||
3801 | u64 multicast) | 3765 | u64 multicast) |
3802 | { | 3766 | { |
3803 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3767 | struct b43_wl *wl = hw_to_b43_wl(hw); |
3804 | struct b43_wldev *dev = wl->current_dev; | 3768 | struct b43_wldev *dev; |
3805 | unsigned long flags; | ||
3806 | 3769 | ||
3770 | mutex_lock(&wl->mutex); | ||
3771 | dev = wl->current_dev; | ||
3807 | if (!dev) { | 3772 | if (!dev) { |
3808 | *fflags = 0; | 3773 | *fflags = 0; |
3809 | return; | 3774 | goto out_unlock; |
3810 | } | 3775 | } |
3811 | 3776 | ||
3812 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3813 | *fflags &= FIF_PROMISC_IN_BSS | | 3777 | *fflags &= FIF_PROMISC_IN_BSS | |
3814 | FIF_ALLMULTI | | 3778 | FIF_ALLMULTI | |
3815 | FIF_FCSFAIL | | 3779 | FIF_FCSFAIL | |
@@ -3830,41 +3794,70 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw, | |||
3830 | 3794 | ||
3831 | if (changed && b43_status(dev) >= B43_STAT_INITIALIZED) | 3795 | if (changed && b43_status(dev) >= B43_STAT_INITIALIZED) |
3832 | b43_adjust_opmode(dev); | 3796 | b43_adjust_opmode(dev); |
3833 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 3797 | |
3798 | out_unlock: | ||
3799 | mutex_unlock(&wl->mutex); | ||
3834 | } | 3800 | } |
3835 | 3801 | ||
3836 | /* Locking: wl->mutex */ | 3802 | /* Locking: wl->mutex |
3837 | static void b43_wireless_core_stop(struct b43_wldev *dev) | 3803 | * Returns the current dev. This might be different from the passed in dev, |
3804 | * because the core might be gone away while we unlocked the mutex. */ | ||
3805 | static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev) | ||
3838 | { | 3806 | { |
3839 | struct b43_wl *wl = dev->wl; | 3807 | struct b43_wl *wl = dev->wl; |
3840 | unsigned long flags; | 3808 | struct b43_wldev *orig_dev; |
3841 | 3809 | ||
3842 | if (b43_status(dev) < B43_STAT_STARTED) | 3810 | redo: |
3843 | return; | 3811 | if (!dev || b43_status(dev) < B43_STAT_STARTED) |
3812 | return dev; | ||
3844 | 3813 | ||
3845 | /* Disable and sync interrupts. We must do this before than | 3814 | /* Cancel work. Unlock to avoid deadlocks. */ |
3846 | * setting the status to INITIALIZED, as the interrupt handler | 3815 | mutex_unlock(&wl->mutex); |
3847 | * won't care about IRQs then. */ | 3816 | cancel_delayed_work_sync(&dev->periodic_work); |
3848 | spin_lock_irqsave(&wl->irq_lock, flags); | 3817 | cancel_work_sync(&wl->tx_work); |
3849 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); | 3818 | mutex_lock(&wl->mutex); |
3850 | b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */ | 3819 | dev = wl->current_dev; |
3851 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 3820 | if (!dev || b43_status(dev) < B43_STAT_STARTED) { |
3852 | b43_synchronize_irq(dev); | 3821 | /* Whoops, aliens ate up the device while we were unlocked. */ |
3822 | return dev; | ||
3823 | } | ||
3853 | 3824 | ||
3854 | write_lock_irqsave(&wl->tx_lock, flags); | 3825 | /* Disable interrupts on the device. */ |
3855 | b43_set_status(dev, B43_STAT_INITIALIZED); | 3826 | b43_set_status(dev, B43_STAT_INITIALIZED); |
3856 | write_unlock_irqrestore(&wl->tx_lock, flags); | 3827 | if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { |
3857 | 3828 | /* wl->mutex is locked. That is enough. */ | |
3858 | b43_pio_stop(dev); | 3829 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); |
3830 | b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ | ||
3831 | } else { | ||
3832 | spin_lock_irq(&wl->hardirq_lock); | ||
3833 | b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); | ||
3834 | b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ | ||
3835 | spin_unlock_irq(&wl->hardirq_lock); | ||
3836 | } | ||
3837 | /* Synchronize the interrupt handlers. Unlock to avoid deadlocks. */ | ||
3838 | orig_dev = dev; | ||
3859 | mutex_unlock(&wl->mutex); | 3839 | mutex_unlock(&wl->mutex); |
3860 | /* Must unlock as it would otherwise deadlock. No races here. | 3840 | synchronize_irq(dev->dev->irq); |
3861 | * Cancel the possibly running self-rearming periodic work. */ | ||
3862 | cancel_delayed_work_sync(&dev->periodic_work); | ||
3863 | mutex_lock(&wl->mutex); | 3841 | mutex_lock(&wl->mutex); |
3842 | dev = wl->current_dev; | ||
3843 | if (!dev) | ||
3844 | return dev; | ||
3845 | if (dev != orig_dev) { | ||
3846 | if (b43_status(dev) >= B43_STAT_STARTED) | ||
3847 | goto redo; | ||
3848 | return dev; | ||
3849 | } | ||
3850 | B43_WARN_ON(b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)); | ||
3851 | |||
3852 | /* Drain the TX queue */ | ||
3853 | while (skb_queue_len(&wl->tx_queue)) | ||
3854 | dev_kfree_skb(skb_dequeue(&wl->tx_queue)); | ||
3864 | 3855 | ||
3865 | b43_mac_suspend(dev); | 3856 | b43_mac_suspend(dev); |
3866 | free_irq(dev->dev->irq, dev); | 3857 | free_irq(dev->dev->irq, dev); |
3867 | b43dbg(wl, "Wireless interface stopped\n"); | 3858 | b43dbg(wl, "Wireless interface stopped\n"); |
3859 | |||
3860 | return dev; | ||
3868 | } | 3861 | } |
3869 | 3862 | ||
3870 | /* Locking: wl->mutex */ | 3863 | /* Locking: wl->mutex */ |
@@ -3875,8 +3868,9 @@ static int b43_wireless_core_start(struct b43_wldev *dev) | |||
3875 | B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED); | 3868 | B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED); |
3876 | 3869 | ||
3877 | drain_txstatus_queue(dev); | 3870 | drain_txstatus_queue(dev); |
3878 | err = request_irq(dev->dev->irq, b43_interrupt_handler, | 3871 | err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler, |
3879 | IRQF_SHARED, KBUILD_MODNAME, dev); | 3872 | b43_interrupt_thread_handler, |
3873 | IRQF_SHARED, KBUILD_MODNAME, dev); | ||
3880 | if (err) { | 3874 | if (err) { |
3881 | b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); | 3875 | b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); |
3882 | goto out; | 3876 | goto out; |
@@ -4098,16 +4092,20 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) | |||
4098 | bus->pcicore.dev->id.revision <= 5) { | 4092 | bus->pcicore.dev->id.revision <= 5) { |
4099 | /* IMCFGLO timeouts workaround. */ | 4093 | /* IMCFGLO timeouts workaround. */ |
4100 | tmp = ssb_read32(dev->dev, SSB_IMCFGLO); | 4094 | tmp = ssb_read32(dev->dev, SSB_IMCFGLO); |
4101 | tmp &= ~SSB_IMCFGLO_REQTO; | ||
4102 | tmp &= ~SSB_IMCFGLO_SERTO; | ||
4103 | switch (bus->bustype) { | 4095 | switch (bus->bustype) { |
4104 | case SSB_BUSTYPE_PCI: | 4096 | case SSB_BUSTYPE_PCI: |
4105 | case SSB_BUSTYPE_PCMCIA: | 4097 | case SSB_BUSTYPE_PCMCIA: |
4098 | tmp &= ~SSB_IMCFGLO_REQTO; | ||
4099 | tmp &= ~SSB_IMCFGLO_SERTO; | ||
4106 | tmp |= 0x32; | 4100 | tmp |= 0x32; |
4107 | break; | 4101 | break; |
4108 | case SSB_BUSTYPE_SSB: | 4102 | case SSB_BUSTYPE_SSB: |
4103 | tmp &= ~SSB_IMCFGLO_REQTO; | ||
4104 | tmp &= ~SSB_IMCFGLO_SERTO; | ||
4109 | tmp |= 0x53; | 4105 | tmp |= 0x53; |
4110 | break; | 4106 | break; |
4107 | default: | ||
4108 | break; | ||
4111 | } | 4109 | } |
4112 | ssb_write32(dev->dev, SSB_IMCFGLO, tmp); | 4110 | ssb_write32(dev->dev, SSB_IMCFGLO, tmp); |
4113 | } | 4111 | } |
@@ -4155,8 +4153,8 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) | |||
4155 | { | 4153 | { |
4156 | u32 macctl; | 4154 | u32 macctl; |
4157 | 4155 | ||
4158 | B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED); | 4156 | B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED); |
4159 | if (b43_status(dev) != B43_STAT_INITIALIZED) | 4157 | if (!dev || b43_status(dev) != B43_STAT_INITIALIZED) |
4160 | return; | 4158 | return; |
4161 | b43_set_status(dev, B43_STAT_UNINIT); | 4159 | b43_set_status(dev, B43_STAT_UNINIT); |
4162 | 4160 | ||
@@ -4309,7 +4307,6 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, | |||
4309 | { | 4307 | { |
4310 | struct b43_wl *wl = hw_to_b43_wl(hw); | 4308 | struct b43_wl *wl = hw_to_b43_wl(hw); |
4311 | struct b43_wldev *dev; | 4309 | struct b43_wldev *dev; |
4312 | unsigned long flags; | ||
4313 | int err = -EOPNOTSUPP; | 4310 | int err = -EOPNOTSUPP; |
4314 | 4311 | ||
4315 | /* TODO: allow WDS/AP devices to coexist */ | 4312 | /* TODO: allow WDS/AP devices to coexist */ |
@@ -4333,12 +4330,10 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, | |||
4333 | wl->if_type = conf->type; | 4330 | wl->if_type = conf->type; |
4334 | memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); | 4331 | memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); |
4335 | 4332 | ||
4336 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
4337 | b43_adjust_opmode(dev); | 4333 | b43_adjust_opmode(dev); |
4338 | b43_set_pretbtt(dev); | 4334 | b43_set_pretbtt(dev); |
4339 | b43_set_synth_pu_delay(dev, 0); | 4335 | b43_set_synth_pu_delay(dev, 0); |
4340 | b43_upload_card_macaddress(dev); | 4336 | b43_upload_card_macaddress(dev); |
4341 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
4342 | 4337 | ||
4343 | err = 0; | 4338 | err = 0; |
4344 | out_mutex_unlock: | 4339 | out_mutex_unlock: |
@@ -4352,7 +4347,6 @@ static void b43_op_remove_interface(struct ieee80211_hw *hw, | |||
4352 | { | 4347 | { |
4353 | struct b43_wl *wl = hw_to_b43_wl(hw); | 4348 | struct b43_wl *wl = hw_to_b43_wl(hw); |
4354 | struct b43_wldev *dev = wl->current_dev; | 4349 | struct b43_wldev *dev = wl->current_dev; |
4355 | unsigned long flags; | ||
4356 | 4350 | ||
4357 | b43dbg(wl, "Removing Interface type %d\n", conf->type); | 4351 | b43dbg(wl, "Removing Interface type %d\n", conf->type); |
4358 | 4352 | ||
@@ -4364,11 +4358,9 @@ static void b43_op_remove_interface(struct ieee80211_hw *hw, | |||
4364 | 4358 | ||
4365 | wl->operating = 0; | 4359 | wl->operating = 0; |
4366 | 4360 | ||
4367 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
4368 | b43_adjust_opmode(dev); | 4361 | b43_adjust_opmode(dev); |
4369 | memset(wl->mac_addr, 0, ETH_ALEN); | 4362 | memset(wl->mac_addr, 0, ETH_ALEN); |
4370 | b43_upload_card_macaddress(dev); | 4363 | b43_upload_card_macaddress(dev); |
4371 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
4372 | 4364 | ||
4373 | mutex_unlock(&wl->mutex); | 4365 | mutex_unlock(&wl->mutex); |
4374 | } | 4366 | } |
@@ -4428,10 +4420,15 @@ static void b43_op_stop(struct ieee80211_hw *hw) | |||
4428 | cancel_work_sync(&(wl->beacon_update_trigger)); | 4420 | cancel_work_sync(&(wl->beacon_update_trigger)); |
4429 | 4421 | ||
4430 | mutex_lock(&wl->mutex); | 4422 | mutex_lock(&wl->mutex); |
4431 | if (b43_status(dev) >= B43_STAT_STARTED) | 4423 | if (b43_status(dev) >= B43_STAT_STARTED) { |
4432 | b43_wireless_core_stop(dev); | 4424 | dev = b43_wireless_core_stop(dev); |
4425 | if (!dev) | ||
4426 | goto out_unlock; | ||
4427 | } | ||
4433 | b43_wireless_core_exit(dev); | 4428 | b43_wireless_core_exit(dev); |
4434 | wl->radio_enabled = 0; | 4429 | wl->radio_enabled = 0; |
4430 | |||
4431 | out_unlock: | ||
4435 | mutex_unlock(&wl->mutex); | 4432 | mutex_unlock(&wl->mutex); |
4436 | 4433 | ||
4437 | cancel_work_sync(&(wl->txpower_adjust_work)); | 4434 | cancel_work_sync(&(wl->txpower_adjust_work)); |
@@ -4441,11 +4438,10 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, | |||
4441 | struct ieee80211_sta *sta, bool set) | 4438 | struct ieee80211_sta *sta, bool set) |
4442 | { | 4439 | { |
4443 | struct b43_wl *wl = hw_to_b43_wl(hw); | 4440 | struct b43_wl *wl = hw_to_b43_wl(hw); |
4444 | unsigned long flags; | ||
4445 | 4441 | ||
4446 | spin_lock_irqsave(&wl->irq_lock, flags); | 4442 | mutex_lock(&wl->mutex); |
4447 | b43_update_templates(wl); | 4443 | b43_update_templates(wl); |
4448 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 4444 | mutex_unlock(&wl->mutex); |
4449 | 4445 | ||
4450 | return 0; | 4446 | return 0; |
4451 | } | 4447 | } |
@@ -4526,8 +4522,13 @@ static void b43_chip_reset(struct work_struct *work) | |||
4526 | 4522 | ||
4527 | prev_status = b43_status(dev); | 4523 | prev_status = b43_status(dev); |
4528 | /* Bring the device down... */ | 4524 | /* Bring the device down... */ |
4529 | if (prev_status >= B43_STAT_STARTED) | 4525 | if (prev_status >= B43_STAT_STARTED) { |
4530 | b43_wireless_core_stop(dev); | 4526 | dev = b43_wireless_core_stop(dev); |
4527 | if (!dev) { | ||
4528 | err = -ENODEV; | ||
4529 | goto out; | ||
4530 | } | ||
4531 | } | ||
4531 | if (prev_status >= B43_STAT_INITIALIZED) | 4532 | if (prev_status >= B43_STAT_INITIALIZED) |
4532 | b43_wireless_core_exit(dev); | 4533 | b43_wireless_core_exit(dev); |
4533 | 4534 | ||
@@ -4742,9 +4743,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) | |||
4742 | wldev->wl = wl; | 4743 | wldev->wl = wl; |
4743 | b43_set_status(wldev, B43_STAT_UNINIT); | 4744 | b43_set_status(wldev, B43_STAT_UNINIT); |
4744 | wldev->bad_frames_preempt = modparam_bad_frames_preempt; | 4745 | wldev->bad_frames_preempt = modparam_bad_frames_preempt; |
4745 | tasklet_init(&wldev->isr_tasklet, | ||
4746 | (void (*)(unsigned long))b43_interrupt_tasklet, | ||
4747 | (unsigned long)wldev); | ||
4748 | INIT_LIST_HEAD(&wldev->list); | 4746 | INIT_LIST_HEAD(&wldev->list); |
4749 | 4747 | ||
4750 | err = b43_wireless_core_attach(wldev); | 4748 | err = b43_wireless_core_attach(wldev); |
@@ -4841,14 +4839,14 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4841 | 4839 | ||
4842 | /* Initialize struct b43_wl */ | 4840 | /* Initialize struct b43_wl */ |
4843 | wl->hw = hw; | 4841 | wl->hw = hw; |
4844 | spin_lock_init(&wl->irq_lock); | ||
4845 | rwlock_init(&wl->tx_lock); | ||
4846 | spin_lock_init(&wl->leds_lock); | 4842 | spin_lock_init(&wl->leds_lock); |
4847 | spin_lock_init(&wl->shm_lock); | ||
4848 | mutex_init(&wl->mutex); | 4843 | mutex_init(&wl->mutex); |
4844 | spin_lock_init(&wl->hardirq_lock); | ||
4849 | INIT_LIST_HEAD(&wl->devlist); | 4845 | INIT_LIST_HEAD(&wl->devlist); |
4850 | INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); | 4846 | INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); |
4851 | INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); | 4847 | INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); |
4848 | INIT_WORK(&wl->tx_work, b43_tx_work); | ||
4849 | skb_queue_head_init(&wl->tx_queue); | ||
4852 | 4850 | ||
4853 | ssb_set_devtypedata(dev, wl); | 4851 | ssb_set_devtypedata(dev, wl); |
4854 | b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n", | 4852 | b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n", |
@@ -4946,8 +4944,8 @@ static int b43_suspend(struct ssb_device *dev, pm_message_t state) | |||
4946 | wldev->suspend_in_progress = true; | 4944 | wldev->suspend_in_progress = true; |
4947 | wldev->suspend_init_status = b43_status(wldev); | 4945 | wldev->suspend_init_status = b43_status(wldev); |
4948 | if (wldev->suspend_init_status >= B43_STAT_STARTED) | 4946 | if (wldev->suspend_init_status >= B43_STAT_STARTED) |
4949 | b43_wireless_core_stop(wldev); | 4947 | wldev = b43_wireless_core_stop(wldev); |
4950 | if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) | 4948 | if (wldev && wldev->suspend_init_status >= B43_STAT_INITIALIZED) |
4951 | b43_wireless_core_exit(wldev); | 4949 | b43_wireless_core_exit(wldev); |
4952 | mutex_unlock(&wl->mutex); | 4950 | mutex_unlock(&wl->mutex); |
4953 | 4951 | ||
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 0406e06781d4..40db03678d9f 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); | |||
112 | void b43_tsf_write(struct b43_wldev *dev, u64 tsf); | 112 | void b43_tsf_write(struct b43_wldev *dev, u64 tsf); |
113 | 113 | ||
114 | u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); | 114 | u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); |
115 | u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); | ||
116 | u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); | 115 | u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); |
117 | u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); | ||
118 | void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); | 116 | void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); |
119 | void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); | ||
120 | void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); | 117 | void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); |
121 | void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); | ||
122 | 118 | ||
123 | u64 b43_hf_read(struct b43_wldev *dev); | 119 | u64 b43_hf_read(struct b43_wldev *dev); |
124 | void b43_hf_write(struct b43_wldev *dev, u64 value); | 120 | void b43_hf_write(struct b43_wldev *dev, u64 value); |
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 6e704becda6f..75b26e175e8f 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) | |||
347 | mutex_unlock(&wl->mutex); | 347 | mutex_unlock(&wl->mutex); |
348 | } | 348 | } |
349 | 349 | ||
350 | /* Called with wl->irq_lock locked */ | ||
351 | void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags) | 350 | void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags) |
352 | { | 351 | { |
353 | struct b43_phy *phy = &dev->phy; | 352 | 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 28e384633c34..9edd4e8e0c85 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 { | |||
131 | * If the parameter "ignore_tssi" is true, the TSSI values should | 131 | * If the parameter "ignore_tssi" is true, the TSSI values should |
132 | * be ignored and a recalculation of the power settings should be | 132 | * be ignored and a recalculation of the power settings should be |
133 | * done even if the TSSI values did not change. | 133 | * done even if the TSSI values did not change. |
134 | * This callback is called with wl->irq_lock held and must not sleep. | 134 | * This function may sleep, but should not. |
135 | * Must not be NULL. | 135 | * Must not be NULL. |
136 | * @adjust_txpower: Write the previously calculated TX power settings | 136 | * @adjust_txpower: Write the previously calculated TX power settings |
137 | * (from @recalc_txpower) to the hardware. | 137 | * (from @recalc_txpower) to the hardware. |
@@ -379,7 +379,6 @@ void b43_software_rfkill(struct b43_wldev *dev, bool blocked); | |||
379 | * | 379 | * |
380 | * Compare the current TX power output to the desired power emission | 380 | * Compare the current TX power output to the desired power emission |
381 | * and schedule an adjustment in case it mismatches. | 381 | * and schedule an adjustment in case it mismatches. |
382 | * Requires wl->irq_lock locked. | ||
383 | * | 382 | * |
384 | * @flags: OR'ed enum b43_phy_txpower_check_flags flags. | 383 | * @flags: OR'ed enum b43_phy_txpower_check_flags flags. |
385 | * See the docs below. | 384 | * See the docs below. |
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 5afa4df0b02f..382826a8da82 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) | |||
2823 | 2823 | ||
2824 | b43_mac_suspend(dev); | 2824 | b43_mac_suspend(dev); |
2825 | 2825 | ||
2826 | spin_lock_irq(&dev->wl->irq_lock); | ||
2827 | |||
2828 | /* Calculate the new attenuation values. */ | 2826 | /* Calculate the new attenuation values. */ |
2829 | bbatt = gphy->bbatt.att; | 2827 | bbatt = gphy->bbatt.att; |
2830 | bbatt += gphy->bbatt_delta; | 2828 | bbatt += gphy->bbatt_delta; |
@@ -2864,11 +2862,6 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) | |||
2864 | gphy->rfatt.att = rfatt; | 2862 | gphy->rfatt.att = rfatt; |
2865 | gphy->bbatt.att = bbatt; | 2863 | gphy->bbatt.att = bbatt; |
2866 | 2864 | ||
2867 | /* We drop the lock early, so we can sleep during hardware | ||
2868 | * adjustment. Possible races with op_recalc_txpower are harmless, | ||
2869 | * as we will be called once again in case we raced. */ | ||
2870 | spin_unlock_irq(&dev->wl->irq_lock); | ||
2871 | |||
2872 | if (b43_debug(dev, B43_DBG_XMITPOWER)) | 2865 | if (b43_debug(dev, B43_DBG_XMITPOWER)) |
2873 | b43dbg(dev->wl, "Adjusting TX power\n"); | 2866 | b43dbg(dev->wl, "Adjusting TX power\n"); |
2874 | 2867 | ||
diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h index 718947fd41ae..8569fdd4c6be 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 { | |||
141 | int tgt_idle_tssi; | 141 | int tgt_idle_tssi; |
142 | /* Current idle TSSI */ | 142 | /* Current idle TSSI */ |
143 | int cur_idle_tssi; | 143 | int cur_idle_tssi; |
144 | /* The current average TSSI. | 144 | /* The current average TSSI. */ |
145 | * Needs irq_lock, as it's updated in the IRQ path. */ | ||
146 | u8 average_tssi; | 145 | u8 average_tssi; |
147 | /* Current TX power level attenuation control values */ | 146 | /* Current TX power level attenuation control values */ |
148 | struct b43_bbatt bbatt; | 147 | struct b43_bbatt bbatt; |
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 3fd653c78b10..3498b68385e7 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c | |||
@@ -32,9 +32,6 @@ | |||
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | 33 | ||
34 | 34 | ||
35 | static void b43_pio_rx_work(struct work_struct *work); | ||
36 | |||
37 | |||
38 | static u16 generate_cookie(struct b43_pio_txqueue *q, | 35 | static u16 generate_cookie(struct b43_pio_txqueue *q, |
39 | struct b43_pio_txpacket *pack) | 36 | struct b43_pio_txpacket *pack) |
40 | { | 37 | { |
@@ -144,7 +141,6 @@ static struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev, | |||
144 | q = kzalloc(sizeof(*q), GFP_KERNEL); | 141 | q = kzalloc(sizeof(*q), GFP_KERNEL); |
145 | if (!q) | 142 | if (!q) |
146 | return NULL; | 143 | return NULL; |
147 | spin_lock_init(&q->lock); | ||
148 | q->dev = dev; | 144 | q->dev = dev; |
149 | q->rev = dev->dev->id.revision; | 145 | q->rev = dev->dev->id.revision; |
150 | q->mmio_base = index_to_pioqueue_base(dev, index) + | 146 | q->mmio_base = index_to_pioqueue_base(dev, index) + |
@@ -179,12 +175,10 @@ static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev, | |||
179 | q = kzalloc(sizeof(*q), GFP_KERNEL); | 175 | q = kzalloc(sizeof(*q), GFP_KERNEL); |
180 | if (!q) | 176 | if (!q) |
181 | return NULL; | 177 | return NULL; |
182 | spin_lock_init(&q->lock); | ||
183 | q->dev = dev; | 178 | q->dev = dev; |
184 | q->rev = dev->dev->id.revision; | 179 | q->rev = dev->dev->id.revision; |
185 | q->mmio_base = index_to_pioqueue_base(dev, index) + | 180 | q->mmio_base = index_to_pioqueue_base(dev, index) + |
186 | pio_rxqueue_offset(dev); | 181 | pio_rxqueue_offset(dev); |
187 | INIT_WORK(&q->rx_work, b43_pio_rx_work); | ||
188 | 182 | ||
189 | /* Enable Direct FIFO RX (PIO) on the engine. */ | 183 | /* Enable Direct FIFO RX (PIO) on the engine. */ |
190 | b43_dma_direct_fifo_rx(dev, index, 1); | 184 | b43_dma_direct_fifo_rx(dev, index, 1); |
@@ -249,13 +243,6 @@ void b43_pio_free(struct b43_wldev *dev) | |||
249 | destroy_queue_tx(pio, tx_queue_AC_BK); | 243 | destroy_queue_tx(pio, tx_queue_AC_BK); |
250 | } | 244 | } |
251 | 245 | ||
252 | void b43_pio_stop(struct b43_wldev *dev) | ||
253 | { | ||
254 | if (!b43_using_pio_transfers(dev)) | ||
255 | return; | ||
256 | cancel_work_sync(&dev->pio.rx_queue->rx_work); | ||
257 | } | ||
258 | |||
259 | int b43_pio_init(struct b43_wldev *dev) | 246 | int b43_pio_init(struct b43_wldev *dev) |
260 | { | 247 | { |
261 | struct b43_pio *pio = &dev->pio; | 248 | struct b43_pio *pio = &dev->pio; |
@@ -494,7 +481,6 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
494 | { | 481 | { |
495 | struct b43_pio_txqueue *q; | 482 | struct b43_pio_txqueue *q; |
496 | struct ieee80211_hdr *hdr; | 483 | struct ieee80211_hdr *hdr; |
497 | unsigned long flags; | ||
498 | unsigned int hdrlen, total_len; | 484 | unsigned int hdrlen, total_len; |
499 | int err = 0; | 485 | int err = 0; |
500 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 486 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
@@ -512,20 +498,18 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
512 | q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); | 498 | q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); |
513 | } | 499 | } |
514 | 500 | ||
515 | spin_lock_irqsave(&q->lock, flags); | ||
516 | |||
517 | hdrlen = b43_txhdr_size(dev); | 501 | hdrlen = b43_txhdr_size(dev); |
518 | total_len = roundup(skb->len + hdrlen, 4); | 502 | total_len = roundup(skb->len + hdrlen, 4); |
519 | 503 | ||
520 | if (unlikely(total_len > q->buffer_size)) { | 504 | if (unlikely(total_len > q->buffer_size)) { |
521 | err = -ENOBUFS; | 505 | err = -ENOBUFS; |
522 | b43dbg(dev->wl, "PIO: TX packet longer than queue.\n"); | 506 | b43dbg(dev->wl, "PIO: TX packet longer than queue.\n"); |
523 | goto out_unlock; | 507 | goto out; |
524 | } | 508 | } |
525 | if (unlikely(q->free_packet_slots == 0)) { | 509 | if (unlikely(q->free_packet_slots == 0)) { |
526 | err = -ENOBUFS; | 510 | err = -ENOBUFS; |
527 | b43warn(dev->wl, "PIO: TX packet overflow.\n"); | 511 | b43warn(dev->wl, "PIO: TX packet overflow.\n"); |
528 | goto out_unlock; | 512 | goto out; |
529 | } | 513 | } |
530 | B43_WARN_ON(q->buffer_used > q->buffer_size); | 514 | B43_WARN_ON(q->buffer_used > q->buffer_size); |
531 | 515 | ||
@@ -534,7 +518,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
534 | err = -EBUSY; | 518 | err = -EBUSY; |
535 | ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); | 519 | ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); |
536 | q->stopped = 1; | 520 | q->stopped = 1; |
537 | goto out_unlock; | 521 | goto out; |
538 | } | 522 | } |
539 | 523 | ||
540 | /* Assign the queue number to the ring (if not already done before) | 524 | /* Assign the queue number to the ring (if not already done before) |
@@ -548,11 +532,11 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
548 | * anymore and must not transmit it unencrypted. */ | 532 | * anymore and must not transmit it unencrypted. */ |
549 | dev_kfree_skb_any(skb); | 533 | dev_kfree_skb_any(skb); |
550 | err = 0; | 534 | err = 0; |
551 | goto out_unlock; | 535 | goto out; |
552 | } | 536 | } |
553 | if (unlikely(err)) { | 537 | if (unlikely(err)) { |
554 | b43err(dev->wl, "PIO transmission failure\n"); | 538 | b43err(dev->wl, "PIO transmission failure\n"); |
555 | goto out_unlock; | 539 | goto out; |
556 | } | 540 | } |
557 | q->nr_tx_packets++; | 541 | q->nr_tx_packets++; |
558 | 542 | ||
@@ -564,13 +548,10 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
564 | q->stopped = 1; | 548 | q->stopped = 1; |
565 | } | 549 | } |
566 | 550 | ||
567 | out_unlock: | 551 | out: |
568 | spin_unlock_irqrestore(&q->lock, flags); | ||
569 | |||
570 | return err; | 552 | return err; |
571 | } | 553 | } |
572 | 554 | ||
573 | /* Called with IRQs disabled. */ | ||
574 | void b43_pio_handle_txstatus(struct b43_wldev *dev, | 555 | void b43_pio_handle_txstatus(struct b43_wldev *dev, |
575 | const struct b43_txstatus *status) | 556 | const struct b43_txstatus *status) |
576 | { | 557 | { |
@@ -584,8 +565,6 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, | |||
584 | return; | 565 | return; |
585 | B43_WARN_ON(!pack); | 566 | B43_WARN_ON(!pack); |
586 | 567 | ||
587 | spin_lock(&q->lock); /* IRQs are already disabled. */ | ||
588 | |||
589 | info = IEEE80211_SKB_CB(pack->skb); | 568 | info = IEEE80211_SKB_CB(pack->skb); |
590 | 569 | ||
591 | b43_fill_txstatus_report(dev, info, status); | 570 | b43_fill_txstatus_report(dev, info, status); |
@@ -603,8 +582,6 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, | |||
603 | ieee80211_wake_queue(dev->wl->hw, q->queue_prio); | 582 | ieee80211_wake_queue(dev->wl->hw, q->queue_prio); |
604 | q->stopped = 0; | 583 | q->stopped = 0; |
605 | } | 584 | } |
606 | |||
607 | spin_unlock(&q->lock); | ||
608 | } | 585 | } |
609 | 586 | ||
610 | void b43_pio_get_tx_stats(struct b43_wldev *dev, | 587 | void b43_pio_get_tx_stats(struct b43_wldev *dev, |
@@ -612,17 +589,14 @@ void b43_pio_get_tx_stats(struct b43_wldev *dev, | |||
612 | { | 589 | { |
613 | const int nr_queues = dev->wl->hw->queues; | 590 | const int nr_queues = dev->wl->hw->queues; |
614 | struct b43_pio_txqueue *q; | 591 | struct b43_pio_txqueue *q; |
615 | unsigned long flags; | ||
616 | int i; | 592 | int i; |
617 | 593 | ||
618 | for (i = 0; i < nr_queues; i++) { | 594 | for (i = 0; i < nr_queues; i++) { |
619 | q = select_queue_by_priority(dev, i); | 595 | q = select_queue_by_priority(dev, i); |
620 | 596 | ||
621 | spin_lock_irqsave(&q->lock, flags); | ||
622 | stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; | 597 | stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; |
623 | stats[i].limit = B43_PIO_MAX_NR_TXPACKETS; | 598 | stats[i].limit = B43_PIO_MAX_NR_TXPACKETS; |
624 | stats[i].count = q->nr_tx_packets; | 599 | stats[i].count = q->nr_tx_packets; |
625 | spin_unlock_irqrestore(&q->lock, flags); | ||
626 | } | 600 | } |
627 | } | 601 | } |
628 | 602 | ||
@@ -760,37 +734,23 @@ rx_error: | |||
760 | return 1; | 734 | return 1; |
761 | } | 735 | } |
762 | 736 | ||
763 | /* RX workqueue. We can sleep, yay! */ | 737 | void b43_pio_rx(struct b43_pio_rxqueue *q) |
764 | static void b43_pio_rx_work(struct work_struct *work) | ||
765 | { | 738 | { |
766 | struct b43_pio_rxqueue *q = container_of(work, struct b43_pio_rxqueue, | 739 | unsigned int count = 0; |
767 | rx_work); | ||
768 | unsigned int budget = 50; | ||
769 | bool stop; | 740 | bool stop; |
770 | 741 | ||
771 | do { | 742 | while (1) { |
772 | spin_lock_irq(&q->lock); | ||
773 | stop = (pio_rx_frame(q) == 0); | 743 | stop = (pio_rx_frame(q) == 0); |
774 | spin_unlock_irq(&q->lock); | ||
775 | cond_resched(); | ||
776 | if (stop) | 744 | if (stop) |
777 | break; | 745 | break; |
778 | } while (--budget); | 746 | cond_resched(); |
779 | } | 747 | if (WARN_ON_ONCE(++count > 10000)) |
780 | 748 | break; | |
781 | /* Called with IRQs disabled. */ | 749 | } |
782 | void b43_pio_rx(struct b43_pio_rxqueue *q) | ||
783 | { | ||
784 | /* Due to latency issues we must run the RX path in | ||
785 | * a workqueue to be able to schedule between packets. */ | ||
786 | ieee80211_queue_work(q->dev->wl->hw, &q->rx_work); | ||
787 | } | 750 | } |
788 | 751 | ||
789 | static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) | 752 | static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) |
790 | { | 753 | { |
791 | unsigned long flags; | ||
792 | |||
793 | spin_lock_irqsave(&q->lock, flags); | ||
794 | if (q->rev >= 8) { | 754 | if (q->rev >= 8) { |
795 | b43_piotx_write32(q, B43_PIO8_TXCTL, | 755 | b43_piotx_write32(q, B43_PIO8_TXCTL, |
796 | b43_piotx_read32(q, B43_PIO8_TXCTL) | 756 | b43_piotx_read32(q, B43_PIO8_TXCTL) |
@@ -800,14 +760,10 @@ static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) | |||
800 | b43_piotx_read16(q, B43_PIO_TXCTL) | 760 | b43_piotx_read16(q, B43_PIO_TXCTL) |
801 | | B43_PIO_TXCTL_SUSPREQ); | 761 | | B43_PIO_TXCTL_SUSPREQ); |
802 | } | 762 | } |
803 | spin_unlock_irqrestore(&q->lock, flags); | ||
804 | } | 763 | } |
805 | 764 | ||
806 | static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q) | 765 | static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q) |
807 | { | 766 | { |
808 | unsigned long flags; | ||
809 | |||
810 | spin_lock_irqsave(&q->lock, flags); | ||
811 | if (q->rev >= 8) { | 767 | if (q->rev >= 8) { |
812 | b43_piotx_write32(q, B43_PIO8_TXCTL, | 768 | b43_piotx_write32(q, B43_PIO8_TXCTL, |
813 | b43_piotx_read32(q, B43_PIO8_TXCTL) | 769 | b43_piotx_read32(q, B43_PIO8_TXCTL) |
@@ -817,7 +773,6 @@ static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q) | |||
817 | b43_piotx_read16(q, B43_PIO_TXCTL) | 773 | b43_piotx_read16(q, B43_PIO_TXCTL) |
818 | & ~B43_PIO_TXCTL_SUSPREQ); | 774 | & ~B43_PIO_TXCTL_SUSPREQ); |
819 | } | 775 | } |
820 | spin_unlock_irqrestore(&q->lock, flags); | ||
821 | } | 776 | } |
822 | 777 | ||
823 | void b43_pio_tx_suspend(struct b43_wldev *dev) | 778 | 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 6c174c91ca20..7dd649c9ddad 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h | |||
@@ -70,7 +70,6 @@ struct b43_pio_txpacket { | |||
70 | 70 | ||
71 | struct b43_pio_txqueue { | 71 | struct b43_pio_txqueue { |
72 | struct b43_wldev *dev; | 72 | struct b43_wldev *dev; |
73 | spinlock_t lock; | ||
74 | u16 mmio_base; | 73 | u16 mmio_base; |
75 | 74 | ||
76 | /* The device queue buffer size in bytes. */ | 75 | /* The device queue buffer size in bytes. */ |
@@ -103,12 +102,8 @@ struct b43_pio_txqueue { | |||
103 | 102 | ||
104 | struct b43_pio_rxqueue { | 103 | struct b43_pio_rxqueue { |
105 | struct b43_wldev *dev; | 104 | struct b43_wldev *dev; |
106 | spinlock_t lock; | ||
107 | u16 mmio_base; | 105 | u16 mmio_base; |
108 | 106 | ||
109 | /* Work to reduce latency issues on RX. */ | ||
110 | struct work_struct rx_work; | ||
111 | |||
112 | /* Shortcut to the 802.11 core revision. This is to | 107 | /* Shortcut to the 802.11 core revision. This is to |
113 | * avoid horrible pointer dereferencing in the fastpaths. */ | 108 | * avoid horrible pointer dereferencing in the fastpaths. */ |
114 | u8 rev; | 109 | u8 rev; |
@@ -162,7 +157,6 @@ static inline void b43_piorx_write32(struct b43_pio_rxqueue *q, | |||
162 | 157 | ||
163 | 158 | ||
164 | int b43_pio_init(struct b43_wldev *dev); | 159 | int b43_pio_init(struct b43_wldev *dev); |
165 | void b43_pio_stop(struct b43_wldev *dev); | ||
166 | void b43_pio_free(struct b43_wldev *dev); | 160 | void b43_pio_free(struct b43_wldev *dev); |
167 | 161 | ||
168 | int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb); | 162 | int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb); |
diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c index 5adaa3692d75..f1ae4e05a32c 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, | |||
94 | const char *buf, size_t count) | 94 | const char *buf, size_t count) |
95 | { | 95 | { |
96 | struct b43_wldev *wldev = dev_to_b43_wldev(dev); | 96 | struct b43_wldev *wldev = dev_to_b43_wldev(dev); |
97 | unsigned long flags; | ||
98 | int err; | 97 | int err; |
99 | int mode; | 98 | int mode; |
100 | 99 | ||
@@ -120,7 +119,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, | |||
120 | } | 119 | } |
121 | 120 | ||
122 | mutex_lock(&wldev->wl->mutex); | 121 | mutex_lock(&wldev->wl->mutex); |
123 | spin_lock_irqsave(&wldev->wl->irq_lock, flags); | ||
124 | 122 | ||
125 | if (wldev->phy.ops->interf_mitigation) { | 123 | if (wldev->phy.ops->interf_mitigation) { |
126 | err = wldev->phy.ops->interf_mitigation(wldev, mode); | 124 | err = wldev->phy.ops->interf_mitigation(wldev, mode); |
@@ -132,7 +130,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, | |||
132 | err = -ENOSYS; | 130 | err = -ENOSYS; |
133 | 131 | ||
134 | mmiowb(); | 132 | mmiowb(); |
135 | spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); | ||
136 | mutex_unlock(&wldev->wl->mutex); | 133 | mutex_unlock(&wldev->wl->mutex); |
137 | 134 | ||
138 | return err ? err : count; | 135 | return err ? err : count; |
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index e7075d2c7757..14f541248b5c 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, | |||
267 | */ | 267 | */ |
268 | ieee80211_get_tkip_key(info->control.hw_key, skb_frag, | 268 | ieee80211_get_tkip_key(info->control.hw_key, skb_frag, |
269 | IEEE80211_TKIP_P1_KEY, (u8*)phase1key); | 269 | IEEE80211_TKIP_P1_KEY, (u8*)phase1key); |
270 | /* phase1key is in host endian */ | 270 | /* phase1key is in host endian. Copy to little-endian txhdr->iv. */ |
271 | for (i = 0; i < 5; i++) | 271 | for (i = 0; i < 5; i++) { |
272 | phase1key[i] = cpu_to_le16(phase1key[i]); | 272 | txhdr->iv[i * 2 + 0] = phase1key[i]; |
273 | 273 | txhdr->iv[i * 2 + 1] = phase1key[i] >> 8; | |
274 | memcpy(txhdr->iv, phase1key, 10); | 274 | } |
275 | /* iv16 */ | 275 | /* iv16 */ |
276 | memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3); | 276 | memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3); |
277 | } else { | 277 | } else { |
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index b166a6f9f055..1d9223b3d4c4 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) | |||
3106 | bus->pcicore.dev->id.revision <= 5) { | 3106 | bus->pcicore.dev->id.revision <= 5) { |
3107 | /* IMCFGLO timeouts workaround. */ | 3107 | /* IMCFGLO timeouts workaround. */ |
3108 | tmp = ssb_read32(dev->dev, SSB_IMCFGLO); | 3108 | tmp = ssb_read32(dev->dev, SSB_IMCFGLO); |
3109 | tmp &= ~SSB_IMCFGLO_REQTO; | ||
3110 | tmp &= ~SSB_IMCFGLO_SERTO; | ||
3111 | switch (bus->bustype) { | 3109 | switch (bus->bustype) { |
3112 | case SSB_BUSTYPE_PCI: | 3110 | case SSB_BUSTYPE_PCI: |
3113 | case SSB_BUSTYPE_PCMCIA: | 3111 | case SSB_BUSTYPE_PCMCIA: |
3112 | tmp &= ~SSB_IMCFGLO_REQTO; | ||
3113 | tmp &= ~SSB_IMCFGLO_SERTO; | ||
3114 | tmp |= 0x32; | 3114 | tmp |= 0x32; |
3115 | break; | 3115 | break; |
3116 | case SSB_BUSTYPE_SSB: | 3116 | case SSB_BUSTYPE_SSB: |
3117 | tmp &= ~SSB_IMCFGLO_REQTO; | ||
3118 | tmp &= ~SSB_IMCFGLO_SERTO; | ||
3117 | tmp |= 0x53; | 3119 | tmp |= 0x53; |
3118 | break; | 3120 | break; |
3121 | default: | ||
3122 | break; | ||
3119 | } | 3123 | } |
3120 | ssb_write32(dev->dev, SSB_IMCFGLO, tmp); | 3124 | ssb_write32(dev->dev, SSB_IMCFGLO, tmp); |
3121 | } | 3125 | } |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 164df9347a2f..798f625e38f7 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, | |||
331 | preamble_mask = erp->short_preamble << 3; | 331 | preamble_mask = erp->short_preamble << 3; |
332 | 332 | ||
333 | rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); | 333 | rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); |
334 | rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); | 334 | rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, 0x1ff); |
335 | rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, | 335 | rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, 0x13a); |
336 | erp->ack_consume_time); | ||
337 | rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); | 336 | rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); |
338 | rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); | 337 | rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); |
339 | rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); | 338 | rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 4186582f2770..2e872ac69826 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, | |||
337 | preamble_mask = erp->short_preamble << 3; | 337 | preamble_mask = erp->short_preamble << 3; |
338 | 338 | ||
339 | rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); | 339 | rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); |
340 | rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); | 340 | rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, 0x162); |
341 | rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, | 341 | rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, 0xa2); |
342 | erp->ack_consume_time); | ||
343 | rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); | 342 | rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); |
344 | rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); | 343 | rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); |
345 | rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); | 344 | rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index b04f59bab3b0..22dd6d9e2981 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, | |||
488 | { | 488 | { |
489 | u16 reg; | 489 | u16 reg; |
490 | 490 | ||
491 | rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); | ||
492 | rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, erp->ack_timeout); | ||
493 | rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); | ||
494 | |||
495 | rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); | 491 | rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); |
496 | rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, | 492 | rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, |
497 | !!erp->short_preamble); | 493 | !!erp->short_preamble); |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 639dc6cc04b9..a084077a1c61 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, | |||
580 | u32 reg; | 580 | u32 reg; |
581 | 581 | ||
582 | rt2x00usb_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); | 582 | rt2x00usb_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); |
583 | rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, | 583 | rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20); |
584 | DIV_ROUND_UP(erp->ack_timeout, erp->slot_time)); | ||
585 | rt2x00usb_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); | 584 | rt2x00usb_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); |
586 | 585 | ||
587 | rt2x00usb_register_read(rt2x00dev, AUTO_RSP_CFG, ®); | 586 | rt2x00usb_register_read(rt2x00dev, AUTO_RSP_CFG, ®); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 555a777db6df..27bc6b7fbfde 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -417,9 +417,6 @@ struct rt2x00lib_erp { | |||
417 | int short_preamble; | 417 | int short_preamble; |
418 | int cts_protection; | 418 | int cts_protection; |
419 | 419 | ||
420 | int ack_timeout; | ||
421 | int ack_consume_time; | ||
422 | |||
423 | u32 basic_rates; | 420 | u32 basic_rates; |
424 | 421 | ||
425 | int slot_time; | 422 | int slot_time; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 3501788ab498..40a201e2e151 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, | |||
94 | erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS; | 94 | erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS; |
95 | erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS; | 95 | erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS; |
96 | 96 | ||
97 | erp.ack_timeout = PLCP + erp.difs + GET_DURATION(ACK_SIZE, 10); | ||
98 | erp.ack_consume_time = SIFS + PLCP + GET_DURATION(ACK_SIZE, 10); | ||
99 | |||
100 | if (bss_conf->use_short_preamble) { | ||
101 | erp.ack_timeout += SHORT_PREAMBLE; | ||
102 | erp.ack_consume_time += SHORT_PREAMBLE; | ||
103 | } else { | ||
104 | erp.ack_timeout += PREAMBLE; | ||
105 | erp.ack_consume_time += PREAMBLE; | ||
106 | } | ||
107 | |||
108 | erp.basic_rates = bss_conf->basic_rates; | 97 | erp.basic_rates = bss_conf->basic_rates; |
109 | erp.beacon_int = bss_conf->beacon_int; | 98 | erp.beacon_int = bss_conf->beacon_int; |
110 | 99 | ||
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index f4b4b86da4da..b20e3eac9d67 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, | |||
598 | u32 reg; | 598 | u32 reg; |
599 | 599 | ||
600 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); | 600 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); |
601 | rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); | 601 | rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); |
602 | rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); | 602 | rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); |
603 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); | 603 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); |
604 | 604 | ||
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 90e117263051..1cbd9b4a3efc 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, | |||
561 | u32 reg; | 561 | u32 reg; |
562 | 562 | ||
563 | rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); | 563 | rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); |
564 | rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); | 564 | rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); |
565 | rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); | 565 | rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); |
566 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); | 566 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); |
567 | 567 | ||
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index 540a2948596c..2d8cc455dbc7 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig | |||
@@ -66,6 +66,20 @@ config SSB_PCMCIAHOST | |||
66 | 66 | ||
67 | If unsure, say N | 67 | If unsure, say N |
68 | 68 | ||
69 | config SSB_SDIOHOST_POSSIBLE | ||
70 | bool | ||
71 | depends on SSB && (MMC = y || MMC = SSB) | ||
72 | default y | ||
73 | |||
74 | config SSB_SDIOHOST | ||
75 | bool "Support for SSB on SDIO-bus host" | ||
76 | depends on SSB_SDIOHOST_POSSIBLE | ||
77 | help | ||
78 | Support for a Sonics Silicon Backplane on top | ||
79 | of a SDIO device. | ||
80 | |||
81 | If unsure, say N | ||
82 | |||
69 | config SSB_SILENT | 83 | config SSB_SILENT |
70 | bool "No SSB kernel messages" | 84 | bool "No SSB kernel messages" |
71 | depends on SSB && EMBEDDED | 85 | depends on SSB && EMBEDDED |
diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile index cfbb74f2982e..656e58b92618 100644 --- a/drivers/ssb/Makefile +++ b/drivers/ssb/Makefile | |||
@@ -6,6 +6,7 @@ ssb-$(CONFIG_SSB_SPROM) += sprom.o | |||
6 | # host support | 6 | # host support |
7 | ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o | 7 | ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o |
8 | ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o | 8 | ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o |
9 | ssb-$(CONFIG_SSB_SDIOHOST) += sdio.o | ||
9 | 10 | ||
10 | # built-in drivers | 11 | # built-in drivers |
11 | ssb-y += driver_chipcommon.o | 12 | ssb-y += driver_chipcommon.o |
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 65a1ed951a1d..579b114be412 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/ssb/ssb_driver_gige.h> | 17 | #include <linux/ssb/ssb_driver_gige.h> |
18 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
19 | #include <linux/pci.h> | 19 | #include <linux/pci.h> |
20 | #include <linux/mmc/sdio_func.h> | ||
20 | 21 | ||
21 | #include <pcmcia/cs_types.h> | 22 | #include <pcmcia/cs_types.h> |
22 | #include <pcmcia/cs.h> | 23 | #include <pcmcia/cs.h> |
@@ -88,6 +89,25 @@ found: | |||
88 | } | 89 | } |
89 | #endif /* CONFIG_SSB_PCMCIAHOST */ | 90 | #endif /* CONFIG_SSB_PCMCIAHOST */ |
90 | 91 | ||
92 | #ifdef CONFIG_SSB_SDIOHOST | ||
93 | struct ssb_bus *ssb_sdio_func_to_bus(struct sdio_func *func) | ||
94 | { | ||
95 | struct ssb_bus *bus; | ||
96 | |||
97 | ssb_buses_lock(); | ||
98 | list_for_each_entry(bus, &buses, list) { | ||
99 | if (bus->bustype == SSB_BUSTYPE_SDIO && | ||
100 | bus->host_sdio == func) | ||
101 | goto found; | ||
102 | } | ||
103 | bus = NULL; | ||
104 | found: | ||
105 | ssb_buses_unlock(); | ||
106 | |||
107 | return bus; | ||
108 | } | ||
109 | #endif /* CONFIG_SSB_SDIOHOST */ | ||
110 | |||
91 | int ssb_for_each_bus_call(unsigned long data, | 111 | int ssb_for_each_bus_call(unsigned long data, |
92 | int (*func)(struct ssb_bus *bus, unsigned long data)) | 112 | int (*func)(struct ssb_bus *bus, unsigned long data)) |
93 | { | 113 | { |
@@ -469,6 +489,12 @@ static int ssb_devices_register(struct ssb_bus *bus) | |||
469 | dev->parent = &bus->host_pcmcia->dev; | 489 | dev->parent = &bus->host_pcmcia->dev; |
470 | #endif | 490 | #endif |
471 | break; | 491 | break; |
492 | case SSB_BUSTYPE_SDIO: | ||
493 | #ifdef CONFIG_SSB_SDIO | ||
494 | sdev->irq = bus->host_sdio->dev.irq; | ||
495 | dev->parent = &bus->host_sdio->dev; | ||
496 | #endif | ||
497 | break; | ||
472 | case SSB_BUSTYPE_SSB: | 498 | case SSB_BUSTYPE_SSB: |
473 | dev->dma_mask = &dev->coherent_dma_mask; | 499 | dev->dma_mask = &dev->coherent_dma_mask; |
474 | break; | 500 | break; |
@@ -724,12 +750,18 @@ static int ssb_bus_register(struct ssb_bus *bus, | |||
724 | err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); | 750 | err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); |
725 | if (err) | 751 | if (err) |
726 | goto out; | 752 | goto out; |
753 | |||
754 | /* Init SDIO-host device (if any), before the scan */ | ||
755 | err = ssb_sdio_init(bus); | ||
756 | if (err) | ||
757 | goto err_disable_xtal; | ||
758 | |||
727 | ssb_buses_lock(); | 759 | ssb_buses_lock(); |
728 | bus->busnumber = next_busnumber; | 760 | bus->busnumber = next_busnumber; |
729 | /* Scan for devices (cores) */ | 761 | /* Scan for devices (cores) */ |
730 | err = ssb_bus_scan(bus, baseaddr); | 762 | err = ssb_bus_scan(bus, baseaddr); |
731 | if (err) | 763 | if (err) |
732 | goto err_disable_xtal; | 764 | goto err_sdio_exit; |
733 | 765 | ||
734 | /* Init PCI-host device (if any) */ | 766 | /* Init PCI-host device (if any) */ |
735 | err = ssb_pci_init(bus); | 767 | err = ssb_pci_init(bus); |
@@ -776,6 +808,8 @@ err_pci_exit: | |||
776 | ssb_pci_exit(bus); | 808 | ssb_pci_exit(bus); |
777 | err_unmap: | 809 | err_unmap: |
778 | ssb_iounmap(bus); | 810 | ssb_iounmap(bus); |
811 | err_sdio_exit: | ||
812 | ssb_sdio_exit(bus); | ||
779 | err_disable_xtal: | 813 | err_disable_xtal: |
780 | ssb_buses_unlock(); | 814 | ssb_buses_unlock(); |
781 | ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); | 815 | ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); |
@@ -825,6 +859,28 @@ int ssb_bus_pcmciabus_register(struct ssb_bus *bus, | |||
825 | EXPORT_SYMBOL(ssb_bus_pcmciabus_register); | 859 | EXPORT_SYMBOL(ssb_bus_pcmciabus_register); |
826 | #endif /* CONFIG_SSB_PCMCIAHOST */ | 860 | #endif /* CONFIG_SSB_PCMCIAHOST */ |
827 | 861 | ||
862 | #ifdef CONFIG_SSB_SDIOHOST | ||
863 | int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func, | ||
864 | unsigned int quirks) | ||
865 | { | ||
866 | int err; | ||
867 | |||
868 | bus->bustype = SSB_BUSTYPE_SDIO; | ||
869 | bus->host_sdio = func; | ||
870 | bus->ops = &ssb_sdio_ops; | ||
871 | bus->quirks = quirks; | ||
872 | |||
873 | err = ssb_bus_register(bus, ssb_sdio_get_invariants, ~0); | ||
874 | if (!err) { | ||
875 | ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " | ||
876 | "SDIO device %s\n", sdio_func_id(func)); | ||
877 | } | ||
878 | |||
879 | return err; | ||
880 | } | ||
881 | EXPORT_SYMBOL(ssb_bus_sdiobus_register); | ||
882 | #endif /* CONFIG_SSB_PCMCIAHOST */ | ||
883 | |||
828 | int ssb_bus_ssbbus_register(struct ssb_bus *bus, | 884 | int ssb_bus_ssbbus_register(struct ssb_bus *bus, |
829 | unsigned long baseaddr, | 885 | unsigned long baseaddr, |
830 | ssb_invariants_func_t get_invariants) | 886 | ssb_invariants_func_t get_invariants) |
@@ -1358,8 +1414,10 @@ static int __init ssb_modinit(void) | |||
1358 | ssb_buses_lock(); | 1414 | ssb_buses_lock(); |
1359 | err = ssb_attach_queued_buses(); | 1415 | err = ssb_attach_queued_buses(); |
1360 | ssb_buses_unlock(); | 1416 | ssb_buses_unlock(); |
1361 | if (err) | 1417 | if (err) { |
1362 | bus_unregister(&ssb_bustype); | 1418 | bus_unregister(&ssb_bustype); |
1419 | goto out; | ||
1420 | } | ||
1363 | 1421 | ||
1364 | err = b43_pci_ssb_bridge_init(); | 1422 | err = b43_pci_ssb_bridge_init(); |
1365 | if (err) { | 1423 | if (err) { |
@@ -1375,7 +1433,7 @@ static int __init ssb_modinit(void) | |||
1375 | /* don't fail SSB init because of this */ | 1433 | /* don't fail SSB init because of this */ |
1376 | err = 0; | 1434 | err = 0; |
1377 | } | 1435 | } |
1378 | 1436 | out: | |
1379 | return err; | 1437 | return err; |
1380 | } | 1438 | } |
1381 | /* ssb must be initialized after PCI but before the ssb drivers. | 1439 | /* ssb must be initialized after PCI but before the ssb drivers. |
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c index 63ee5cfbefbb..b74212d698c7 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, | |||
175 | } else | 175 | } else |
176 | ssb_pcmcia_switch_segment(bus, 0); | 176 | ssb_pcmcia_switch_segment(bus, 0); |
177 | break; | 177 | break; |
178 | case SSB_BUSTYPE_SDIO: | ||
179 | offset += current_coreidx * SSB_CORE_SIZE; | ||
180 | return ssb_sdio_scan_read32(bus, offset); | ||
178 | } | 181 | } |
179 | return readl(bus->mmio + offset); | 182 | return readl(bus->mmio + offset); |
180 | } | 183 | } |
@@ -188,6 +191,8 @@ static int scan_switchcore(struct ssb_bus *bus, u8 coreidx) | |||
188 | return ssb_pci_switch_coreidx(bus, coreidx); | 191 | return ssb_pci_switch_coreidx(bus, coreidx); |
189 | case SSB_BUSTYPE_PCMCIA: | 192 | case SSB_BUSTYPE_PCMCIA: |
190 | return ssb_pcmcia_switch_coreidx(bus, coreidx); | 193 | return ssb_pcmcia_switch_coreidx(bus, coreidx); |
194 | case SSB_BUSTYPE_SDIO: | ||
195 | return ssb_sdio_scan_switch_coreidx(bus, coreidx); | ||
191 | } | 196 | } |
192 | return 0; | 197 | return 0; |
193 | } | 198 | } |
@@ -206,6 +211,8 @@ void ssb_iounmap(struct ssb_bus *bus) | |||
206 | SSB_BUG_ON(1); /* Can't reach this code. */ | 211 | SSB_BUG_ON(1); /* Can't reach this code. */ |
207 | #endif | 212 | #endif |
208 | break; | 213 | break; |
214 | case SSB_BUSTYPE_SDIO: | ||
215 | break; | ||
209 | } | 216 | } |
210 | bus->mmio = NULL; | 217 | bus->mmio = NULL; |
211 | bus->mapped_device = NULL; | 218 | bus->mapped_device = NULL; |
@@ -230,6 +237,10 @@ static void __iomem *ssb_ioremap(struct ssb_bus *bus, | |||
230 | SSB_BUG_ON(1); /* Can't reach this code. */ | 237 | SSB_BUG_ON(1); /* Can't reach this code. */ |
231 | #endif | 238 | #endif |
232 | break; | 239 | break; |
240 | case SSB_BUSTYPE_SDIO: | ||
241 | /* Nothing to ioremap in the SDIO case, just fake it */ | ||
242 | mmio = (void __iomem *)baseaddr; | ||
243 | break; | ||
233 | } | 244 | } |
234 | 245 | ||
235 | return mmio; | 246 | return mmio; |
diff --git a/drivers/ssb/sdio.c b/drivers/ssb/sdio.c new file mode 100644 index 000000000000..114051056b52 --- /dev/null +++ b/drivers/ssb/sdio.c | |||
@@ -0,0 +1,610 @@ | |||
1 | /* | ||
2 | * Sonics Silicon Backplane | ||
3 | * SDIO-Hostbus related functions | ||
4 | * | ||
5 | * Copyright 2009 Albert Herranz <albert_herranz@yahoo.es> | ||
6 | * | ||
7 | * Based on drivers/ssb/pcmcia.c | ||
8 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
9 | * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de> | ||
10 | * | ||
11 | * Licensed under the GNU/GPL. See COPYING for details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/ssb/ssb.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/etherdevice.h> | ||
19 | #include <linux/mmc/sdio_func.h> | ||
20 | |||
21 | #include "ssb_private.h" | ||
22 | |||
23 | /* Define the following to 1 to enable a printk on each coreswitch. */ | ||
24 | #define SSB_VERBOSE_SDIOCORESWITCH_DEBUG 1 | ||
25 | |||
26 | |||
27 | /* Hardware invariants CIS tuples */ | ||
28 | #define SSB_SDIO_CIS 0x80 | ||
29 | #define SSB_SDIO_CIS_SROMREV 0x00 | ||
30 | #define SSB_SDIO_CIS_ID 0x01 | ||
31 | #define SSB_SDIO_CIS_BOARDREV 0x02 | ||
32 | #define SSB_SDIO_CIS_PA 0x03 | ||
33 | #define SSB_SDIO_CIS_PA_PA0B0_LO 0 | ||
34 | #define SSB_SDIO_CIS_PA_PA0B0_HI 1 | ||
35 | #define SSB_SDIO_CIS_PA_PA0B1_LO 2 | ||
36 | #define SSB_SDIO_CIS_PA_PA0B1_HI 3 | ||
37 | #define SSB_SDIO_CIS_PA_PA0B2_LO 4 | ||
38 | #define SSB_SDIO_CIS_PA_PA0B2_HI 5 | ||
39 | #define SSB_SDIO_CIS_PA_ITSSI 6 | ||
40 | #define SSB_SDIO_CIS_PA_MAXPOW 7 | ||
41 | #define SSB_SDIO_CIS_OEMNAME 0x04 | ||
42 | #define SSB_SDIO_CIS_CCODE 0x05 | ||
43 | #define SSB_SDIO_CIS_ANTENNA 0x06 | ||
44 | #define SSB_SDIO_CIS_ANTGAIN 0x07 | ||
45 | #define SSB_SDIO_CIS_BFLAGS 0x08 | ||
46 | #define SSB_SDIO_CIS_LEDS 0x09 | ||
47 | |||
48 | #define CISTPL_FUNCE_LAN_NODE_ID 0x04 /* same as in PCMCIA */ | ||
49 | |||
50 | |||
51 | /* | ||
52 | * Function 1 miscellaneous registers. | ||
53 | * | ||
54 | * Definitions match src/include/sbsdio.h from the | ||
55 | * Android Open Source Project | ||
56 | * http://android.git.kernel.org/?p=platform/system/wlan/broadcom.git | ||
57 | * | ||
58 | */ | ||
59 | #define SBSDIO_FUNC1_SBADDRLOW 0x1000a /* SB Address window Low (b15) */ | ||
60 | #define SBSDIO_FUNC1_SBADDRMID 0x1000b /* SB Address window Mid (b23-b16) */ | ||
61 | #define SBSDIO_FUNC1_SBADDRHIGH 0x1000c /* SB Address window High (b24-b31) */ | ||
62 | |||
63 | /* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */ | ||
64 | #define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid address bits in SBADDRLOW */ | ||
65 | #define SBSDIO_SBADDRMID_MASK 0xff /* Valid address bits in SBADDRMID */ | ||
66 | #define SBSDIO_SBADDRHIGH_MASK 0xff /* Valid address bits in SBADDRHIGH */ | ||
67 | |||
68 | #define SBSDIO_SB_OFT_ADDR_MASK 0x7FFF /* sb offset addr is <= 15 bits, 32k */ | ||
69 | |||
70 | /* REVISIT: this flag doesn't seem to matter */ | ||
71 | #define SBSDIO_SB_ACCESS_2_4B_FLAG 0x8000 /* forces 32-bit SB access */ | ||
72 | |||
73 | |||
74 | /* | ||
75 | * Address map within the SDIO function address space (128K). | ||
76 | * | ||
77 | * Start End Description | ||
78 | * ------- ------- ------------------------------------------ | ||
79 | * 0x00000 0x0ffff selected backplane address window (64K) | ||
80 | * 0x10000 0x1ffff backplane control registers (max 64K) | ||
81 | * | ||
82 | * The current address window is configured by writing to registers | ||
83 | * SBADDRLOW, SBADDRMID and SBADDRHIGH. | ||
84 | * | ||
85 | * In order to access the contents of a 32-bit Silicon Backplane address | ||
86 | * the backplane address window must be first loaded with the highest | ||
87 | * 16 bits of the target address. Then, an access must be done to the | ||
88 | * SDIO function address space using the lower 15 bits of the address. | ||
89 | * Bit 15 of the address must be set when doing 32 bit accesses. | ||
90 | * | ||
91 | * 10987654321098765432109876543210 | ||
92 | * WWWWWWWWWWWWWWWWW SB Address Window | ||
93 | * OOOOOOOOOOOOOOOO Offset within SB Address Window | ||
94 | * a 32-bit access flag | ||
95 | */ | ||
96 | |||
97 | |||
98 | /* | ||
99 | * SSB I/O via SDIO. | ||
100 | * | ||
101 | * NOTE: SDIO address @addr is 17 bits long (SDIO address space is 128K). | ||
102 | */ | ||
103 | |||
104 | static inline struct device *ssb_sdio_dev(struct ssb_bus *bus) | ||
105 | { | ||
106 | return &bus->host_sdio->dev; | ||
107 | } | ||
108 | |||
109 | /* host claimed */ | ||
110 | static int ssb_sdio_writeb(struct ssb_bus *bus, unsigned int addr, u8 val) | ||
111 | { | ||
112 | int error = 0; | ||
113 | |||
114 | sdio_writeb(bus->host_sdio, val, addr, &error); | ||
115 | if (unlikely(error)) { | ||
116 | dev_dbg(ssb_sdio_dev(bus), "%08X <- %02x, error %d\n", | ||
117 | addr, val, error); | ||
118 | } | ||
119 | |||
120 | return error; | ||
121 | } | ||
122 | |||
123 | #if 0 | ||
124 | static u8 ssb_sdio_readb(struct ssb_bus *bus, unsigned int addr) | ||
125 | { | ||
126 | u8 val; | ||
127 | int error = 0; | ||
128 | |||
129 | val = sdio_readb(bus->host_sdio, addr, &error); | ||
130 | if (unlikely(error)) { | ||
131 | dev_dbg(ssb_sdio_dev(bus), "%08X -> %02x, error %d\n", | ||
132 | addr, val, error); | ||
133 | } | ||
134 | |||
135 | return val; | ||
136 | } | ||
137 | #endif | ||
138 | |||
139 | /* host claimed */ | ||
140 | static int ssb_sdio_set_sbaddr_window(struct ssb_bus *bus, u32 address) | ||
141 | { | ||
142 | int error; | ||
143 | |||
144 | error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRLOW, | ||
145 | (address >> 8) & SBSDIO_SBADDRLOW_MASK); | ||
146 | if (error) | ||
147 | goto out; | ||
148 | error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRMID, | ||
149 | (address >> 16) & SBSDIO_SBADDRMID_MASK); | ||
150 | if (error) | ||
151 | goto out; | ||
152 | error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRHIGH, | ||
153 | (address >> 24) & SBSDIO_SBADDRHIGH_MASK); | ||
154 | if (error) | ||
155 | goto out; | ||
156 | bus->sdio_sbaddr = address; | ||
157 | out: | ||
158 | if (error) { | ||
159 | dev_dbg(ssb_sdio_dev(bus), "failed to set address window" | ||
160 | " to 0x%08x, error %d\n", address, error); | ||
161 | } | ||
162 | |||
163 | return error; | ||
164 | } | ||
165 | |||
166 | /* for enumeration use only */ | ||
167 | u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset) | ||
168 | { | ||
169 | u32 val; | ||
170 | int error; | ||
171 | |||
172 | sdio_claim_host(bus->host_sdio); | ||
173 | val = sdio_readl(bus->host_sdio, offset, &error); | ||
174 | sdio_release_host(bus->host_sdio); | ||
175 | if (unlikely(error)) { | ||
176 | dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n", | ||
177 | bus->sdio_sbaddr >> 16, offset, val, error); | ||
178 | } | ||
179 | |||
180 | return val; | ||
181 | } | ||
182 | |||
183 | /* for enumeration use only */ | ||
184 | int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx) | ||
185 | { | ||
186 | u32 sbaddr; | ||
187 | int error; | ||
188 | |||
189 | sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; | ||
190 | sdio_claim_host(bus->host_sdio); | ||
191 | error = ssb_sdio_set_sbaddr_window(bus, sbaddr); | ||
192 | sdio_release_host(bus->host_sdio); | ||
193 | if (error) { | ||
194 | dev_err(ssb_sdio_dev(bus), "failed to switch to core %u," | ||
195 | " error %d\n", coreidx, error); | ||
196 | goto out; | ||
197 | } | ||
198 | out: | ||
199 | return error; | ||
200 | } | ||
201 | |||
202 | /* host must be already claimed */ | ||
203 | int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev) | ||
204 | { | ||
205 | u8 coreidx = dev->core_index; | ||
206 | u32 sbaddr; | ||
207 | int error = 0; | ||
208 | |||
209 | sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; | ||
210 | if (unlikely(bus->sdio_sbaddr != sbaddr)) { | ||
211 | #if SSB_VERBOSE_SDIOCORESWITCH_DEBUG | ||
212 | dev_info(ssb_sdio_dev(bus), | ||
213 | "switching to %s core, index %d\n", | ||
214 | ssb_core_name(dev->id.coreid), coreidx); | ||
215 | #endif | ||
216 | error = ssb_sdio_set_sbaddr_window(bus, sbaddr); | ||
217 | if (error) { | ||
218 | dev_dbg(ssb_sdio_dev(bus), "failed to switch to" | ||
219 | " core %u, error %d\n", coreidx, error); | ||
220 | goto out; | ||
221 | } | ||
222 | bus->mapped_device = dev; | ||
223 | } | ||
224 | |||
225 | out: | ||
226 | return error; | ||
227 | } | ||
228 | |||
229 | static u8 ssb_sdio_read8(struct ssb_device *dev, u16 offset) | ||
230 | { | ||
231 | struct ssb_bus *bus = dev->bus; | ||
232 | u8 val = 0xff; | ||
233 | int error = 0; | ||
234 | |||
235 | sdio_claim_host(bus->host_sdio); | ||
236 | if (unlikely(ssb_sdio_switch_core(bus, dev))) | ||
237 | goto out; | ||
238 | offset |= bus->sdio_sbaddr & 0xffff; | ||
239 | offset &= SBSDIO_SB_OFT_ADDR_MASK; | ||
240 | val = sdio_readb(bus->host_sdio, offset, &error); | ||
241 | if (error) { | ||
242 | dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %02x, error %d\n", | ||
243 | bus->sdio_sbaddr >> 16, offset, val, error); | ||
244 | } | ||
245 | out: | ||
246 | sdio_release_host(bus->host_sdio); | ||
247 | |||
248 | return val; | ||
249 | } | ||
250 | |||
251 | static u16 ssb_sdio_read16(struct ssb_device *dev, u16 offset) | ||
252 | { | ||
253 | struct ssb_bus *bus = dev->bus; | ||
254 | u16 val = 0xffff; | ||
255 | int error = 0; | ||
256 | |||
257 | sdio_claim_host(bus->host_sdio); | ||
258 | if (unlikely(ssb_sdio_switch_core(bus, dev))) | ||
259 | goto out; | ||
260 | offset |= bus->sdio_sbaddr & 0xffff; | ||
261 | offset &= SBSDIO_SB_OFT_ADDR_MASK; | ||
262 | val = sdio_readw(bus->host_sdio, offset, &error); | ||
263 | if (error) { | ||
264 | dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %04x, error %d\n", | ||
265 | bus->sdio_sbaddr >> 16, offset, val, error); | ||
266 | } | ||
267 | out: | ||
268 | sdio_release_host(bus->host_sdio); | ||
269 | |||
270 | return val; | ||
271 | } | ||
272 | |||
273 | static u32 ssb_sdio_read32(struct ssb_device *dev, u16 offset) | ||
274 | { | ||
275 | struct ssb_bus *bus = dev->bus; | ||
276 | u32 val = 0xffffffff; | ||
277 | int error = 0; | ||
278 | |||
279 | sdio_claim_host(bus->host_sdio); | ||
280 | if (unlikely(ssb_sdio_switch_core(bus, dev))) | ||
281 | goto out; | ||
282 | offset |= bus->sdio_sbaddr & 0xffff; | ||
283 | offset &= SBSDIO_SB_OFT_ADDR_MASK; | ||
284 | offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ | ||
285 | val = sdio_readl(bus->host_sdio, offset, &error); | ||
286 | if (error) { | ||
287 | dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n", | ||
288 | bus->sdio_sbaddr >> 16, offset, val, error); | ||
289 | } | ||
290 | out: | ||
291 | sdio_release_host(bus->host_sdio); | ||
292 | |||
293 | return val; | ||
294 | } | ||
295 | |||
296 | #ifdef CONFIG_SSB_BLOCKIO | ||
297 | static void ssb_sdio_block_read(struct ssb_device *dev, void *buffer, | ||
298 | size_t count, u16 offset, u8 reg_width) | ||
299 | { | ||
300 | size_t saved_count = count; | ||
301 | struct ssb_bus *bus = dev->bus; | ||
302 | int error = 0; | ||
303 | |||
304 | sdio_claim_host(bus->host_sdio); | ||
305 | if (unlikely(ssb_sdio_switch_core(bus, dev))) { | ||
306 | error = -EIO; | ||
307 | memset(buffer, 0xff, count); | ||
308 | goto err_out; | ||
309 | } | ||
310 | offset |= bus->sdio_sbaddr & 0xffff; | ||
311 | offset &= SBSDIO_SB_OFT_ADDR_MASK; | ||
312 | |||
313 | switch (reg_width) { | ||
314 | case sizeof(u8): { | ||
315 | error = sdio_readsb(bus->host_sdio, buffer, offset, count); | ||
316 | break; | ||
317 | } | ||
318 | case sizeof(u16): { | ||
319 | SSB_WARN_ON(count & 1); | ||
320 | error = sdio_readsb(bus->host_sdio, buffer, offset, count); | ||
321 | break; | ||
322 | } | ||
323 | case sizeof(u32): { | ||
324 | SSB_WARN_ON(count & 3); | ||
325 | offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ | ||
326 | error = sdio_readsb(bus->host_sdio, buffer, offset, count); | ||
327 | break; | ||
328 | } | ||
329 | default: | ||
330 | SSB_WARN_ON(1); | ||
331 | } | ||
332 | if (!error) | ||
333 | goto out; | ||
334 | |||
335 | err_out: | ||
336 | dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%u), error %d\n", | ||
337 | bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error); | ||
338 | out: | ||
339 | sdio_release_host(bus->host_sdio); | ||
340 | } | ||
341 | #endif /* CONFIG_SSB_BLOCKIO */ | ||
342 | |||
343 | static void ssb_sdio_write8(struct ssb_device *dev, u16 offset, u8 val) | ||
344 | { | ||
345 | struct ssb_bus *bus = dev->bus; | ||
346 | int error = 0; | ||
347 | |||
348 | sdio_claim_host(bus->host_sdio); | ||
349 | if (unlikely(ssb_sdio_switch_core(bus, dev))) | ||
350 | goto out; | ||
351 | offset |= bus->sdio_sbaddr & 0xffff; | ||
352 | offset &= SBSDIO_SB_OFT_ADDR_MASK; | ||
353 | sdio_writeb(bus->host_sdio, val, offset, &error); | ||
354 | if (error) { | ||
355 | dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %02x, error %d\n", | ||
356 | bus->sdio_sbaddr >> 16, offset, val, error); | ||
357 | } | ||
358 | out: | ||
359 | sdio_release_host(bus->host_sdio); | ||
360 | } | ||
361 | |||
362 | static void ssb_sdio_write16(struct ssb_device *dev, u16 offset, u16 val) | ||
363 | { | ||
364 | struct ssb_bus *bus = dev->bus; | ||
365 | int error = 0; | ||
366 | |||
367 | sdio_claim_host(bus->host_sdio); | ||
368 | if (unlikely(ssb_sdio_switch_core(bus, dev))) | ||
369 | goto out; | ||
370 | offset |= bus->sdio_sbaddr & 0xffff; | ||
371 | offset &= SBSDIO_SB_OFT_ADDR_MASK; | ||
372 | sdio_writew(bus->host_sdio, val, offset, &error); | ||
373 | if (error) { | ||
374 | dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %04x, error %d\n", | ||
375 | bus->sdio_sbaddr >> 16, offset, val, error); | ||
376 | } | ||
377 | out: | ||
378 | sdio_release_host(bus->host_sdio); | ||
379 | } | ||
380 | |||
381 | static void ssb_sdio_write32(struct ssb_device *dev, u16 offset, u32 val) | ||
382 | { | ||
383 | struct ssb_bus *bus = dev->bus; | ||
384 | int error = 0; | ||
385 | |||
386 | sdio_claim_host(bus->host_sdio); | ||
387 | if (unlikely(ssb_sdio_switch_core(bus, dev))) | ||
388 | goto out; | ||
389 | offset |= bus->sdio_sbaddr & 0xffff; | ||
390 | offset &= SBSDIO_SB_OFT_ADDR_MASK; | ||
391 | offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ | ||
392 | sdio_writel(bus->host_sdio, val, offset, &error); | ||
393 | if (error) { | ||
394 | dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %08x, error %d\n", | ||
395 | bus->sdio_sbaddr >> 16, offset, val, error); | ||
396 | } | ||
397 | if (bus->quirks & SSB_QUIRK_SDIO_READ_AFTER_WRITE32) | ||
398 | sdio_readl(bus->host_sdio, 0, &error); | ||
399 | out: | ||
400 | sdio_release_host(bus->host_sdio); | ||
401 | } | ||
402 | |||
403 | #ifdef CONFIG_SSB_BLOCKIO | ||
404 | static void ssb_sdio_block_write(struct ssb_device *dev, const void *buffer, | ||
405 | size_t count, u16 offset, u8 reg_width) | ||
406 | { | ||
407 | size_t saved_count = count; | ||
408 | struct ssb_bus *bus = dev->bus; | ||
409 | int error = 0; | ||
410 | |||
411 | sdio_claim_host(bus->host_sdio); | ||
412 | if (unlikely(ssb_sdio_switch_core(bus, dev))) { | ||
413 | error = -EIO; | ||
414 | memset((void *)buffer, 0xff, count); | ||
415 | goto err_out; | ||
416 | } | ||
417 | offset |= bus->sdio_sbaddr & 0xffff; | ||
418 | offset &= SBSDIO_SB_OFT_ADDR_MASK; | ||
419 | |||
420 | switch (reg_width) { | ||
421 | case sizeof(u8): | ||
422 | error = sdio_writesb(bus->host_sdio, offset, | ||
423 | (void *)buffer, count); | ||
424 | break; | ||
425 | case sizeof(u16): | ||
426 | SSB_WARN_ON(count & 1); | ||
427 | error = sdio_writesb(bus->host_sdio, offset, | ||
428 | (void *)buffer, count); | ||
429 | break; | ||
430 | case sizeof(u32): | ||
431 | SSB_WARN_ON(count & 3); | ||
432 | offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ | ||
433 | error = sdio_writesb(bus->host_sdio, offset, | ||
434 | (void *)buffer, count); | ||
435 | break; | ||
436 | default: | ||
437 | SSB_WARN_ON(1); | ||
438 | } | ||
439 | if (!error) | ||
440 | goto out; | ||
441 | |||
442 | err_out: | ||
443 | dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%u), error %d\n", | ||
444 | bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error); | ||
445 | out: | ||
446 | sdio_release_host(bus->host_sdio); | ||
447 | } | ||
448 | |||
449 | #endif /* CONFIG_SSB_BLOCKIO */ | ||
450 | |||
451 | /* Not "static", as it's used in main.c */ | ||
452 | const struct ssb_bus_ops ssb_sdio_ops = { | ||
453 | .read8 = ssb_sdio_read8, | ||
454 | .read16 = ssb_sdio_read16, | ||
455 | .read32 = ssb_sdio_read32, | ||
456 | .write8 = ssb_sdio_write8, | ||
457 | .write16 = ssb_sdio_write16, | ||
458 | .write32 = ssb_sdio_write32, | ||
459 | #ifdef CONFIG_SSB_BLOCKIO | ||
460 | .block_read = ssb_sdio_block_read, | ||
461 | .block_write = ssb_sdio_block_write, | ||
462 | #endif | ||
463 | }; | ||
464 | |||
465 | #define GOTO_ERROR_ON(condition, description) do { \ | ||
466 | if (unlikely(condition)) { \ | ||
467 | error_description = description; \ | ||
468 | goto error; \ | ||
469 | } \ | ||
470 | } while (0) | ||
471 | |||
472 | int ssb_sdio_get_invariants(struct ssb_bus *bus, | ||
473 | struct ssb_init_invariants *iv) | ||
474 | { | ||
475 | struct ssb_sprom *sprom = &iv->sprom; | ||
476 | struct ssb_boardinfo *bi = &iv->boardinfo; | ||
477 | const char *error_description = "none"; | ||
478 | struct sdio_func_tuple *tuple; | ||
479 | void *mac; | ||
480 | |||
481 | memset(sprom, 0xFF, sizeof(*sprom)); | ||
482 | sprom->boardflags_lo = 0; | ||
483 | sprom->boardflags_hi = 0; | ||
484 | |||
485 | tuple = bus->host_sdio->tuples; | ||
486 | while (tuple) { | ||
487 | switch (tuple->code) { | ||
488 | case 0x22: /* extended function */ | ||
489 | switch (tuple->data[0]) { | ||
490 | case CISTPL_FUNCE_LAN_NODE_ID: | ||
491 | GOTO_ERROR_ON((tuple->size != 7) && | ||
492 | (tuple->data[1] != 6), | ||
493 | "mac tpl size"); | ||
494 | /* fetch the MAC address. */ | ||
495 | mac = tuple->data + 2; | ||
496 | memcpy(sprom->il0mac, mac, ETH_ALEN); | ||
497 | memcpy(sprom->et1mac, mac, ETH_ALEN); | ||
498 | break; | ||
499 | default: | ||
500 | break; | ||
501 | } | ||
502 | break; | ||
503 | case 0x80: /* vendor specific tuple */ | ||
504 | switch (tuple->data[0]) { | ||
505 | case SSB_SDIO_CIS_SROMREV: | ||
506 | GOTO_ERROR_ON(tuple->size != 2, | ||
507 | "sromrev tpl size"); | ||
508 | sprom->revision = tuple->data[1]; | ||
509 | break; | ||
510 | case SSB_SDIO_CIS_ID: | ||
511 | GOTO_ERROR_ON((tuple->size != 5) && | ||
512 | (tuple->size != 7), | ||
513 | "id tpl size"); | ||
514 | bi->vendor = tuple->data[1] | | ||
515 | (tuple->data[2]<<8); | ||
516 | break; | ||
517 | case SSB_SDIO_CIS_BOARDREV: | ||
518 | GOTO_ERROR_ON(tuple->size != 2, | ||
519 | "boardrev tpl size"); | ||
520 | sprom->board_rev = tuple->data[1]; | ||
521 | break; | ||
522 | case SSB_SDIO_CIS_PA: | ||
523 | GOTO_ERROR_ON((tuple->size != 9) && | ||
524 | (tuple->size != 10), | ||
525 | "pa tpl size"); | ||
526 | sprom->pa0b0 = tuple->data[1] | | ||
527 | ((u16)tuple->data[2] << 8); | ||
528 | sprom->pa0b1 = tuple->data[3] | | ||
529 | ((u16)tuple->data[4] << 8); | ||
530 | sprom->pa0b2 = tuple->data[5] | | ||
531 | ((u16)tuple->data[6] << 8); | ||
532 | sprom->itssi_a = tuple->data[7]; | ||
533 | sprom->itssi_bg = tuple->data[7]; | ||
534 | sprom->maxpwr_a = tuple->data[8]; | ||
535 | sprom->maxpwr_bg = tuple->data[8]; | ||
536 | break; | ||
537 | case SSB_SDIO_CIS_OEMNAME: | ||
538 | /* Not present */ | ||
539 | break; | ||
540 | case SSB_SDIO_CIS_CCODE: | ||
541 | GOTO_ERROR_ON(tuple->size != 2, | ||
542 | "ccode tpl size"); | ||
543 | sprom->country_code = tuple->data[1]; | ||
544 | break; | ||
545 | case SSB_SDIO_CIS_ANTENNA: | ||
546 | GOTO_ERROR_ON(tuple->size != 2, | ||
547 | "ant tpl size"); | ||
548 | sprom->ant_available_a = tuple->data[1]; | ||
549 | sprom->ant_available_bg = tuple->data[1]; | ||
550 | break; | ||
551 | case SSB_SDIO_CIS_ANTGAIN: | ||
552 | GOTO_ERROR_ON(tuple->size != 2, | ||
553 | "antg tpl size"); | ||
554 | sprom->antenna_gain.ghz24.a0 = tuple->data[1]; | ||
555 | sprom->antenna_gain.ghz24.a1 = tuple->data[1]; | ||
556 | sprom->antenna_gain.ghz24.a2 = tuple->data[1]; | ||
557 | sprom->antenna_gain.ghz24.a3 = tuple->data[1]; | ||
558 | sprom->antenna_gain.ghz5.a0 = tuple->data[1]; | ||
559 | sprom->antenna_gain.ghz5.a1 = tuple->data[1]; | ||
560 | sprom->antenna_gain.ghz5.a2 = tuple->data[1]; | ||
561 | sprom->antenna_gain.ghz5.a3 = tuple->data[1]; | ||
562 | break; | ||
563 | case SSB_SDIO_CIS_BFLAGS: | ||
564 | GOTO_ERROR_ON((tuple->size != 3) && | ||
565 | (tuple->size != 5), | ||
566 | "bfl tpl size"); | ||
567 | sprom->boardflags_lo = tuple->data[1] | | ||
568 | ((u16)tuple->data[2] << 8); | ||
569 | break; | ||
570 | case SSB_SDIO_CIS_LEDS: | ||
571 | GOTO_ERROR_ON(tuple->size != 5, | ||
572 | "leds tpl size"); | ||
573 | sprom->gpio0 = tuple->data[1]; | ||
574 | sprom->gpio1 = tuple->data[2]; | ||
575 | sprom->gpio2 = tuple->data[3]; | ||
576 | sprom->gpio3 = tuple->data[4]; | ||
577 | break; | ||
578 | default: | ||
579 | break; | ||
580 | } | ||
581 | break; | ||
582 | default: | ||
583 | break; | ||
584 | } | ||
585 | tuple = tuple->next; | ||
586 | } | ||
587 | |||
588 | return 0; | ||
589 | error: | ||
590 | dev_err(ssb_sdio_dev(bus), "failed to fetch device invariants: %s\n", | ||
591 | error_description); | ||
592 | return -ENODEV; | ||
593 | } | ||
594 | |||
595 | void ssb_sdio_exit(struct ssb_bus *bus) | ||
596 | { | ||
597 | if (bus->bustype != SSB_BUSTYPE_SDIO) | ||
598 | return; | ||
599 | /* Nothing to do here. */ | ||
600 | } | ||
601 | |||
602 | int ssb_sdio_init(struct ssb_bus *bus) | ||
603 | { | ||
604 | if (bus->bustype != SSB_BUSTYPE_SDIO) | ||
605 | return 0; | ||
606 | |||
607 | bus->sdio_sbaddr = ~0; | ||
608 | |||
609 | return 0; | ||
610 | } | ||
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 57fa482abb94..25433565dfda 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) | |||
114 | } | 114 | } |
115 | #endif /* CONFIG_SSB_PCMCIAHOST */ | 115 | #endif /* CONFIG_SSB_PCMCIAHOST */ |
116 | 116 | ||
117 | /* sdio.c */ | ||
118 | #ifdef CONFIG_SSB_SDIOHOST | ||
119 | extern int ssb_sdio_get_invariants(struct ssb_bus *bus, | ||
120 | struct ssb_init_invariants *iv); | ||
121 | |||
122 | extern u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset); | ||
123 | extern int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev); | ||
124 | extern int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx); | ||
125 | extern int ssb_sdio_hardware_setup(struct ssb_bus *bus); | ||
126 | extern void ssb_sdio_exit(struct ssb_bus *bus); | ||
127 | extern int ssb_sdio_init(struct ssb_bus *bus); | ||
128 | |||
129 | extern const struct ssb_bus_ops ssb_sdio_ops; | ||
130 | #else /* CONFIG_SSB_SDIOHOST */ | ||
131 | static inline u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset) | ||
132 | { | ||
133 | return 0; | ||
134 | } | ||
135 | static inline int ssb_sdio_switch_core(struct ssb_bus *bus, | ||
136 | struct ssb_device *dev) | ||
137 | { | ||
138 | return 0; | ||
139 | } | ||
140 | static inline int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx) | ||
141 | { | ||
142 | return 0; | ||
143 | } | ||
144 | static inline int ssb_sdio_hardware_setup(struct ssb_bus *bus) | ||
145 | { | ||
146 | return 0; | ||
147 | } | ||
148 | static inline void ssb_sdio_exit(struct ssb_bus *bus) | ||
149 | { | ||
150 | } | ||
151 | static inline int ssb_sdio_init(struct ssb_bus *bus) | ||
152 | { | ||
153 | return 0; | ||
154 | } | ||
155 | #endif /* CONFIG_SSB_SDIOHOST */ | ||
156 | |||
117 | 157 | ||
118 | /* scan.c */ | 158 | /* scan.c */ |
119 | extern const char *ssb_core_name(u16 coreid); | 159 | extern const char *ssb_core_name(u16 coreid); |
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 17ffc1f84d76..3d0a9ff24f01 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h | |||
@@ -238,6 +238,7 @@ enum ssb_bustype { | |||
238 | SSB_BUSTYPE_SSB, /* This SSB bus is the system bus */ | 238 | SSB_BUSTYPE_SSB, /* This SSB bus is the system bus */ |
239 | SSB_BUSTYPE_PCI, /* SSB is connected to PCI bus */ | 239 | SSB_BUSTYPE_PCI, /* SSB is connected to PCI bus */ |
240 | SSB_BUSTYPE_PCMCIA, /* SSB is connected to PCMCIA bus */ | 240 | SSB_BUSTYPE_PCMCIA, /* SSB is connected to PCMCIA bus */ |
241 | SSB_BUSTYPE_SDIO, /* SSB is connected to SDIO bus */ | ||
241 | }; | 242 | }; |
242 | 243 | ||
243 | /* board_vendor */ | 244 | /* board_vendor */ |
@@ -270,8 +271,12 @@ struct ssb_bus { | |||
270 | 271 | ||
271 | /* The core in the basic address register window. (PCI bus only) */ | 272 | /* The core in the basic address register window. (PCI bus only) */ |
272 | struct ssb_device *mapped_device; | 273 | struct ssb_device *mapped_device; |
273 | /* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA only) */ | 274 | union { |
274 | u8 mapped_pcmcia_seg; | 275 | /* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA only) */ |
276 | u8 mapped_pcmcia_seg; | ||
277 | /* Current SSB base address window for SDIO. */ | ||
278 | u32 sdio_sbaddr; | ||
279 | }; | ||
275 | /* Lock for core and segment switching. | 280 | /* Lock for core and segment switching. |
276 | * On PCMCIA-host busses this is used to protect the whole MMIO access. */ | 281 | * On PCMCIA-host busses this is used to protect the whole MMIO access. */ |
277 | spinlock_t bar_lock; | 282 | spinlock_t bar_lock; |
@@ -282,6 +287,11 @@ struct ssb_bus { | |||
282 | struct pci_dev *host_pci; | 287 | struct pci_dev *host_pci; |
283 | /* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */ | 288 | /* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */ |
284 | struct pcmcia_device *host_pcmcia; | 289 | struct pcmcia_device *host_pcmcia; |
290 | /* Pointer to the SDIO device (only if bustype == SSB_BUSTYPE_SDIO). */ | ||
291 | struct sdio_func *host_sdio; | ||
292 | |||
293 | /* See enum ssb_quirks */ | ||
294 | unsigned int quirks; | ||
285 | 295 | ||
286 | #ifdef CONFIG_SSB_SPROM | 296 | #ifdef CONFIG_SSB_SPROM |
287 | /* Mutex to protect the SPROM writing. */ | 297 | /* Mutex to protect the SPROM writing. */ |
@@ -336,6 +346,11 @@ struct ssb_bus { | |||
336 | #endif /* DEBUG */ | 346 | #endif /* DEBUG */ |
337 | }; | 347 | }; |
338 | 348 | ||
349 | enum ssb_quirks { | ||
350 | /* SDIO connected card requires performing a read after writing a 32-bit value */ | ||
351 | SSB_QUIRK_SDIO_READ_AFTER_WRITE32 = (1 << 0), | ||
352 | }; | ||
353 | |||
339 | /* The initialization-invariants. */ | 354 | /* The initialization-invariants. */ |
340 | struct ssb_init_invariants { | 355 | struct ssb_init_invariants { |
341 | /* Versioning information about the PCB. */ | 356 | /* Versioning information about the PCB. */ |
@@ -366,6 +381,12 @@ extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus, | |||
366 | struct pcmcia_device *pcmcia_dev, | 381 | struct pcmcia_device *pcmcia_dev, |
367 | unsigned long baseaddr); | 382 | unsigned long baseaddr); |
368 | #endif /* CONFIG_SSB_PCMCIAHOST */ | 383 | #endif /* CONFIG_SSB_PCMCIAHOST */ |
384 | #ifdef CONFIG_SSB_SDIOHOST | ||
385 | extern int ssb_bus_sdiobus_register(struct ssb_bus *bus, | ||
386 | struct sdio_func *sdio_func, | ||
387 | unsigned int quirks); | ||
388 | #endif /* CONFIG_SSB_SDIOHOST */ | ||
389 | |||
369 | 390 | ||
370 | extern void ssb_bus_unregister(struct ssb_bus *bus); | 391 | extern void ssb_bus_unregister(struct ssb_bus *bus); |
371 | 392 | ||
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 68c504fab122..abf7ca3f9ff9 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
@@ -1,6 +1,15 @@ | |||
1 | config CFG80211 | 1 | config CFG80211 |
2 | tristate "Improved wireless configuration API" | 2 | tristate "cfg80211 - wireless configuration API" |
3 | depends on RFKILL || !RFKILL | 3 | depends on RFKILL || !RFKILL |
4 | ---help--- | ||
5 | cfg80211 is the Linux wireless LAN (802.11) configuration API. | ||
6 | Enable this if you have a wireless device. | ||
7 | |||
8 | For more information refer to documentation on the wireless wiki: | ||
9 | |||
10 | http://wireless.kernel.org/en/developers/Documentation/cfg80211 | ||
11 | |||
12 | When built as a module it will be called cfg80211. | ||
4 | 13 | ||
5 | config NL80211_TESTMODE | 14 | config NL80211_TESTMODE |
6 | bool "nl80211 testmode command" | 15 | bool "nl80211 testmode command" |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 19c5a9a8d085..4c210c2debc6 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -607,6 +607,9 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
607 | if (!netif_running(dev)) | 607 | if (!netif_running(dev)) |
608 | return -ENETDOWN; | 608 | return -ENETDOWN; |
609 | 609 | ||
610 | if (wrqu->data.length == sizeof(struct iw_scan_req)) | ||
611 | wreq = (struct iw_scan_req *)extra; | ||
612 | |||
610 | rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); | 613 | rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); |
611 | 614 | ||
612 | if (IS_ERR(rdev)) | 615 | if (IS_ERR(rdev)) |
@@ -619,9 +622,14 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
619 | 622 | ||
620 | wiphy = &rdev->wiphy; | 623 | wiphy = &rdev->wiphy; |
621 | 624 | ||
622 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | 625 | /* Determine number of channels, needed to allocate creq */ |
623 | if (wiphy->bands[band]) | 626 | if (wreq && wreq->num_channels) |
624 | n_channels += wiphy->bands[band]->n_channels; | 627 | n_channels = wreq->num_channels; |
628 | else { | ||
629 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | ||
630 | if (wiphy->bands[band]) | ||
631 | n_channels += wiphy->bands[band]->n_channels; | ||
632 | } | ||
625 | 633 | ||
626 | creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) + | 634 | creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) + |
627 | n_channels * sizeof(void *), | 635 | n_channels * sizeof(void *), |
@@ -638,22 +646,41 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
638 | creq->n_channels = n_channels; | 646 | creq->n_channels = n_channels; |
639 | creq->n_ssids = 1; | 647 | creq->n_ssids = 1; |
640 | 648 | ||
641 | /* all channels */ | 649 | /* translate "Scan on frequencies" request */ |
642 | i = 0; | 650 | i = 0; |
643 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 651 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
644 | int j; | 652 | int j; |
645 | if (!wiphy->bands[band]) | 653 | if (!wiphy->bands[band]) |
646 | continue; | 654 | continue; |
647 | for (j = 0; j < wiphy->bands[band]->n_channels; j++) { | 655 | for (j = 0; j < wiphy->bands[band]->n_channels; j++) { |
656 | |||
657 | /* If we have a wireless request structure and the | ||
658 | * wireless request specifies frequencies, then search | ||
659 | * for the matching hardware channel. | ||
660 | */ | ||
661 | if (wreq && wreq->num_channels) { | ||
662 | int k; | ||
663 | int wiphy_freq = wiphy->bands[band]->channels[j].center_freq; | ||
664 | for (k = 0; k < wreq->num_channels; k++) { | ||
665 | int wext_freq = wreq->channel_list[k].m / 100000; | ||
666 | if (wext_freq == wiphy_freq) | ||
667 | goto wext_freq_found; | ||
668 | } | ||
669 | goto wext_freq_not_found; | ||
670 | } | ||
671 | |||
672 | wext_freq_found: | ||
648 | creq->channels[i] = &wiphy->bands[band]->channels[j]; | 673 | creq->channels[i] = &wiphy->bands[band]->channels[j]; |
649 | i++; | 674 | i++; |
675 | wext_freq_not_found: ; | ||
650 | } | 676 | } |
651 | } | 677 | } |
652 | 678 | ||
653 | /* translate scan request */ | 679 | /* Set real number of channels specified in creq->channels[] */ |
654 | if (wrqu->data.length == sizeof(struct iw_scan_req)) { | 680 | creq->n_channels = i; |
655 | wreq = (struct iw_scan_req *)extra; | ||
656 | 681 | ||
682 | /* translate "Scan for SSID" request */ | ||
683 | if (wreq) { | ||
657 | if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { | 684 | if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { |
658 | if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) | 685 | if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) |
659 | return -EINVAL; | 686 | return -EINVAL; |