diff options
175 files changed, 21960 insertions, 7592 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 22af4965c16c..866253d7abd7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -3583,9 +3583,12 @@ M: "John W. Linville" <linville@tuxdriver.com> | |||
3583 | L: linux-wireless@vger.kernel.org | 3583 | L: linux-wireless@vger.kernel.org |
3584 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git | 3584 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git |
3585 | S: Maintained | 3585 | S: Maintained |
3586 | F: net/mac80211/ | ||
3587 | F: net/rfkill/ | ||
3586 | F: net/wireless/ | 3588 | F: net/wireless/ |
3587 | F: include/net/ieee80211* | 3589 | F: include/net/ieee80211* |
3588 | F: include/linux/wireless.h | 3590 | F: include/linux/wireless.h |
3591 | F: drivers/net/wireless/ | ||
3589 | 3592 | ||
3590 | NETWORKING DRIVERS | 3593 | NETWORKING DRIVERS |
3591 | L: netdev@vger.kernel.org | 3594 | L: netdev@vger.kernel.org |
@@ -5577,7 +5580,16 @@ L: linux-wireless@vger.kernel.org | |||
5577 | W: http://wireless.kernel.org | 5580 | W: http://wireless.kernel.org |
5578 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git | 5581 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git |
5579 | S: Maintained | 5582 | S: Maintained |
5580 | F: drivers/net/wireless/wl12xx/wl1251* | 5583 | F: drivers/net/wireless/wl12xx/* |
5584 | X: drivers/net/wireless/wl12xx/wl1271* | ||
5585 | |||
5586 | WL1271 WIRELESS DRIVER | ||
5587 | M: Luciano Coelho <luciano.coelho@nokia.com> | ||
5588 | L: linux-wireless@vger.kernel.org | ||
5589 | W: http://wireless.kernel.org | ||
5590 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git | ||
5591 | S: Maintained | ||
5592 | F: drivers/net/wireless/wl12xx/wl1271* | ||
5581 | 5593 | ||
5582 | WL3501 WIRELESS PCMCIA CARD DRIVER | 5594 | WL3501 WIRELESS PCMCIA CARD DRIVER |
5583 | M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> | 5595 | M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> |
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index af1fe4696509..7d471fca2743 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c | |||
@@ -233,6 +233,11 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) | |||
233 | { | 233 | { |
234 | int status; | 234 | int status; |
235 | 235 | ||
236 | if (test_bit(EVENT_RX_PAUSED, &dev->flags)) { | ||
237 | skb_queue_tail(&dev->rxq_pause, skb); | ||
238 | return; | ||
239 | } | ||
240 | |||
236 | skb->protocol = eth_type_trans (skb, dev->net); | 241 | skb->protocol = eth_type_trans (skb, dev->net); |
237 | dev->net->stats.rx_packets++; | 242 | dev->net->stats.rx_packets++; |
238 | dev->net->stats.rx_bytes += skb->len; | 243 | dev->net->stats.rx_bytes += skb->len; |
@@ -526,6 +531,41 @@ static void intr_complete (struct urb *urb) | |||
526 | } | 531 | } |
527 | 532 | ||
528 | /*-------------------------------------------------------------------------*/ | 533 | /*-------------------------------------------------------------------------*/ |
534 | void usbnet_pause_rx(struct usbnet *dev) | ||
535 | { | ||
536 | set_bit(EVENT_RX_PAUSED, &dev->flags); | ||
537 | |||
538 | if (netif_msg_rx_status(dev)) | ||
539 | devdbg(dev, "paused rx queue enabled"); | ||
540 | } | ||
541 | EXPORT_SYMBOL_GPL(usbnet_pause_rx); | ||
542 | |||
543 | void usbnet_resume_rx(struct usbnet *dev) | ||
544 | { | ||
545 | struct sk_buff *skb; | ||
546 | int num = 0; | ||
547 | |||
548 | clear_bit(EVENT_RX_PAUSED, &dev->flags); | ||
549 | |||
550 | while ((skb = skb_dequeue(&dev->rxq_pause)) != NULL) { | ||
551 | usbnet_skb_return(dev, skb); | ||
552 | num++; | ||
553 | } | ||
554 | |||
555 | tasklet_schedule(&dev->bh); | ||
556 | |||
557 | if (netif_msg_rx_status(dev)) | ||
558 | devdbg(dev, "paused rx queue disabled, %d skbs requeued", num); | ||
559 | } | ||
560 | EXPORT_SYMBOL_GPL(usbnet_resume_rx); | ||
561 | |||
562 | void usbnet_purge_paused_rxq(struct usbnet *dev) | ||
563 | { | ||
564 | skb_queue_purge(&dev->rxq_pause); | ||
565 | } | ||
566 | EXPORT_SYMBOL_GPL(usbnet_purge_paused_rxq); | ||
567 | |||
568 | /*-------------------------------------------------------------------------*/ | ||
529 | 569 | ||
530 | // unlink pending rx/tx; completion handlers do all other cleanup | 570 | // unlink pending rx/tx; completion handlers do all other cleanup |
531 | 571 | ||
@@ -623,6 +663,8 @@ int usbnet_stop (struct net_device *net) | |||
623 | 663 | ||
624 | usb_kill_urb(dev->interrupt); | 664 | usb_kill_urb(dev->interrupt); |
625 | 665 | ||
666 | usbnet_purge_paused_rxq(dev); | ||
667 | |||
626 | /* deferred work (task, timer, softirq) must also stop. | 668 | /* deferred work (task, timer, softirq) must also stop. |
627 | * can't flush_scheduled_work() until we drop rtnl (later), | 669 | * can't flush_scheduled_work() until we drop rtnl (later), |
628 | * else workers could deadlock; so make workers a NOP. | 670 | * else workers could deadlock; so make workers a NOP. |
@@ -1113,7 +1155,6 @@ static void usbnet_bh (unsigned long param) | |||
1113 | } | 1155 | } |
1114 | 1156 | ||
1115 | 1157 | ||
1116 | |||
1117 | /*------------------------------------------------------------------------- | 1158 | /*------------------------------------------------------------------------- |
1118 | * | 1159 | * |
1119 | * USB Device Driver support | 1160 | * USB Device Driver support |
@@ -1210,6 +1251,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) | |||
1210 | skb_queue_head_init (&dev->rxq); | 1251 | skb_queue_head_init (&dev->rxq); |
1211 | skb_queue_head_init (&dev->txq); | 1252 | skb_queue_head_init (&dev->txq); |
1212 | skb_queue_head_init (&dev->done); | 1253 | skb_queue_head_init (&dev->done); |
1254 | skb_queue_head_init(&dev->rxq_pause); | ||
1213 | dev->bh.func = usbnet_bh; | 1255 | dev->bh.func = usbnet_bh; |
1214 | dev->bh.data = (unsigned long) dev; | 1256 | dev->bh.data = (unsigned long) dev; |
1215 | INIT_WORK (&dev->kevent, kevent); | 1257 | INIT_WORK (&dev->kevent, kevent); |
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 253b95a264b1..11ded150b932 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig | |||
@@ -5,9 +5,7 @@ menuconfig ATH_COMMON | |||
5 | ---help--- | 5 | ---help--- |
6 | This will enable the support for the Atheros wireless drivers. | 6 | This will enable the support for the Atheros wireless drivers. |
7 | ath5k, ath9k and ar9170 drivers share some common code, this option | 7 | ath5k, ath9k and ar9170 drivers share some common code, this option |
8 | enables the common ath.ko module which currently shares just common | 8 | enables the common ath.ko module which shares common helpers. |
9 | regulatory EEPROM helpers but will likely be extended later to share | ||
10 | more between modules. | ||
11 | 9 | ||
12 | For more information and documentation on this module you can visit: | 10 | For more information and documentation on this module you can visit: |
13 | 11 | ||
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h new file mode 100644 index 000000000000..e284cd3ac6d4 --- /dev/null +++ b/drivers/net/wireless/ath/ath.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008-2009 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef ATH_H | ||
18 | #define ATH_H | ||
19 | |||
20 | #include <linux/skbuff.h> | ||
21 | |||
22 | struct ath_common { | ||
23 | u16 cachelsz; | ||
24 | }; | ||
25 | |||
26 | struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, | ||
27 | u32 len, | ||
28 | gfp_t gfp_mask); | ||
29 | |||
30 | #endif /* ATH_H */ | ||
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 91375113916b..c09402eea7f3 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h | |||
@@ -919,6 +919,12 @@ enum ath5k_int { | |||
919 | AR5K_INT_NOCARD = 0xffffffff | 919 | AR5K_INT_NOCARD = 0xffffffff |
920 | }; | 920 | }; |
921 | 921 | ||
922 | /* Software interrupts used for calibration */ | ||
923 | enum ath5k_software_interrupt { | ||
924 | AR5K_SWI_FULL_CALIBRATION = 0x01, | ||
925 | AR5K_SWI_SHORT_CALIBRATION = 0x02, | ||
926 | }; | ||
927 | |||
922 | /* | 928 | /* |
923 | * Power management | 929 | * Power management |
924 | */ | 930 | */ |
@@ -1123,6 +1129,15 @@ struct ath5k_hw { | |||
1123 | /* noise floor from last periodic calibration */ | 1129 | /* noise floor from last periodic calibration */ |
1124 | s32 ah_noise_floor; | 1130 | s32 ah_noise_floor; |
1125 | 1131 | ||
1132 | /* Calibration timestamp */ | ||
1133 | unsigned long ah_cal_tstamp; | ||
1134 | |||
1135 | /* Calibration interval (secs) */ | ||
1136 | u8 ah_cal_intval; | ||
1137 | |||
1138 | /* Software interrupt mask */ | ||
1139 | u8 ah_swi_mask; | ||
1140 | |||
1126 | /* | 1141 | /* |
1127 | * Function pointers | 1142 | * Function pointers |
1128 | */ | 1143 | */ |
@@ -1157,6 +1172,7 @@ extern void ath5k_unregister_leds(struct ath5k_softc *sc); | |||
1157 | 1172 | ||
1158 | /* Reset Functions */ | 1173 | /* Reset Functions */ |
1159 | extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial); | 1174 | extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial); |
1175 | extern int ath5k_hw_on_hold(struct ath5k_hw *ah); | ||
1160 | extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel); | 1176 | extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel); |
1161 | /* Power management functions */ | 1177 | /* Power management functions */ |
1162 | extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration); | 1178 | extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration); |
@@ -1275,6 +1291,7 @@ extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *chann | |||
1275 | /* PHY calibration */ | 1291 | /* PHY calibration */ |
1276 | extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); | 1292 | extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); |
1277 | extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); | 1293 | extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); |
1294 | extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah); | ||
1278 | /* Spur mitigation */ | 1295 | /* Spur mitigation */ |
1279 | bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, | 1296 | bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, |
1280 | struct ieee80211_channel *channel); | 1297 | struct ieee80211_channel *channel); |
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 9a84d9410b27..65d438b59f64 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c | |||
@@ -145,7 +145,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) | |||
145 | goto err_free; | 145 | goto err_free; |
146 | 146 | ||
147 | /* Bring device out of sleep and reset it's units */ | 147 | /* Bring device out of sleep and reset it's units */ |
148 | ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true); | 148 | ret = ath5k_hw_nic_wakeup(ah, 0, true); |
149 | if (ret) | 149 | if (ret) |
150 | goto err_free; | 150 | goto err_free; |
151 | 151 | ||
@@ -253,28 +253,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) | |||
253 | } | 253 | } |
254 | 254 | ||
255 | /* | 255 | /* |
256 | * Write PCI-E power save settings | ||
257 | */ | ||
258 | if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { | ||
259 | ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES); | ||
260 | ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES); | ||
261 | /* Shut off RX when elecidle is asserted */ | ||
262 | ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES); | ||
263 | ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES); | ||
264 | /* TODO: EEPROM work */ | ||
265 | ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES); | ||
266 | /* Shut off PLL and CLKREQ active in L1 */ | ||
267 | ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES); | ||
268 | /* Preserce other settings */ | ||
269 | ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES); | ||
270 | ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES); | ||
271 | ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES); | ||
272 | /* Reset SERDES to load new settings */ | ||
273 | ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET); | ||
274 | mdelay(1); | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * POST | 256 | * POST |
279 | */ | 257 | */ |
280 | ret = ath5k_hw_post(ah); | 258 | ret = ath5k_hw_post(ah); |
@@ -283,7 +261,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) | |||
283 | 261 | ||
284 | /* Enable pci core retry fix on Hainan (5213A) and later chips */ | 262 | /* Enable pci core retry fix on Hainan (5213A) and later chips */ |
285 | if (srev >= AR5K_SREV_AR5213A) | 263 | if (srev >= AR5K_SREV_AR5213A) |
286 | ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG); | 264 | AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_RETRY_FIX); |
287 | 265 | ||
288 | /* | 266 | /* |
289 | * Get card capabilities, calibration values etc | 267 | * Get card capabilities, calibration values etc |
@@ -295,6 +273,40 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) | |||
295 | goto err_free; | 273 | goto err_free; |
296 | } | 274 | } |
297 | 275 | ||
276 | /* | ||
277 | * Write PCI-E power save settings | ||
278 | */ | ||
279 | if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { | ||
280 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
281 | |||
282 | ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES); | ||
283 | ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES); | ||
284 | |||
285 | /* Shut off RX when elecidle is asserted */ | ||
286 | ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES); | ||
287 | ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES); | ||
288 | |||
289 | /* If serdes programing is enabled, increase PCI-E | ||
290 | * tx power for systems with long trace from host | ||
291 | * to minicard connector. */ | ||
292 | if (ee->ee_serdes) | ||
293 | ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES); | ||
294 | else | ||
295 | ath5k_hw_reg_write(ah, 0xf6800579, AR5K_PCIE_SERDES); | ||
296 | |||
297 | /* Shut off PLL and CLKREQ active in L1 */ | ||
298 | ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES); | ||
299 | |||
300 | /* Preserve other settings */ | ||
301 | ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES); | ||
302 | ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES); | ||
303 | ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES); | ||
304 | |||
305 | /* Reset SERDES to load new settings */ | ||
306 | ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET); | ||
307 | mdelay(1); | ||
308 | } | ||
309 | |||
298 | /* Get misc capabilities */ | 310 | /* Get misc capabilities */ |
299 | ret = ath5k_hw_set_capabilities(ah); | 311 | ret = ath5k_hw_set_capabilities(ah); |
300 | if (ret) { | 312 | if (ret) { |
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 3a1c156d275f..2b3cf39dd4b1 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -59,7 +59,7 @@ | |||
59 | #include "reg.h" | 59 | #include "reg.h" |
60 | #include "debug.h" | 60 | #include "debug.h" |
61 | 61 | ||
62 | static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ | 62 | static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ |
63 | static int modparam_nohwcrypt; | 63 | static int modparam_nohwcrypt; |
64 | module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); | 64 | module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); |
65 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | 65 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); |
@@ -376,7 +376,7 @@ static int ath5k_stop_hw(struct ath5k_softc *sc); | |||
376 | static irqreturn_t ath5k_intr(int irq, void *dev_id); | 376 | static irqreturn_t ath5k_intr(int irq, void *dev_id); |
377 | static void ath5k_tasklet_reset(unsigned long data); | 377 | static void ath5k_tasklet_reset(unsigned long data); |
378 | 378 | ||
379 | static void ath5k_calibrate(unsigned long data); | 379 | static void ath5k_tasklet_calibrate(unsigned long data); |
380 | 380 | ||
381 | /* | 381 | /* |
382 | * Module init/exit functions | 382 | * Module init/exit functions |
@@ -471,7 +471,7 @@ ath5k_pci_probe(struct pci_dev *pdev, | |||
471 | * DMA to work so force a reasonable value here if it | 471 | * DMA to work so force a reasonable value here if it |
472 | * comes up zero. | 472 | * comes up zero. |
473 | */ | 473 | */ |
474 | csz = L1_CACHE_BYTES / sizeof(u32); | 474 | csz = L1_CACHE_BYTES >> 2; |
475 | pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); | 475 | pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); |
476 | } | 476 | } |
477 | /* | 477 | /* |
@@ -544,7 +544,7 @@ ath5k_pci_probe(struct pci_dev *pdev, | |||
544 | __set_bit(ATH_STAT_INVALID, sc->status); | 544 | __set_bit(ATH_STAT_INVALID, sc->status); |
545 | 545 | ||
546 | sc->iobase = mem; /* So we can unmap it on detach */ | 546 | sc->iobase = mem; /* So we can unmap it on detach */ |
547 | sc->cachelsz = csz * sizeof(u32); /* convert to bytes */ | 547 | sc->common.cachelsz = csz << 2; /* convert to bytes */ |
548 | sc->opmode = NL80211_IFTYPE_STATION; | 548 | sc->opmode = NL80211_IFTYPE_STATION; |
549 | sc->bintval = 1000; | 549 | sc->bintval = 1000; |
550 | mutex_init(&sc->lock); | 550 | mutex_init(&sc->lock); |
@@ -799,8 +799,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) | |||
799 | tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); | 799 | tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); |
800 | tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); | 800 | tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); |
801 | tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); | 801 | tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); |
802 | tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc); | ||
802 | tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); | 803 | tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); |
803 | setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); | ||
804 | 804 | ||
805 | ret = ath5k_eeprom_read_mac(ah, mac); | 805 | ret = ath5k_eeprom_read_mac(ah, mac); |
806 | if (ret) { | 806 | if (ret) { |
@@ -1071,10 +1071,9 @@ ath5k_setup_bands(struct ieee80211_hw *hw) | |||
1071 | } | 1071 | } |
1072 | 1072 | ||
1073 | /* | 1073 | /* |
1074 | * Set/change channels. If the channel is really being changed, | 1074 | * Set/change channels. We always reset the chip. |
1075 | * it's done by reseting the chip. To accomplish this we must | 1075 | * To accomplish this we must first cleanup any pending DMA, |
1076 | * first cleanup any pending DMA, then restart stuff after a la | 1076 | * then restart stuff after a la ath5k_init. |
1077 | * ath5k_init. | ||
1078 | * | 1077 | * |
1079 | * Called with sc->lock. | 1078 | * Called with sc->lock. |
1080 | */ | 1079 | */ |
@@ -1084,19 +1083,13 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) | |||
1084 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n", | 1083 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n", |
1085 | sc->curchan->center_freq, chan->center_freq); | 1084 | sc->curchan->center_freq, chan->center_freq); |
1086 | 1085 | ||
1087 | if (chan->center_freq != sc->curchan->center_freq || | 1086 | /* |
1088 | chan->hw_value != sc->curchan->hw_value) { | 1087 | * To switch channels clear any pending DMA operations; |
1089 | 1088 | * wait long enough for the RX fifo to drain, reset the | |
1090 | /* | 1089 | * hardware at the new frequency, and then re-enable |
1091 | * To switch channels clear any pending DMA operations; | 1090 | * the relevant bits of the h/w. |
1092 | * wait long enough for the RX fifo to drain, reset the | 1091 | */ |
1093 | * hardware at the new frequency, and then re-enable | 1092 | return ath5k_reset(sc, chan); |
1094 | * the relevant bits of the h/w. | ||
1095 | */ | ||
1096 | return ath5k_reset(sc, chan); | ||
1097 | } | ||
1098 | |||
1099 | return 0; | ||
1100 | } | 1093 | } |
1101 | 1094 | ||
1102 | static void | 1095 | static void |
@@ -1158,27 +1151,20 @@ static | |||
1158 | struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr) | 1151 | struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr) |
1159 | { | 1152 | { |
1160 | struct sk_buff *skb; | 1153 | struct sk_buff *skb; |
1161 | unsigned int off; | ||
1162 | 1154 | ||
1163 | /* | 1155 | /* |
1164 | * Allocate buffer with headroom_needed space for the | 1156 | * Allocate buffer with headroom_needed space for the |
1165 | * fake physical layer header at the start. | 1157 | * fake physical layer header at the start. |
1166 | */ | 1158 | */ |
1167 | skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1); | 1159 | skb = ath_rxbuf_alloc(&sc->common, |
1160 | sc->rxbufsize + sc->common.cachelsz - 1, | ||
1161 | GFP_ATOMIC); | ||
1168 | 1162 | ||
1169 | if (!skb) { | 1163 | if (!skb) { |
1170 | ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", | 1164 | ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", |
1171 | sc->rxbufsize + sc->cachelsz - 1); | 1165 | sc->rxbufsize + sc->common.cachelsz - 1); |
1172 | return NULL; | 1166 | return NULL; |
1173 | } | 1167 | } |
1174 | /* | ||
1175 | * Cache-line-align. This is important (for the | ||
1176 | * 5210 at least) as not doing so causes bogus data | ||
1177 | * in rx'd frames. | ||
1178 | */ | ||
1179 | off = ((unsigned long)skb->data) % sc->cachelsz; | ||
1180 | if (off != 0) | ||
1181 | skb_reserve(skb, sc->cachelsz - off); | ||
1182 | 1168 | ||
1183 | *skb_addr = pci_map_single(sc->pdev, | 1169 | *skb_addr = pci_map_single(sc->pdev, |
1184 | skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); | 1170 | skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); |
@@ -1620,10 +1606,10 @@ ath5k_rx_start(struct ath5k_softc *sc) | |||
1620 | struct ath5k_buf *bf; | 1606 | struct ath5k_buf *bf; |
1621 | int ret; | 1607 | int ret; |
1622 | 1608 | ||
1623 | sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz); | 1609 | sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz); |
1624 | 1610 | ||
1625 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n", | 1611 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n", |
1626 | sc->cachelsz, sc->rxbufsize); | 1612 | sc->common.cachelsz, sc->rxbufsize); |
1627 | 1613 | ||
1628 | spin_lock_bh(&sc->rxbuflock); | 1614 | spin_lock_bh(&sc->rxbuflock); |
1629 | sc->rxlink = NULL; | 1615 | sc->rxlink = NULL; |
@@ -2371,7 +2357,7 @@ ath5k_init(struct ath5k_softc *sc) | |||
2371 | sc->curband = &sc->sbands[sc->curchan->band]; | 2357 | sc->curband = &sc->sbands[sc->curchan->band]; |
2372 | sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | | 2358 | sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | |
2373 | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | | 2359 | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | |
2374 | AR5K_INT_FATAL | AR5K_INT_GLOBAL; | 2360 | AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI; |
2375 | ret = ath5k_reset(sc, NULL); | 2361 | ret = ath5k_reset(sc, NULL); |
2376 | if (ret) | 2362 | if (ret) |
2377 | goto done; | 2363 | goto done; |
@@ -2388,8 +2374,8 @@ ath5k_init(struct ath5k_softc *sc) | |||
2388 | /* Set ack to be sent at low bit-rates */ | 2374 | /* Set ack to be sent at low bit-rates */ |
2389 | ath5k_hw_set_ack_bitrate_high(ah, false); | 2375 | ath5k_hw_set_ack_bitrate_high(ah, false); |
2390 | 2376 | ||
2391 | mod_timer(&sc->calib_tim, round_jiffies(jiffies + | 2377 | /* Set PHY calibration inteval */ |
2392 | msecs_to_jiffies(ath5k_calinterval * 1000))); | 2378 | ah->ah_cal_intval = ath5k_calinterval; |
2393 | 2379 | ||
2394 | ret = 0; | 2380 | ret = 0; |
2395 | done: | 2381 | done: |
@@ -2453,37 +2439,39 @@ ath5k_stop_hw(struct ath5k_softc *sc) | |||
2453 | ret = ath5k_stop_locked(sc); | 2439 | ret = ath5k_stop_locked(sc); |
2454 | if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) { | 2440 | if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) { |
2455 | /* | 2441 | /* |
2456 | * Set the chip in full sleep mode. Note that we are | 2442 | * Don't set the card in full sleep mode! |
2457 | * careful to do this only when bringing the interface | 2443 | * |
2458 | * completely to a stop. When the chip is in this state | 2444 | * a) When the device is in this state it must be carefully |
2459 | * it must be carefully woken up or references to | 2445 | * woken up or references to registers in the PCI clock |
2460 | * registers in the PCI clock domain may freeze the bus | 2446 | * domain may freeze the bus (and system). This varies |
2461 | * (and system). This varies by chip and is mostly an | 2447 | * by chip and is mostly an issue with newer parts |
2462 | * issue with newer parts that go to sleep more quickly. | 2448 | * (madwifi sources mentioned srev >= 0x78) that go to |
2463 | */ | 2449 | * sleep more quickly. |
2464 | if (sc->ah->ah_mac_srev >= 0x78) { | 2450 | * |
2465 | /* | 2451 | * b) On older chips full sleep results a weird behaviour |
2466 | * XXX | 2452 | * during wakeup. I tested various cards with srev < 0x78 |
2467 | * don't put newer MAC revisions > 7.8 to sleep because | 2453 | * and they don't wake up after module reload, a second |
2468 | * of the above mentioned problems | 2454 | * module reload is needed to bring the card up again. |
2469 | */ | 2455 | * |
2470 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, " | 2456 | * Until we figure out what's going on don't enable |
2471 | "not putting device to sleep\n"); | 2457 | * full chip reset on any chip (this is what Legacy HAL |
2472 | } else { | 2458 | * and Sam's HAL do anyway). Instead Perform a full reset |
2473 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, | 2459 | * on the device (same as initial state after attach) and |
2474 | "putting device to full sleep\n"); | 2460 | * leave it idle (keep MAC/BB on warm reset) */ |
2475 | ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0); | 2461 | ret = ath5k_hw_on_hold(sc->ah); |
2476 | } | 2462 | |
2463 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, | ||
2464 | "putting device to sleep\n"); | ||
2477 | } | 2465 | } |
2478 | ath5k_txbuf_free(sc, sc->bbuf); | 2466 | ath5k_txbuf_free(sc, sc->bbuf); |
2479 | 2467 | ||
2480 | mmiowb(); | 2468 | mmiowb(); |
2481 | mutex_unlock(&sc->lock); | 2469 | mutex_unlock(&sc->lock); |
2482 | 2470 | ||
2483 | del_timer_sync(&sc->calib_tim); | ||
2484 | tasklet_kill(&sc->rxtq); | 2471 | tasklet_kill(&sc->rxtq); |
2485 | tasklet_kill(&sc->txtq); | 2472 | tasklet_kill(&sc->txtq); |
2486 | tasklet_kill(&sc->restq); | 2473 | tasklet_kill(&sc->restq); |
2474 | tasklet_kill(&sc->calib); | ||
2487 | tasklet_kill(&sc->beacontq); | 2475 | tasklet_kill(&sc->beacontq); |
2488 | 2476 | ||
2489 | ath5k_rfkill_hw_stop(sc->ah); | 2477 | ath5k_rfkill_hw_stop(sc->ah); |
@@ -2539,6 +2527,9 @@ ath5k_intr(int irq, void *dev_id) | |||
2539 | if (status & AR5K_INT_BMISS) { | 2527 | if (status & AR5K_INT_BMISS) { |
2540 | /* TODO */ | 2528 | /* TODO */ |
2541 | } | 2529 | } |
2530 | if (status & AR5K_INT_SWI) { | ||
2531 | tasklet_schedule(&sc->calib); | ||
2532 | } | ||
2542 | if (status & AR5K_INT_MIB) { | 2533 | if (status & AR5K_INT_MIB) { |
2543 | /* | 2534 | /* |
2544 | * These stats are also used for ANI i think | 2535 | * These stats are also used for ANI i think |
@@ -2555,6 +2546,8 @@ ath5k_intr(int irq, void *dev_id) | |||
2555 | if (unlikely(!counter)) | 2546 | if (unlikely(!counter)) |
2556 | ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); | 2547 | ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); |
2557 | 2548 | ||
2549 | ath5k_hw_calibration_poll(ah); | ||
2550 | |||
2558 | return IRQ_HANDLED; | 2551 | return IRQ_HANDLED; |
2559 | } | 2552 | } |
2560 | 2553 | ||
@@ -2571,11 +2564,19 @@ ath5k_tasklet_reset(unsigned long data) | |||
2571 | * for temperature/environment changes. | 2564 | * for temperature/environment changes. |
2572 | */ | 2565 | */ |
2573 | static void | 2566 | static void |
2574 | ath5k_calibrate(unsigned long data) | 2567 | ath5k_tasklet_calibrate(unsigned long data) |
2575 | { | 2568 | { |
2576 | struct ath5k_softc *sc = (void *)data; | 2569 | struct ath5k_softc *sc = (void *)data; |
2577 | struct ath5k_hw *ah = sc->ah; | 2570 | struct ath5k_hw *ah = sc->ah; |
2578 | 2571 | ||
2572 | /* Only full calibration for now */ | ||
2573 | if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION) | ||
2574 | return; | ||
2575 | |||
2576 | /* Stop queues so that calibration | ||
2577 | * doesn't interfere with tx */ | ||
2578 | ieee80211_stop_queues(sc->hw); | ||
2579 | |||
2579 | ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", | 2580 | ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", |
2580 | ieee80211_frequency_to_channel(sc->curchan->center_freq), | 2581 | ieee80211_frequency_to_channel(sc->curchan->center_freq), |
2581 | sc->curchan->hw_value); | 2582 | sc->curchan->hw_value); |
@@ -2593,8 +2594,11 @@ ath5k_calibrate(unsigned long data) | |||
2593 | ieee80211_frequency_to_channel( | 2594 | ieee80211_frequency_to_channel( |
2594 | sc->curchan->center_freq)); | 2595 | sc->curchan->center_freq)); |
2595 | 2596 | ||
2596 | mod_timer(&sc->calib_tim, round_jiffies(jiffies + | 2597 | ah->ah_swi_mask = 0; |
2597 | msecs_to_jiffies(ath5k_calinterval * 1000))); | 2598 | |
2599 | /* Wake queues */ | ||
2600 | ieee80211_wake_queues(sc->hw); | ||
2601 | |||
2598 | } | 2602 | } |
2599 | 2603 | ||
2600 | 2604 | ||
@@ -2811,9 +2815,11 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) | |||
2811 | 2815 | ||
2812 | mutex_lock(&sc->lock); | 2816 | mutex_lock(&sc->lock); |
2813 | 2817 | ||
2814 | ret = ath5k_chan_set(sc, conf->channel); | 2818 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { |
2815 | if (ret < 0) | 2819 | ret = ath5k_chan_set(sc, conf->channel); |
2816 | goto unlock; | 2820 | if (ret < 0) |
2821 | goto unlock; | ||
2822 | } | ||
2817 | 2823 | ||
2818 | if ((changed & IEEE80211_CONF_CHANGE_POWER) && | 2824 | if ((changed & IEEE80211_CONF_CHANGE_POWER) && |
2819 | (sc->power_level != conf->power_level)) { | 2825 | (sc->power_level != conf->power_level)) { |
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 778e422946ab..25a72a85aaa5 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h | |||
@@ -50,6 +50,7 @@ | |||
50 | 50 | ||
51 | #include "ath5k.h" | 51 | #include "ath5k.h" |
52 | #include "debug.h" | 52 | #include "debug.h" |
53 | #include "../ath.h" | ||
53 | 54 | ||
54 | #define ATH_RXBUF 40 /* number of RX buffers */ | 55 | #define ATH_RXBUF 40 /* number of RX buffers */ |
55 | #define ATH_TXBUF 200 /* number of TX buffers */ | 56 | #define ATH_TXBUF 200 /* number of TX buffers */ |
@@ -112,6 +113,7 @@ struct ath5k_rfkill { | |||
112 | * associated with an instance of a device */ | 113 | * associated with an instance of a device */ |
113 | struct ath5k_softc { | 114 | struct ath5k_softc { |
114 | struct pci_dev *pdev; /* for dma mapping */ | 115 | struct pci_dev *pdev; /* for dma mapping */ |
116 | struct ath_common common; | ||
115 | void __iomem *iobase; /* address of the device */ | 117 | void __iomem *iobase; /* address of the device */ |
116 | struct mutex lock; /* dev-level lock */ | 118 | struct mutex lock; /* dev-level lock */ |
117 | struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES]; | 119 | struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES]; |
@@ -134,7 +136,6 @@ struct ath5k_softc { | |||
134 | struct ath5k_desc *desc; /* TX/RX descriptors */ | 136 | struct ath5k_desc *desc; /* TX/RX descriptors */ |
135 | dma_addr_t desc_daddr; /* DMA (physical) address */ | 137 | dma_addr_t desc_daddr; /* DMA (physical) address */ |
136 | size_t desc_len; /* size of TX/RX descriptors */ | 138 | size_t desc_len; /* size of TX/RX descriptors */ |
137 | u16 cachelsz; /* cache line size */ | ||
138 | 139 | ||
139 | DECLARE_BITMAP(status, 5); | 140 | DECLARE_BITMAP(status, 5); |
140 | #define ATH_STAT_INVALID 0 /* disable hardware accesses */ | 141 | #define ATH_STAT_INVALID 0 /* disable hardware accesses */ |
@@ -177,6 +178,8 @@ struct ath5k_softc { | |||
177 | 178 | ||
178 | struct ath5k_rfkill rf_kill; | 179 | struct ath5k_rfkill rf_kill; |
179 | 180 | ||
181 | struct tasklet_struct calib; /* calibration tasklet */ | ||
182 | |||
180 | spinlock_t block; /* protects beacon */ | 183 | spinlock_t block; /* protects beacon */ |
181 | struct tasklet_struct beacontq; /* beacon intr tasklet */ | 184 | struct tasklet_struct beacontq; /* beacon intr tasklet */ |
182 | struct ath5k_buf *bbuf; /* beacon buffer */ | 185 | struct ath5k_buf *bbuf; /* beacon buffer */ |
@@ -187,7 +190,6 @@ struct ath5k_softc { | |||
187 | unsigned int nexttbtt; /* next beacon time in TU */ | 190 | unsigned int nexttbtt; /* next beacon time in TU */ |
188 | struct ath5k_txq *cabq; /* content after beacon */ | 191 | struct ath5k_txq *cabq; /* content after beacon */ |
189 | 192 | ||
190 | struct timer_list calib_tim; /* calibration timer */ | ||
191 | int power_level; /* Requested tx power in dbm */ | 193 | int power_level; /* Requested tx power in dbm */ |
192 | bool assoc; /* assocate state */ | 194 | bool assoc; /* assocate state */ |
193 | bool enable_beacon; /* true if beacons are on */ | 195 | bool enable_beacon; /* true if beacons are on */ |
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index c56b494d417a..8af477dd6fc7 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c | |||
@@ -167,6 +167,16 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) | |||
167 | ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL); | 167 | ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL); |
168 | ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? true : false; | 168 | ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? true : false; |
169 | 169 | ||
170 | /* Check if PCIE_OFFSET points to PCIE_SERDES_SECTION | ||
171 | * and enable serdes programming if needed. | ||
172 | * | ||
173 | * XXX: Serdes values seem to be fixed so | ||
174 | * no need to read them here, we write them | ||
175 | * during ath5k_hw_attach */ | ||
176 | AR5K_EEPROM_READ(AR5K_EEPROM_PCIE_OFFSET, val); | ||
177 | ee->ee_serdes = (val == AR5K_EEPROM_PCIE_SERDES_SECTION) ? | ||
178 | true : false; | ||
179 | |||
170 | return 0; | 180 | return 0; |
171 | } | 181 | } |
172 | 182 | ||
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index 64be73a5edae..0123f3521a0b 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h | |||
@@ -19,6 +19,9 @@ | |||
19 | /* | 19 | /* |
20 | * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE) | 20 | * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE) |
21 | */ | 21 | */ |
22 | #define AR5K_EEPROM_PCIE_OFFSET 0x02 /* Contains offset to PCI-E infos */ | ||
23 | #define AR5K_EEPROM_PCIE_SERDES_SECTION 0x40 /* PCIE_OFFSET points here when | ||
24 | * SERDES infos are present */ | ||
22 | #define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */ | 25 | #define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */ |
23 | #define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */ | 26 | #define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */ |
24 | #define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */ | 27 | #define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */ |
@@ -391,6 +394,7 @@ struct ath5k_eeprom_info { | |||
391 | u8 ee_rfkill_pin; | 394 | u8 ee_rfkill_pin; |
392 | bool ee_rfkill_pol; | 395 | bool ee_rfkill_pol; |
393 | bool ee_is_hb63; | 396 | bool ee_is_hb63; |
397 | bool ee_serdes; | ||
394 | u16 ee_misc0; | 398 | u16 ee_misc0; |
395 | u16 ee_misc1; | 399 | u16 ee_misc1; |
396 | u16 ee_misc2; | 400 | u16 ee_misc2; |
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 2075ba993966..298fcf015227 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c | |||
@@ -740,13 +740,22 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, | |||
740 | AR5K_RF_XPD_GAIN, true); | 740 | AR5K_RF_XPD_GAIN, true); |
741 | 741 | ||
742 | } else { | 742 | } else { |
743 | /* TODO: Set high and low gain bits */ | 743 | u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode]; |
744 | ath5k_hw_rfb_op(ah, rf_regs, | 744 | if (ee->ee_pd_gains[ee_mode] > 1) { |
745 | ee->ee_x_gain[ee_mode], | 745 | ath5k_hw_rfb_op(ah, rf_regs, |
746 | pdg_curve_to_idx[0], | ||
746 | AR5K_RF_PD_GAIN_LO, true); | 747 | AR5K_RF_PD_GAIN_LO, true); |
747 | ath5k_hw_rfb_op(ah, rf_regs, | 748 | ath5k_hw_rfb_op(ah, rf_regs, |
748 | ee->ee_x_gain[ee_mode], | 749 | pdg_curve_to_idx[1], |
749 | AR5K_RF_PD_GAIN_HI, true); | 750 | AR5K_RF_PD_GAIN_HI, true); |
751 | } else { | ||
752 | ath5k_hw_rfb_op(ah, rf_regs, | ||
753 | pdg_curve_to_idx[0], | ||
754 | AR5K_RF_PD_GAIN_LO, true); | ||
755 | ath5k_hw_rfb_op(ah, rf_regs, | ||
756 | pdg_curve_to_idx[0], | ||
757 | AR5K_RF_PD_GAIN_HI, true); | ||
758 | } | ||
750 | 759 | ||
751 | /* Lower synth voltage on Rev 2 */ | 760 | /* Lower synth voltage on Rev 2 */ |
752 | ath5k_hw_rfb_op(ah, rf_regs, 2, | 761 | ath5k_hw_rfb_op(ah, rf_regs, 2, |
@@ -1095,6 +1104,29 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) | |||
1095 | PHY calibration | 1104 | PHY calibration |
1096 | \*****************/ | 1105 | \*****************/ |
1097 | 1106 | ||
1107 | void | ||
1108 | ath5k_hw_calibration_poll(struct ath5k_hw *ah) | ||
1109 | { | ||
1110 | /* Calibration interval in jiffies */ | ||
1111 | unsigned long cal_intval; | ||
1112 | |||
1113 | cal_intval = msecs_to_jiffies(ah->ah_cal_intval * 1000); | ||
1114 | |||
1115 | /* Initialize timestamp if needed */ | ||
1116 | if (!ah->ah_cal_tstamp) | ||
1117 | ah->ah_cal_tstamp = jiffies; | ||
1118 | |||
1119 | /* For now we always do full calibration | ||
1120 | * Mark software interrupt mask and fire software | ||
1121 | * interrupt (bit gets auto-cleared) */ | ||
1122 | if (time_is_before_eq_jiffies(ah->ah_cal_tstamp + cal_intval)) { | ||
1123 | ah->ah_cal_tstamp = jiffies; | ||
1124 | ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION; | ||
1125 | AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); | ||
1126 | } | ||
1127 | |||
1128 | } | ||
1129 | |||
1098 | /** | 1130 | /** |
1099 | * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration | 1131 | * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration |
1100 | * | 1132 | * |
@@ -1896,8 +1928,9 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, | |||
1896 | s16 min_pwrL, min_pwrR; | 1928 | s16 min_pwrL, min_pwrR; |
1897 | s16 pwr_i; | 1929 | s16 pwr_i; |
1898 | 1930 | ||
1899 | if (WARN_ON(stepL[0] == stepL[1] || stepR[0] == stepR[1])) | 1931 | /* Some vendors write the same pcdac value twice !!! */ |
1900 | return 0; | 1932 | if (stepL[0] == stepL[1] || stepR[0] == stepR[1]) |
1933 | return max(pwrL[0], pwrR[0]); | ||
1901 | 1934 | ||
1902 | if (pwrL[0] == pwrL[1]) | 1935 | if (pwrL[0] == pwrL[1]) |
1903 | min_pwrL = pwrL[0]; | 1936 | min_pwrL = pwrL[0]; |
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 6d5aaf00d8bb..eeebb9aef206 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c | |||
@@ -362,7 +362,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) | |||
362 | } | 362 | } |
363 | 363 | ||
364 | if (tq->tqi_ready_time && | 364 | if (tq->tqi_ready_time && |
365 | (tq->tqi_type != AR5K_TX_QUEUE_ID_CAB)) | 365 | (tq->tqi_type != AR5K_TX_QUEUE_CAB)) |
366 | ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, | 366 | ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, |
367 | AR5K_QCU_RDYTIMECFG_INTVAL) | | 367 | AR5K_QCU_RDYTIMECFG_INTVAL) | |
368 | AR5K_QCU_RDYTIMECFG_ENABLE, | 368 | AR5K_QCU_RDYTIMECFG_ENABLE, |
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 86733fdb4774..34e13c700849 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c | |||
@@ -258,29 +258,35 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, | |||
258 | if (!set_chip) | 258 | if (!set_chip) |
259 | goto commit; | 259 | goto commit; |
260 | 260 | ||
261 | /* Preserve sleep duration */ | ||
262 | data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL); | 261 | data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL); |
262 | |||
263 | /* If card is down we 'll get 0xffff... so we | ||
264 | * need to clean this up before we write the register | ||
265 | */ | ||
263 | if (data & 0xffc00000) | 266 | if (data & 0xffc00000) |
264 | data = 0; | 267 | data = 0; |
265 | else | 268 | else |
266 | data = data & 0xfffcffff; | 269 | /* Preserve sleep duration etc */ |
270 | data = data & ~AR5K_SLEEP_CTL_SLE; | ||
267 | 271 | ||
268 | ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); | 272 | ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE, |
273 | AR5K_SLEEP_CTL); | ||
269 | udelay(15); | 274 | udelay(15); |
270 | 275 | ||
271 | for (i = 50; i > 0; i--) { | 276 | for (i = 200; i > 0; i--) { |
272 | /* Check if the chip did wake up */ | 277 | /* Check if the chip did wake up */ |
273 | if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) & | 278 | if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) & |
274 | AR5K_PCICFG_SPWR_DN) == 0) | 279 | AR5K_PCICFG_SPWR_DN) == 0) |
275 | break; | 280 | break; |
276 | 281 | ||
277 | /* Wait a bit and retry */ | 282 | /* Wait a bit and retry */ |
278 | udelay(200); | 283 | udelay(50); |
279 | ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); | 284 | ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE, |
285 | AR5K_SLEEP_CTL); | ||
280 | } | 286 | } |
281 | 287 | ||
282 | /* Fail if the chip didn't wake up */ | 288 | /* Fail if the chip didn't wake up */ |
283 | if (i <= 0) | 289 | if (i == 0) |
284 | return -EIO; | 290 | return -EIO; |
285 | 291 | ||
286 | break; | 292 | break; |
@@ -296,6 +302,64 @@ commit: | |||
296 | } | 302 | } |
297 | 303 | ||
298 | /* | 304 | /* |
305 | * Put device on hold | ||
306 | * | ||
307 | * Put MAC and Baseband on warm reset and | ||
308 | * keep that state (don't clean sleep control | ||
309 | * register). After this MAC and Baseband are | ||
310 | * disabled and a full reset is needed to come | ||
311 | * back. This way we save as much power as possible | ||
312 | * without puting the card on full sleep. | ||
313 | */ | ||
314 | int ath5k_hw_on_hold(struct ath5k_hw *ah) | ||
315 | { | ||
316 | struct pci_dev *pdev = ah->ah_sc->pdev; | ||
317 | u32 bus_flags; | ||
318 | int ret; | ||
319 | |||
320 | /* Make sure device is awake */ | ||
321 | ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); | ||
322 | if (ret) { | ||
323 | ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n"); | ||
324 | return ret; | ||
325 | } | ||
326 | |||
327 | /* | ||
328 | * Put chipset on warm reset... | ||
329 | * | ||
330 | * Note: puting PCI core on warm reset on PCI-E cards | ||
331 | * results card to hang and always return 0xffff... so | ||
332 | * we ingore that flag for PCI-E cards. On PCI cards | ||
333 | * this flag gets cleared after 64 PCI clocks. | ||
334 | */ | ||
335 | bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; | ||
336 | |||
337 | if (ah->ah_version == AR5K_AR5210) { | ||
338 | ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | | ||
339 | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | | ||
340 | AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); | ||
341 | mdelay(2); | ||
342 | } else { | ||
343 | ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | | ||
344 | AR5K_RESET_CTL_BASEBAND | bus_flags); | ||
345 | } | ||
346 | |||
347 | if (ret) { | ||
348 | ATH5K_ERR(ah->ah_sc, "failed to put device on warm reset\n"); | ||
349 | return -EIO; | ||
350 | } | ||
351 | |||
352 | /* ...wakeup again!*/ | ||
353 | ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); | ||
354 | if (ret) { | ||
355 | ATH5K_ERR(ah->ah_sc, "failed to put device on hold\n"); | ||
356 | return ret; | ||
357 | } | ||
358 | |||
359 | return ret; | ||
360 | } | ||
361 | |||
362 | /* | ||
299 | * Bring up MAC + PHY Chips and program PLL | 363 | * Bring up MAC + PHY Chips and program PLL |
300 | * TODO: Half/Quarter rate support | 364 | * TODO: Half/Quarter rate support |
301 | */ | 365 | */ |
@@ -318,6 +382,50 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) | |||
318 | return ret; | 382 | return ret; |
319 | } | 383 | } |
320 | 384 | ||
385 | /* | ||
386 | * Put chipset on warm reset... | ||
387 | * | ||
388 | * Note: puting PCI core on warm reset on PCI-E cards | ||
389 | * results card to hang and always return 0xffff... so | ||
390 | * we ingore that flag for PCI-E cards. On PCI cards | ||
391 | * this flag gets cleared after 64 PCI clocks. | ||
392 | */ | ||
393 | bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; | ||
394 | |||
395 | if (ah->ah_version == AR5K_AR5210) { | ||
396 | ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | | ||
397 | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | | ||
398 | AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); | ||
399 | mdelay(2); | ||
400 | } else { | ||
401 | ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | | ||
402 | AR5K_RESET_CTL_BASEBAND | bus_flags); | ||
403 | } | ||
404 | |||
405 | if (ret) { | ||
406 | ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n"); | ||
407 | return -EIO; | ||
408 | } | ||
409 | |||
410 | /* ...wakeup again!...*/ | ||
411 | ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); | ||
412 | if (ret) { | ||
413 | ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n"); | ||
414 | return ret; | ||
415 | } | ||
416 | |||
417 | /* ...clear reset control register and pull device out of | ||
418 | * warm reset */ | ||
419 | if (ath5k_hw_nic_reset(ah, 0)) { | ||
420 | ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n"); | ||
421 | return -EIO; | ||
422 | } | ||
423 | |||
424 | /* On initialization skip PLL programming since we don't have | ||
425 | * a channel / mode set yet */ | ||
426 | if (initial) | ||
427 | return 0; | ||
428 | |||
321 | if (ah->ah_version != AR5K_AR5210) { | 429 | if (ah->ah_version != AR5K_AR5210) { |
322 | /* | 430 | /* |
323 | * Get channel mode flags | 431 | * Get channel mode flags |
@@ -383,39 +491,6 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) | |||
383 | AR5K_PHY_TURBO); | 491 | AR5K_PHY_TURBO); |
384 | } | 492 | } |
385 | 493 | ||
386 | /* reseting PCI on PCI-E cards results card to hang | ||
387 | * and always return 0xffff... so we ingore that flag | ||
388 | * for PCI-E cards */ | ||
389 | bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; | ||
390 | |||
391 | /* Reset chipset */ | ||
392 | if (ah->ah_version == AR5K_AR5210) { | ||
393 | ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | | ||
394 | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | | ||
395 | AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); | ||
396 | mdelay(2); | ||
397 | } else { | ||
398 | ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | | ||
399 | AR5K_RESET_CTL_BASEBAND | bus_flags); | ||
400 | } | ||
401 | if (ret) { | ||
402 | ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n"); | ||
403 | return -EIO; | ||
404 | } | ||
405 | |||
406 | /* ...wakeup again!*/ | ||
407 | ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); | ||
408 | if (ret) { | ||
409 | ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n"); | ||
410 | return ret; | ||
411 | } | ||
412 | |||
413 | /* ...final warm reset */ | ||
414 | if (ath5k_hw_nic_reset(ah, 0)) { | ||
415 | ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n"); | ||
416 | return -EIO; | ||
417 | } | ||
418 | |||
419 | if (ah->ah_version != AR5K_AR5210) { | 494 | if (ah->ah_version != AR5K_AR5210) { |
420 | 495 | ||
421 | /* ...update PLL if needed */ | 496 | /* ...update PLL if needed */ |
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 2cb72f8c32d7..ef5f59c4dd80 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig | |||
@@ -6,7 +6,13 @@ config ATH9K | |||
6 | select NEW_LEDS | 6 | select NEW_LEDS |
7 | ---help--- | 7 | ---help--- |
8 | This module adds support for wireless adapters based on | 8 | This module adds support for wireless adapters based on |
9 | Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets. | 9 | Atheros IEEE 802.11n AR5008, AR9001 and AR9002 family |
10 | of chipsets. For a specific list of supported external | ||
11 | cards, laptops that already ship with these cards and | ||
12 | APs that come with these cards refer to to ath9k wiki | ||
13 | products page: | ||
14 | |||
15 | http://wireless.kernel.org/en/users/Drivers/ath9k/products | ||
10 | 16 | ||
11 | If you choose to build a module, it'll be called ath9k. | 17 | If you choose to build a module, it'll be called ath9k. |
12 | 18 | ||
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 783bc39eb2ff..28443e05ec10 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile | |||
@@ -1,5 +1,8 @@ | |||
1 | ath9k-y += hw.o \ | 1 | ath9k-y += hw.o \ |
2 | eeprom.o \ | 2 | eeprom.o \ |
3 | eeprom_def.o \ | ||
4 | eeprom_4k.o \ | ||
5 | eeprom_9287.o \ | ||
3 | mac.o \ | 6 | mac.o \ |
4 | calib.o \ | 7 | calib.o \ |
5 | ani.o \ | 8 | ani.o \ |
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index b7093126dbb8..f264097a2f4e 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c | |||
@@ -236,36 +236,35 @@ static void ath9k_ani_restart(struct ath_hw *ah) | |||
236 | return; | 236 | return; |
237 | 237 | ||
238 | aniState = ah->curani; | 238 | aniState = ah->curani; |
239 | |||
240 | aniState->listenTime = 0; | 239 | aniState->listenTime = 0; |
241 | if (ah->has_hw_phycounters) { | 240 | |
242 | if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { | 241 | if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { |
243 | aniState->ofdmPhyErrBase = 0; | 242 | aniState->ofdmPhyErrBase = 0; |
244 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
245 | "OFDM Trigger is too high for hw counters\n"); | ||
246 | } else { | ||
247 | aniState->ofdmPhyErrBase = | ||
248 | AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; | ||
249 | } | ||
250 | if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { | ||
251 | aniState->cckPhyErrBase = 0; | ||
252 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
253 | "CCK Trigger is too high for hw counters\n"); | ||
254 | } else { | ||
255 | aniState->cckPhyErrBase = | ||
256 | AR_PHY_COUNTMAX - aniState->cckTrigHigh; | ||
257 | } | ||
258 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | 243 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, |
259 | "Writing ofdmbase=%u cckbase=%u\n", | 244 | "OFDM Trigger is too high for hw counters\n"); |
260 | aniState->ofdmPhyErrBase, | 245 | } else { |
261 | aniState->cckPhyErrBase); | 246 | aniState->ofdmPhyErrBase = |
262 | REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); | 247 | AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; |
263 | REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); | 248 | } |
264 | REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); | 249 | if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { |
265 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); | 250 | aniState->cckPhyErrBase = 0; |
266 | 251 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | |
267 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); | 252 | "CCK Trigger is too high for hw counters\n"); |
253 | } else { | ||
254 | aniState->cckPhyErrBase = | ||
255 | AR_PHY_COUNTMAX - aniState->cckTrigHigh; | ||
268 | } | 256 | } |
257 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
258 | "Writing ofdmbase=%u cckbase=%u\n", | ||
259 | aniState->ofdmPhyErrBase, | ||
260 | aniState->cckPhyErrBase); | ||
261 | REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); | ||
262 | REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); | ||
263 | REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); | ||
264 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); | ||
265 | |||
266 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); | ||
267 | |||
269 | aniState->ofdmPhyErrCount = 0; | 268 | aniState->ofdmPhyErrCount = 0; |
270 | aniState->cckPhyErrCount = 0; | 269 | aniState->cckPhyErrCount = 0; |
271 | } | 270 | } |
@@ -530,18 +529,12 @@ void ath9k_ani_reset(struct ath_hw *ah) | |||
530 | if (aniState->firstepLevel != 0) | 529 | if (aniState->firstepLevel != 0) |
531 | ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, | 530 | ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, |
532 | aniState->firstepLevel); | 531 | aniState->firstepLevel); |
533 | if (ah->has_hw_phycounters) { | ||
534 | ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & | ||
535 | ~ATH9K_RX_FILTER_PHYERR); | ||
536 | ath9k_ani_restart(ah); | ||
537 | REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); | ||
538 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); | ||
539 | 532 | ||
540 | } else { | 533 | ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & |
541 | ath9k_ani_restart(ah); | 534 | ~ATH9K_RX_FILTER_PHYERR); |
542 | ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | | 535 | ath9k_ani_restart(ah); |
543 | ATH9K_RX_FILTER_PHYERR); | 536 | REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); |
544 | } | 537 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); |
545 | } | 538 | } |
546 | 539 | ||
547 | void ath9k_hw_ani_monitor(struct ath_hw *ah, | 540 | void ath9k_hw_ani_monitor(struct ath_hw *ah, |
@@ -550,6 +543,8 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, | |||
550 | { | 543 | { |
551 | struct ar5416AniState *aniState; | 544 | struct ar5416AniState *aniState; |
552 | int32_t listenTime; | 545 | int32_t listenTime; |
546 | u32 phyCnt1, phyCnt2; | ||
547 | u32 ofdmPhyErrCnt, cckPhyErrCnt; | ||
553 | 548 | ||
554 | if (!DO_ANI(ah)) | 549 | if (!DO_ANI(ah)) |
555 | return; | 550 | return; |
@@ -566,50 +561,45 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, | |||
566 | 561 | ||
567 | aniState->listenTime += listenTime; | 562 | aniState->listenTime += listenTime; |
568 | 563 | ||
569 | if (ah->has_hw_phycounters) { | 564 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); |
570 | u32 phyCnt1, phyCnt2; | ||
571 | u32 ofdmPhyErrCnt, cckPhyErrCnt; | ||
572 | 565 | ||
573 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); | 566 | phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); |
574 | 567 | phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); | |
575 | phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); | 568 | |
576 | phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); | 569 | if (phyCnt1 < aniState->ofdmPhyErrBase || |
577 | 570 | phyCnt2 < aniState->cckPhyErrBase) { | |
578 | if (phyCnt1 < aniState->ofdmPhyErrBase || | 571 | if (phyCnt1 < aniState->ofdmPhyErrBase) { |
579 | phyCnt2 < aniState->cckPhyErrBase) { | 572 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, |
580 | if (phyCnt1 < aniState->ofdmPhyErrBase) { | 573 | "phyCnt1 0x%x, resetting " |
581 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | 574 | "counter value to 0x%x\n", |
582 | "phyCnt1 0x%x, resetting " | 575 | phyCnt1, aniState->ofdmPhyErrBase); |
583 | "counter value to 0x%x\n", | 576 | REG_WRITE(ah, AR_PHY_ERR_1, |
584 | phyCnt1, aniState->ofdmPhyErrBase); | 577 | aniState->ofdmPhyErrBase); |
585 | REG_WRITE(ah, AR_PHY_ERR_1, | 578 | REG_WRITE(ah, AR_PHY_ERR_MASK_1, |
586 | aniState->ofdmPhyErrBase); | 579 | AR_PHY_ERR_OFDM_TIMING); |
587 | REG_WRITE(ah, AR_PHY_ERR_MASK_1, | 580 | } |
588 | AR_PHY_ERR_OFDM_TIMING); | 581 | if (phyCnt2 < aniState->cckPhyErrBase) { |
589 | } | 582 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, |
590 | if (phyCnt2 < aniState->cckPhyErrBase) { | 583 | "phyCnt2 0x%x, resetting " |
591 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | 584 | "counter value to 0x%x\n", |
592 | "phyCnt2 0x%x, resetting " | 585 | phyCnt2, aniState->cckPhyErrBase); |
593 | "counter value to 0x%x\n", | 586 | REG_WRITE(ah, AR_PHY_ERR_2, |
594 | phyCnt2, aniState->cckPhyErrBase); | 587 | aniState->cckPhyErrBase); |
595 | REG_WRITE(ah, AR_PHY_ERR_2, | 588 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, |
596 | aniState->cckPhyErrBase); | 589 | AR_PHY_ERR_CCK_TIMING); |
597 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, | ||
598 | AR_PHY_ERR_CCK_TIMING); | ||
599 | } | ||
600 | return; | ||
601 | } | 590 | } |
591 | return; | ||
592 | } | ||
602 | 593 | ||
603 | ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; | 594 | ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; |
604 | ah->stats.ast_ani_ofdmerrs += | 595 | ah->stats.ast_ani_ofdmerrs += |
605 | ofdmPhyErrCnt - aniState->ofdmPhyErrCount; | 596 | ofdmPhyErrCnt - aniState->ofdmPhyErrCount; |
606 | aniState->ofdmPhyErrCount = ofdmPhyErrCnt; | 597 | aniState->ofdmPhyErrCount = ofdmPhyErrCnt; |
607 | 598 | ||
608 | cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; | 599 | cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; |
609 | ah->stats.ast_ani_cckerrs += | 600 | ah->stats.ast_ani_cckerrs += |
610 | cckPhyErrCnt - aniState->cckPhyErrCount; | 601 | cckPhyErrCnt - aniState->cckPhyErrCount; |
611 | aniState->cckPhyErrCount = cckPhyErrCnt; | 602 | aniState->cckPhyErrCount = cckPhyErrCnt; |
612 | } | ||
613 | 603 | ||
614 | if (aniState->listenTime > 5 * ah->aniperiod) { | 604 | if (aniState->listenTime > 5 * ah->aniperiod) { |
615 | if (aniState->ofdmPhyErrCount <= aniState->listenTime * | 605 | if (aniState->ofdmPhyErrCount <= aniState->listenTime * |
@@ -632,11 +622,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, | |||
632 | } | 622 | } |
633 | } | 623 | } |
634 | 624 | ||
635 | bool ath9k_hw_phycounters(struct ath_hw *ah) | ||
636 | { | ||
637 | return ah->has_hw_phycounters ? true : false; | ||
638 | } | ||
639 | |||
640 | void ath9k_enable_mib_counters(struct ath_hw *ah) | 625 | void ath9k_enable_mib_counters(struct ath_hw *ah) |
641 | { | 626 | { |
642 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n"); | 627 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n"); |
@@ -781,9 +766,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah) | |||
781 | { | 766 | { |
782 | int i; | 767 | int i; |
783 | 768 | ||
784 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n"); | 769 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Initialize ANI\n"); |
785 | |||
786 | ah->has_hw_phycounters = 1; | ||
787 | 770 | ||
788 | memset(ah->ani, 0, sizeof(ah->ani)); | 771 | memset(ah->ani, 0, sizeof(ah->ani)); |
789 | for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { | 772 | for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { |
@@ -799,24 +782,22 @@ void ath9k_hw_ani_init(struct ath_hw *ah) | |||
799 | ATH9K_ANI_CCK_WEAK_SIG_THR; | 782 | ATH9K_ANI_CCK_WEAK_SIG_THR; |
800 | ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; | 783 | ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; |
801 | ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; | 784 | ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; |
802 | if (ah->has_hw_phycounters) { | 785 | ah->ani[i].ofdmPhyErrBase = |
803 | ah->ani[i].ofdmPhyErrBase = | 786 | AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; |
804 | AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; | 787 | ah->ani[i].cckPhyErrBase = |
805 | ah->ani[i].cckPhyErrBase = | 788 | AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; |
806 | AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; | ||
807 | } | ||
808 | } | ||
809 | if (ah->has_hw_phycounters) { | ||
810 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
811 | "Setting OfdmErrBase = 0x%08x\n", | ||
812 | ah->ani[0].ofdmPhyErrBase); | ||
813 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", | ||
814 | ah->ani[0].cckPhyErrBase); | ||
815 | |||
816 | REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); | ||
817 | REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); | ||
818 | ath9k_enable_mib_counters(ah); | ||
819 | } | 789 | } |
790 | |||
791 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
792 | "Setting OfdmErrBase = 0x%08x\n", | ||
793 | ah->ani[0].ofdmPhyErrBase); | ||
794 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", | ||
795 | ah->ani[0].cckPhyErrBase); | ||
796 | |||
797 | REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); | ||
798 | REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); | ||
799 | ath9k_enable_mib_counters(ah); | ||
800 | |||
820 | ah->aniperiod = ATH9K_ANI_PERIOD; | 801 | ah->aniperiod = ATH9K_ANI_PERIOD; |
821 | if (ah->config.enable_ani) | 802 | if (ah->config.enable_ani) |
822 | ah->proc_phyerr |= HAL_PROCESS_ANI; | 803 | ah->proc_phyerr |= HAL_PROCESS_ANI; |
@@ -826,9 +807,7 @@ void ath9k_hw_ani_disable(struct ath_hw *ah) | |||
826 | { | 807 | { |
827 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling ANI\n"); | 808 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling ANI\n"); |
828 | 809 | ||
829 | if (ah->has_hw_phycounters) { | 810 | ath9k_hw_disable_mib_counters(ah); |
830 | ath9k_hw_disable_mib_counters(ah); | 811 | REG_WRITE(ah, AR_PHY_ERR_1, 0); |
831 | REG_WRITE(ah, AR_PHY_ERR_1, 0); | 812 | REG_WRITE(ah, AR_PHY_ERR_2, 0); |
832 | REG_WRITE(ah, AR_PHY_ERR_2, 0); | ||
833 | } | ||
834 | } | 813 | } |
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index a36b7bb7c42a..119924511f85 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h | |||
@@ -124,7 +124,6 @@ void ath9k_ani_reset(struct ath_hw *ah); | |||
124 | void ath9k_hw_ani_monitor(struct ath_hw *ah, | 124 | void ath9k_hw_ani_monitor(struct ath_hw *ah, |
125 | const struct ath9k_node_stats *stats, | 125 | const struct ath9k_node_stats *stats, |
126 | struct ath9k_channel *chan); | 126 | struct ath9k_channel *chan); |
127 | bool ath9k_hw_phycounters(struct ath_hw *ah); | ||
128 | void ath9k_enable_mib_counters(struct ath_hw *ah); | 127 | void ath9k_enable_mib_counters(struct ath_hw *ah); |
129 | void ath9k_hw_disable_mib_counters(struct ath_hw *ah); | 128 | void ath9k_hw_disable_mib_counters(struct ath_hw *ah); |
130 | u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, | 129 | u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7a5a157e15c4..2fd663c01b8e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "hw.h" | 25 | #include "hw.h" |
26 | #include "rc.h" | 26 | #include "rc.h" |
27 | #include "debug.h" | 27 | #include "debug.h" |
28 | #include "../ath.h" | ||
28 | 29 | ||
29 | struct ath_node; | 30 | struct ath_node; |
30 | 31 | ||
@@ -532,6 +533,8 @@ struct ath_softc { | |||
532 | struct ieee80211_hw *hw; | 533 | struct ieee80211_hw *hw; |
533 | struct device *dev; | 534 | struct device *dev; |
534 | 535 | ||
536 | struct ath_common common; | ||
537 | |||
535 | spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */ | 538 | spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */ |
536 | struct ath_wiphy *pri_wiphy; | 539 | struct ath_wiphy *pri_wiphy; |
537 | struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may | 540 | struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may |
@@ -564,7 +567,6 @@ struct ath_softc { | |||
564 | u32 sc_flags; /* SC_OP_* */ | 567 | u32 sc_flags; /* SC_OP_* */ |
565 | u16 curtxpow; | 568 | u16 curtxpow; |
566 | u16 curaid; | 569 | u16 curaid; |
567 | u16 cachelsz; | ||
568 | u8 nbcnvifs; | 570 | u8 nbcnvifs; |
569 | u16 nvifs; | 571 | u16 nvifs; |
570 | u8 tx_chainmask; | 572 | u8 tx_chainmask; |
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 4cb64a0900bb..958948bc73fd 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c | |||
@@ -16,9 +16,16 @@ | |||
16 | 16 | ||
17 | #include "ath9k.h" | 17 | #include "ath9k.h" |
18 | 18 | ||
19 | static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, | 19 | static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) |
20 | u32 reg, u32 mask, | 20 | { |
21 | u32 shift, u32 val) | 21 | if (fbin == AR5416_BCHAN_UNUSED) |
22 | return fbin; | ||
23 | |||
24 | return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); | ||
25 | } | ||
26 | |||
27 | void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, | ||
28 | u32 shift, u32 val) | ||
22 | { | 29 | { |
23 | u32 regVal; | 30 | u32 regVal; |
24 | 31 | ||
@@ -33,19 +40,8 @@ static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, | |||
33 | return; | 40 | return; |
34 | } | 41 | } |
35 | 42 | ||
36 | static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) | 43 | int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, |
37 | { | 44 | int16_t targetLeft, int16_t targetRight) |
38 | |||
39 | if (fbin == AR5416_BCHAN_UNUSED) | ||
40 | return fbin; | ||
41 | |||
42 | return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); | ||
43 | } | ||
44 | |||
45 | static inline int16_t ath9k_hw_interpolate(u16 target, | ||
46 | u16 srcLeft, u16 srcRight, | ||
47 | int16_t targetLeft, | ||
48 | int16_t targetRight) | ||
49 | { | 45 | { |
50 | int16_t rv; | 46 | int16_t rv; |
51 | 47 | ||
@@ -59,9 +55,8 @@ static inline int16_t ath9k_hw_interpolate(u16 target, | |||
59 | return rv; | 55 | return rv; |
60 | } | 56 | } |
61 | 57 | ||
62 | static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, | 58 | bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, |
63 | u16 listSize, u16 *indexL, | 59 | u16 *indexL, u16 *indexR) |
64 | u16 *indexR) | ||
65 | { | 60 | { |
66 | u16 i; | 61 | u16 i; |
67 | 62 | ||
@@ -88,16 +83,16 @@ static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, | |||
88 | return false; | 83 | return false; |
89 | } | 84 | } |
90 | 85 | ||
91 | static inline bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) | 86 | bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) |
92 | { | 87 | { |
93 | struct ath_softc *sc = ah->ah_sc; | 88 | struct ath_softc *sc = ah->ah_sc; |
94 | 89 | ||
95 | return sc->bus_ops->eeprom_read(ah, off, data); | 90 | return sc->bus_ops->eeprom_read(ah, off, data); |
96 | } | 91 | } |
97 | 92 | ||
98 | static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, | 93 | void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, |
99 | u8 *pVpdList, u16 numIntercepts, | 94 | u8 *pVpdList, u16 numIntercepts, |
100 | u8 *pRetVpdList) | 95 | u8 *pRetVpdList) |
101 | { | 96 | { |
102 | u16 i, k; | 97 | u16 i, k; |
103 | u8 currPwr = pwrMin; | 98 | u8 currPwr = pwrMin; |
@@ -120,16 +115,14 @@ static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, | |||
120 | pRetVpdList[i] = (u8) k; | 115 | pRetVpdList[i] = (u8) k; |
121 | currPwr += 2; | 116 | currPwr += 2; |
122 | } | 117 | } |
123 | |||
124 | return true; | ||
125 | } | 118 | } |
126 | 119 | ||
127 | static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, | 120 | void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, |
128 | struct ath9k_channel *chan, | 121 | struct ath9k_channel *chan, |
129 | struct cal_target_power_leg *powInfo, | 122 | struct cal_target_power_leg *powInfo, |
130 | u16 numChannels, | 123 | u16 numChannels, |
131 | struct cal_target_power_leg *pNewPower, | 124 | struct cal_target_power_leg *pNewPower, |
132 | u16 numRates, bool isExtTarget) | 125 | u16 numRates, bool isExtTarget) |
133 | { | 126 | { |
134 | struct chan_centers centers; | 127 | struct chan_centers centers; |
135 | u16 clo, chi; | 128 | u16 clo, chi; |
@@ -179,75 +172,12 @@ static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, | |||
179 | } | 172 | } |
180 | } | 173 | } |
181 | 174 | ||
182 | static void ath9k_get_txgain_index(struct ath_hw *ah, | 175 | void ath9k_hw_get_target_powers(struct ath_hw *ah, |
183 | struct ath9k_channel *chan, | 176 | struct ath9k_channel *chan, |
184 | struct calDataPerFreqOpLoop *rawDatasetOpLoop, | 177 | struct cal_target_power_ht *powInfo, |
185 | u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx) | 178 | u16 numChannels, |
186 | { | 179 | struct cal_target_power_ht *pNewPower, |
187 | u8 pcdac, i = 0; | 180 | u16 numRates, bool isHt40Target) |
188 | u16 idxL = 0, idxR = 0, numPiers; | ||
189 | bool match; | ||
190 | struct chan_centers centers; | ||
191 | |||
192 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
193 | |||
194 | for (numPiers = 0; numPiers < availPiers; numPiers++) | ||
195 | if (calChans[numPiers] == AR5416_BCHAN_UNUSED) | ||
196 | break; | ||
197 | |||
198 | match = ath9k_hw_get_lower_upper_index( | ||
199 | (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), | ||
200 | calChans, numPiers, &idxL, &idxR); | ||
201 | if (match) { | ||
202 | pcdac = rawDatasetOpLoop[idxL].pcdac[0][0]; | ||
203 | *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0]; | ||
204 | } else { | ||
205 | pcdac = rawDatasetOpLoop[idxR].pcdac[0][0]; | ||
206 | *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] + | ||
207 | rawDatasetOpLoop[idxR].pwrPdg[0][0])/2; | ||
208 | } | ||
209 | |||
210 | while (pcdac > ah->originalGain[i] && | ||
211 | i < (AR9280_TX_GAIN_TABLE_SIZE - 1)) | ||
212 | i++; | ||
213 | |||
214 | *pcdacIdx = i; | ||
215 | return; | ||
216 | } | ||
217 | |||
218 | static void ath9k_olc_get_pdadcs(struct ath_hw *ah, | ||
219 | u32 initTxGain, | ||
220 | int txPower, | ||
221 | u8 *pPDADCValues) | ||
222 | { | ||
223 | u32 i; | ||
224 | u32 offset; | ||
225 | |||
226 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, | ||
227 | AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); | ||
228 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, | ||
229 | AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); | ||
230 | |||
231 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, | ||
232 | AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain); | ||
233 | |||
234 | offset = txPower; | ||
235 | for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++) | ||
236 | if (i < offset) | ||
237 | pPDADCValues[i] = 0x0; | ||
238 | else | ||
239 | pPDADCValues[i] = 0xFF; | ||
240 | } | ||
241 | |||
242 | |||
243 | |||
244 | |||
245 | static void ath9k_hw_get_target_powers(struct ath_hw *ah, | ||
246 | struct ath9k_channel *chan, | ||
247 | struct cal_target_power_ht *powInfo, | ||
248 | u16 numChannels, | ||
249 | struct cal_target_power_ht *pNewPower, | ||
250 | u16 numRates, bool isHt40Target) | ||
251 | { | 181 | { |
252 | struct chan_centers centers; | 182 | struct chan_centers centers; |
253 | u16 clo, chi; | 183 | u16 clo, chi; |
@@ -297,9 +227,8 @@ static void ath9k_hw_get_target_powers(struct ath_hw *ah, | |||
297 | } | 227 | } |
298 | } | 228 | } |
299 | 229 | ||
300 | static u16 ath9k_hw_get_max_edge_power(u16 freq, | 230 | u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, |
301 | struct cal_ctl_edges *pRdEdgesPower, | 231 | bool is2GHz, int num_band_edges) |
302 | bool is2GHz, int num_band_edges) | ||
303 | { | 232 | { |
304 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | 233 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; |
305 | int i; | 234 | int i; |
@@ -325,3743 +254,10 @@ static u16 ath9k_hw_get_max_edge_power(u16 freq, | |||
325 | return twiceMaxEdgePower; | 254 | return twiceMaxEdgePower; |
326 | } | 255 | } |
327 | 256 | ||
328 | /****************************************/ | ||
329 | /* EEPROM Operations for 4K sized cards */ | ||
330 | /****************************************/ | ||
331 | |||
332 | static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) | ||
333 | { | ||
334 | return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF); | ||
335 | } | ||
336 | |||
337 | static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) | ||
338 | { | ||
339 | return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); | ||
340 | } | ||
341 | |||
342 | static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) | ||
343 | { | ||
344 | #define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) | ||
345 | u16 *eep_data = (u16 *)&ah->eeprom.map4k; | ||
346 | int addr, eep_start_loc = 0; | ||
347 | |||
348 | eep_start_loc = 64; | ||
349 | |||
350 | if (!ath9k_hw_use_flash(ah)) { | ||
351 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
352 | "Reading from EEPROM, not flash\n"); | ||
353 | } | ||
354 | |||
355 | for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { | ||
356 | if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { | ||
357 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
358 | "Unable to read eeprom region \n"); | ||
359 | return false; | ||
360 | } | ||
361 | eep_data++; | ||
362 | } | ||
363 | |||
364 | return true; | ||
365 | #undef SIZE_EEPROM_4K | ||
366 | } | ||
367 | |||
368 | static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) | ||
369 | { | ||
370 | #define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) | ||
371 | struct ar5416_eeprom_4k *eep = | ||
372 | (struct ar5416_eeprom_4k *) &ah->eeprom.map4k; | ||
373 | u16 *eepdata, temp, magic, magic2; | ||
374 | u32 sum = 0, el; | ||
375 | bool need_swap = false; | ||
376 | int i, addr; | ||
377 | |||
378 | |||
379 | if (!ath9k_hw_use_flash(ah)) { | ||
380 | if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, | ||
381 | &magic)) { | ||
382 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
383 | "Reading Magic # failed\n"); | ||
384 | return false; | ||
385 | } | ||
386 | |||
387 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
388 | "Read Magic = 0x%04X\n", magic); | ||
389 | |||
390 | if (magic != AR5416_EEPROM_MAGIC) { | ||
391 | magic2 = swab16(magic); | ||
392 | |||
393 | if (magic2 == AR5416_EEPROM_MAGIC) { | ||
394 | need_swap = true; | ||
395 | eepdata = (u16 *) (&ah->eeprom); | ||
396 | |||
397 | for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { | ||
398 | temp = swab16(*eepdata); | ||
399 | *eepdata = temp; | ||
400 | eepdata++; | ||
401 | } | ||
402 | } else { | ||
403 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
404 | "Invalid EEPROM Magic. " | ||
405 | "endianness mismatch.\n"); | ||
406 | return -EINVAL; | ||
407 | } | ||
408 | } | ||
409 | } | ||
410 | |||
411 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", | ||
412 | need_swap ? "True" : "False"); | ||
413 | |||
414 | if (need_swap) | ||
415 | el = swab16(ah->eeprom.map4k.baseEepHeader.length); | ||
416 | else | ||
417 | el = ah->eeprom.map4k.baseEepHeader.length; | ||
418 | |||
419 | if (el > sizeof(struct ar5416_eeprom_4k)) | ||
420 | el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); | ||
421 | else | ||
422 | el = el / sizeof(u16); | ||
423 | |||
424 | eepdata = (u16 *)(&ah->eeprom); | ||
425 | |||
426 | for (i = 0; i < el; i++) | ||
427 | sum ^= *eepdata++; | ||
428 | |||
429 | if (need_swap) { | ||
430 | u32 integer; | ||
431 | u16 word; | ||
432 | |||
433 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
434 | "EEPROM Endianness is not native.. Changing\n"); | ||
435 | |||
436 | word = swab16(eep->baseEepHeader.length); | ||
437 | eep->baseEepHeader.length = word; | ||
438 | |||
439 | word = swab16(eep->baseEepHeader.checksum); | ||
440 | eep->baseEepHeader.checksum = word; | ||
441 | |||
442 | word = swab16(eep->baseEepHeader.version); | ||
443 | eep->baseEepHeader.version = word; | ||
444 | |||
445 | word = swab16(eep->baseEepHeader.regDmn[0]); | ||
446 | eep->baseEepHeader.regDmn[0] = word; | ||
447 | |||
448 | word = swab16(eep->baseEepHeader.regDmn[1]); | ||
449 | eep->baseEepHeader.regDmn[1] = word; | ||
450 | |||
451 | word = swab16(eep->baseEepHeader.rfSilent); | ||
452 | eep->baseEepHeader.rfSilent = word; | ||
453 | |||
454 | word = swab16(eep->baseEepHeader.blueToothOptions); | ||
455 | eep->baseEepHeader.blueToothOptions = word; | ||
456 | |||
457 | word = swab16(eep->baseEepHeader.deviceCap); | ||
458 | eep->baseEepHeader.deviceCap = word; | ||
459 | |||
460 | integer = swab32(eep->modalHeader.antCtrlCommon); | ||
461 | eep->modalHeader.antCtrlCommon = integer; | ||
462 | |||
463 | for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { | ||
464 | integer = swab32(eep->modalHeader.antCtrlChain[i]); | ||
465 | eep->modalHeader.antCtrlChain[i] = integer; | ||
466 | } | ||
467 | |||
468 | for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { | ||
469 | word = swab16(eep->modalHeader.spurChans[i].spurChan); | ||
470 | eep->modalHeader.spurChans[i].spurChan = word; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || | ||
475 | ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { | ||
476 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
477 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", | ||
478 | sum, ah->eep_ops->get_eeprom_ver(ah)); | ||
479 | return -EINVAL; | ||
480 | } | ||
481 | |||
482 | return 0; | ||
483 | #undef EEPROM_4K_SIZE | ||
484 | } | ||
485 | |||
486 | static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, | ||
487 | enum eeprom_param param) | ||
488 | { | ||
489 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
490 | struct modal_eep_4k_header *pModal = &eep->modalHeader; | ||
491 | struct base_eep_header_4k *pBase = &eep->baseEepHeader; | ||
492 | |||
493 | switch (param) { | ||
494 | case EEP_NFTHRESH_2: | ||
495 | return pModal->noiseFloorThreshCh[0]; | ||
496 | case AR_EEPROM_MAC(0): | ||
497 | return pBase->macAddr[0] << 8 | pBase->macAddr[1]; | ||
498 | case AR_EEPROM_MAC(1): | ||
499 | return pBase->macAddr[2] << 8 | pBase->macAddr[3]; | ||
500 | case AR_EEPROM_MAC(2): | ||
501 | return pBase->macAddr[4] << 8 | pBase->macAddr[5]; | ||
502 | case EEP_REG_0: | ||
503 | return pBase->regDmn[0]; | ||
504 | case EEP_REG_1: | ||
505 | return pBase->regDmn[1]; | ||
506 | case EEP_OP_CAP: | ||
507 | return pBase->deviceCap; | ||
508 | case EEP_OP_MODE: | ||
509 | return pBase->opCapFlags; | ||
510 | case EEP_RF_SILENT: | ||
511 | return pBase->rfSilent; | ||
512 | case EEP_OB_2: | ||
513 | return pModal->ob_01; | ||
514 | case EEP_DB_2: | ||
515 | return pModal->db1_01; | ||
516 | case EEP_MINOR_REV: | ||
517 | return pBase->version & AR5416_EEP_VER_MINOR_MASK; | ||
518 | case EEP_TX_MASK: | ||
519 | return pBase->txMask; | ||
520 | case EEP_RX_MASK: | ||
521 | return pBase->rxMask; | ||
522 | case EEP_FRAC_N_5G: | ||
523 | return 0; | ||
524 | default: | ||
525 | return 0; | ||
526 | } | ||
527 | } | ||
528 | |||
529 | static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, | ||
530 | struct ath9k_channel *chan, | ||
531 | struct cal_data_per_freq_4k *pRawDataSet, | ||
532 | u8 *bChans, u16 availPiers, | ||
533 | u16 tPdGainOverlap, int16_t *pMinCalPower, | ||
534 | u16 *pPdGainBoundaries, u8 *pPDADCValues, | ||
535 | u16 numXpdGains) | ||
536 | { | ||
537 | #define TMP_VAL_VPD_TABLE \ | ||
538 | ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); | ||
539 | int i, j, k; | ||
540 | int16_t ss; | ||
541 | u16 idxL = 0, idxR = 0, numPiers; | ||
542 | static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] | ||
543 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
544 | static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] | ||
545 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
546 | static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] | ||
547 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
548 | |||
549 | u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; | ||
550 | u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; | ||
551 | u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; | ||
552 | int16_t vpdStep; | ||
553 | int16_t tmpVal; | ||
554 | u16 sizeCurrVpdTable, maxIndex, tgtIndex; | ||
555 | bool match; | ||
556 | int16_t minDelta = 0; | ||
557 | struct chan_centers centers; | ||
558 | #define PD_GAIN_BOUNDARY_DEFAULT 58; | ||
559 | |||
560 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
561 | |||
562 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
563 | if (bChans[numPiers] == AR5416_BCHAN_UNUSED) | ||
564 | break; | ||
565 | } | ||
566 | |||
567 | match = ath9k_hw_get_lower_upper_index( | ||
568 | (u8)FREQ2FBIN(centers.synth_center, | ||
569 | IS_CHAN_2GHZ(chan)), bChans, numPiers, | ||
570 | &idxL, &idxR); | ||
571 | |||
572 | if (match) { | ||
573 | for (i = 0; i < numXpdGains; i++) { | ||
574 | minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; | ||
575 | maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; | ||
576 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
577 | pRawDataSet[idxL].pwrPdg[i], | ||
578 | pRawDataSet[idxL].vpdPdg[i], | ||
579 | AR5416_EEP4K_PD_GAIN_ICEPTS, | ||
580 | vpdTableI[i]); | ||
581 | } | ||
582 | } else { | ||
583 | for (i = 0; i < numXpdGains; i++) { | ||
584 | pVpdL = pRawDataSet[idxL].vpdPdg[i]; | ||
585 | pPwrL = pRawDataSet[idxL].pwrPdg[i]; | ||
586 | pVpdR = pRawDataSet[idxR].vpdPdg[i]; | ||
587 | pPwrR = pRawDataSet[idxR].pwrPdg[i]; | ||
588 | |||
589 | minPwrT4[i] = max(pPwrL[0], pPwrR[0]); | ||
590 | |||
591 | maxPwrT4[i] = | ||
592 | min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1], | ||
593 | pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); | ||
594 | |||
595 | |||
596 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
597 | pPwrL, pVpdL, | ||
598 | AR5416_EEP4K_PD_GAIN_ICEPTS, | ||
599 | vpdTableL[i]); | ||
600 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
601 | pPwrR, pVpdR, | ||
602 | AR5416_EEP4K_PD_GAIN_ICEPTS, | ||
603 | vpdTableR[i]); | ||
604 | |||
605 | for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { | ||
606 | vpdTableI[i][j] = | ||
607 | (u8)(ath9k_hw_interpolate((u16) | ||
608 | FREQ2FBIN(centers. | ||
609 | synth_center, | ||
610 | IS_CHAN_2GHZ | ||
611 | (chan)), | ||
612 | bChans[idxL], bChans[idxR], | ||
613 | vpdTableL[i][j], vpdTableR[i][j])); | ||
614 | } | ||
615 | } | ||
616 | } | ||
617 | |||
618 | *pMinCalPower = (int16_t)(minPwrT4[0] / 2); | ||
619 | |||
620 | k = 0; | ||
621 | |||
622 | for (i = 0; i < numXpdGains; i++) { | ||
623 | if (i == (numXpdGains - 1)) | ||
624 | pPdGainBoundaries[i] = | ||
625 | (u16)(maxPwrT4[i] / 2); | ||
626 | else | ||
627 | pPdGainBoundaries[i] = | ||
628 | (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); | ||
629 | |||
630 | pPdGainBoundaries[i] = | ||
631 | min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); | ||
632 | |||
633 | if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { | ||
634 | minDelta = pPdGainBoundaries[0] - 23; | ||
635 | pPdGainBoundaries[0] = 23; | ||
636 | } else { | ||
637 | minDelta = 0; | ||
638 | } | ||
639 | |||
640 | if (i == 0) { | ||
641 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
642 | ss = (int16_t)(0 - (minPwrT4[i] / 2)); | ||
643 | else | ||
644 | ss = 0; | ||
645 | } else { | ||
646 | ss = (int16_t)((pPdGainBoundaries[i - 1] - | ||
647 | (minPwrT4[i] / 2)) - | ||
648 | tPdGainOverlap + 1 + minDelta); | ||
649 | } | ||
650 | vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); | ||
651 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
652 | |||
653 | while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
654 | tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); | ||
655 | pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); | ||
656 | ss++; | ||
657 | } | ||
658 | |||
659 | sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); | ||
660 | tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - | ||
661 | (minPwrT4[i] / 2)); | ||
662 | maxIndex = (tgtIndex < sizeCurrVpdTable) ? | ||
663 | tgtIndex : sizeCurrVpdTable; | ||
664 | |||
665 | while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) | ||
666 | pPDADCValues[k++] = vpdTableI[i][ss++]; | ||
667 | |||
668 | vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - | ||
669 | vpdTableI[i][sizeCurrVpdTable - 2]); | ||
670 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
671 | |||
672 | if (tgtIndex >= maxIndex) { | ||
673 | while ((ss <= tgtIndex) && | ||
674 | (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
675 | tmpVal = (int16_t) TMP_VAL_VPD_TABLE; | ||
676 | pPDADCValues[k++] = (u8)((tmpVal > 255) ? | ||
677 | 255 : tmpVal); | ||
678 | ss++; | ||
679 | } | ||
680 | } | ||
681 | } | ||
682 | |||
683 | while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { | ||
684 | pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; | ||
685 | i++; | ||
686 | } | ||
687 | |||
688 | while (k < AR5416_NUM_PDADC_VALUES) { | ||
689 | pPDADCValues[k] = pPDADCValues[k - 1]; | ||
690 | k++; | ||
691 | } | ||
692 | |||
693 | return; | ||
694 | #undef TMP_VAL_VPD_TABLE | ||
695 | } | ||
696 | |||
697 | static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, | ||
698 | struct ath9k_channel *chan, | ||
699 | int16_t *pTxPowerIndexOffset) | ||
700 | { | ||
701 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | ||
702 | struct cal_data_per_freq_4k *pRawDataset; | ||
703 | u8 *pCalBChans = NULL; | ||
704 | u16 pdGainOverlap_t2; | ||
705 | static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; | ||
706 | u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK]; | ||
707 | u16 numPiers, i, j; | ||
708 | int16_t tMinCalPower; | ||
709 | u16 numXpdGain, xpdMask; | ||
710 | u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 }; | ||
711 | u32 reg32, regOffset, regChainOffset; | ||
712 | |||
713 | xpdMask = pEepData->modalHeader.xpdGain; | ||
714 | |||
715 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
716 | AR5416_EEP_MINOR_VER_2) { | ||
717 | pdGainOverlap_t2 = | ||
718 | pEepData->modalHeader.pdGainOverlap; | ||
719 | } else { | ||
720 | pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), | ||
721 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); | ||
722 | } | ||
723 | |||
724 | pCalBChans = pEepData->calFreqPier2G; | ||
725 | numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS; | ||
726 | |||
727 | numXpdGain = 0; | ||
728 | |||
729 | for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) { | ||
730 | if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) { | ||
731 | if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS) | ||
732 | break; | ||
733 | xpdGainValues[numXpdGain] = | ||
734 | (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i); | ||
735 | numXpdGain++; | ||
736 | } | ||
737 | } | ||
738 | |||
739 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, | ||
740 | (numXpdGain - 1) & 0x3); | ||
741 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, | ||
742 | xpdGainValues[0]); | ||
743 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, | ||
744 | xpdGainValues[1]); | ||
745 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0); | ||
746 | |||
747 | for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { | ||
748 | if (AR_SREV_5416_20_OR_LATER(ah) && | ||
749 | (ah->rxchainmask == 5 || ah->txchainmask == 5) && | ||
750 | (i != 0)) { | ||
751 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; | ||
752 | } else | ||
753 | regChainOffset = i * 0x1000; | ||
754 | |||
755 | if (pEepData->baseEepHeader.txMask & (1 << i)) { | ||
756 | pRawDataset = pEepData->calPierData2G[i]; | ||
757 | |||
758 | ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan, | ||
759 | pRawDataset, pCalBChans, | ||
760 | numPiers, pdGainOverlap_t2, | ||
761 | &tMinCalPower, gainBoundaries, | ||
762 | pdadcValues, numXpdGain); | ||
763 | |||
764 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { | ||
765 | REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, | ||
766 | SM(pdGainOverlap_t2, | ||
767 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | ||
768 | | SM(gainBoundaries[0], | ||
769 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | ||
770 | | SM(gainBoundaries[1], | ||
771 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | ||
772 | | SM(gainBoundaries[2], | ||
773 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | ||
774 | | SM(gainBoundaries[3], | ||
775 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); | ||
776 | } | ||
777 | |||
778 | regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; | ||
779 | for (j = 0; j < 32; j++) { | ||
780 | reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | | ||
781 | ((pdadcValues[4 * j + 1] & 0xFF) << 8) | | ||
782 | ((pdadcValues[4 * j + 2] & 0xFF) << 16)| | ||
783 | ((pdadcValues[4 * j + 3] & 0xFF) << 24); | ||
784 | REG_WRITE(ah, regOffset, reg32); | ||
785 | |||
786 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
787 | "PDADC (%d,%4x): %4.4x %8.8x\n", | ||
788 | i, regChainOffset, regOffset, | ||
789 | reg32); | ||
790 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
791 | "PDADC: Chain %d | " | ||
792 | "PDADC %3d Value %3d | " | ||
793 | "PDADC %3d Value %3d | " | ||
794 | "PDADC %3d Value %3d | " | ||
795 | "PDADC %3d Value %3d |\n", | ||
796 | i, 4 * j, pdadcValues[4 * j], | ||
797 | 4 * j + 1, pdadcValues[4 * j + 1], | ||
798 | 4 * j + 2, pdadcValues[4 * j + 2], | ||
799 | 4 * j + 3, | ||
800 | pdadcValues[4 * j + 3]); | ||
801 | |||
802 | regOffset += 4; | ||
803 | } | ||
804 | } | ||
805 | } | ||
806 | |||
807 | *pTxPowerIndexOffset = 0; | ||
808 | } | ||
809 | |||
810 | static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, | ||
811 | struct ath9k_channel *chan, | ||
812 | int16_t *ratesArray, | ||
813 | u16 cfgCtl, | ||
814 | u16 AntennaReduction, | ||
815 | u16 twiceMaxRegulatoryPower, | ||
816 | u16 powerLimit) | ||
817 | { | ||
818 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | ||
819 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
820 | static const u16 tpScaleReductionTable[5] = | ||
821 | { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; | ||
822 | |||
823 | int i; | ||
824 | int16_t twiceLargestAntenna; | ||
825 | struct cal_ctl_data_4k *rep; | ||
826 | struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { | ||
827 | 0, { 0, 0, 0, 0} | ||
828 | }; | ||
829 | struct cal_target_power_leg targetPowerOfdmExt = { | ||
830 | 0, { 0, 0, 0, 0} }, targetPowerCckExt = { | ||
831 | 0, { 0, 0, 0, 0 } | ||
832 | }; | ||
833 | struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { | ||
834 | 0, {0, 0, 0, 0} | ||
835 | }; | ||
836 | u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; | ||
837 | u16 ctlModesFor11g[] = | ||
838 | { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, | ||
839 | CTL_2GHT40 | ||
840 | }; | ||
841 | u16 numCtlModes, *pCtlMode, ctlMode, freq; | ||
842 | struct chan_centers centers; | ||
843 | int tx_chainmask; | ||
844 | u16 twiceMinEdgePower; | ||
845 | |||
846 | tx_chainmask = ah->txchainmask; | ||
847 | |||
848 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
849 | |||
850 | twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; | ||
851 | |||
852 | twiceLargestAntenna = (int16_t)min(AntennaReduction - | ||
853 | twiceLargestAntenna, 0); | ||
854 | |||
855 | maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; | ||
856 | |||
857 | if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { | ||
858 | maxRegAllowedPower -= | ||
859 | (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); | ||
860 | } | ||
861 | |||
862 | scaledPower = min(powerLimit, maxRegAllowedPower); | ||
863 | scaledPower = max((u16)0, scaledPower); | ||
864 | |||
865 | numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; | ||
866 | pCtlMode = ctlModesFor11g; | ||
867 | |||
868 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
869 | pEepData->calTargetPowerCck, | ||
870 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
871 | &targetPowerCck, 4, false); | ||
872 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
873 | pEepData->calTargetPower2G, | ||
874 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
875 | &targetPowerOfdm, 4, false); | ||
876 | ath9k_hw_get_target_powers(ah, chan, | ||
877 | pEepData->calTargetPower2GHT20, | ||
878 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
879 | &targetPowerHt20, 8, false); | ||
880 | |||
881 | if (IS_CHAN_HT40(chan)) { | ||
882 | numCtlModes = ARRAY_SIZE(ctlModesFor11g); | ||
883 | ath9k_hw_get_target_powers(ah, chan, | ||
884 | pEepData->calTargetPower2GHT40, | ||
885 | AR5416_NUM_2G_40_TARGET_POWERS, | ||
886 | &targetPowerHt40, 8, true); | ||
887 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
888 | pEepData->calTargetPowerCck, | ||
889 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
890 | &targetPowerCckExt, 4, true); | ||
891 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
892 | pEepData->calTargetPower2G, | ||
893 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
894 | &targetPowerOfdmExt, 4, true); | ||
895 | } | ||
896 | |||
897 | for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { | ||
898 | bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || | ||
899 | (pCtlMode[ctlMode] == CTL_2GHT40); | ||
900 | if (isHt40CtlMode) | ||
901 | freq = centers.synth_center; | ||
902 | else if (pCtlMode[ctlMode] & EXT_ADDITIVE) | ||
903 | freq = centers.ext_center; | ||
904 | else | ||
905 | freq = centers.ctl_center; | ||
906 | |||
907 | if (ah->eep_ops->get_eeprom_ver(ah) == 14 && | ||
908 | ah->eep_ops->get_eeprom_rev(ah) <= 2) | ||
909 | twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
910 | |||
911 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
912 | "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " | ||
913 | "EXT_ADDITIVE %d\n", | ||
914 | ctlMode, numCtlModes, isHt40CtlMode, | ||
915 | (pCtlMode[ctlMode] & EXT_ADDITIVE)); | ||
916 | |||
917 | for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && | ||
918 | pEepData->ctlIndex[i]; i++) { | ||
919 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
920 | " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " | ||
921 | "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " | ||
922 | "chan %d\n", | ||
923 | i, cfgCtl, pCtlMode[ctlMode], | ||
924 | pEepData->ctlIndex[i], chan->channel); | ||
925 | |||
926 | if ((((cfgCtl & ~CTL_MODE_M) | | ||
927 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
928 | pEepData->ctlIndex[i]) || | ||
929 | (((cfgCtl & ~CTL_MODE_M) | | ||
930 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
931 | ((pEepData->ctlIndex[i] & CTL_MODE_M) | | ||
932 | SD_NO_CTL))) { | ||
933 | rep = &(pEepData->ctlData[i]); | ||
934 | |||
935 | twiceMinEdgePower = | ||
936 | ath9k_hw_get_max_edge_power(freq, | ||
937 | rep->ctlEdges[ar5416_get_ntxchains | ||
938 | (tx_chainmask) - 1], | ||
939 | IS_CHAN_2GHZ(chan), | ||
940 | AR5416_EEP4K_NUM_BAND_EDGES); | ||
941 | |||
942 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
943 | " MATCH-EE_IDX %d: ch %d is2 %d " | ||
944 | "2xMinEdge %d chainmask %d chains %d\n", | ||
945 | i, freq, IS_CHAN_2GHZ(chan), | ||
946 | twiceMinEdgePower, tx_chainmask, | ||
947 | ar5416_get_ntxchains | ||
948 | (tx_chainmask)); | ||
949 | if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { | ||
950 | twiceMaxEdgePower = | ||
951 | min(twiceMaxEdgePower, | ||
952 | twiceMinEdgePower); | ||
953 | } else { | ||
954 | twiceMaxEdgePower = twiceMinEdgePower; | ||
955 | break; | ||
956 | } | ||
957 | } | ||
958 | } | ||
959 | |||
960 | minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); | ||
961 | |||
962 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
963 | " SEL-Min ctlMode %d pCtlMode %d " | ||
964 | "2xMaxEdge %d sP %d minCtlPwr %d\n", | ||
965 | ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, | ||
966 | scaledPower, minCtlPower); | ||
967 | |||
968 | switch (pCtlMode[ctlMode]) { | ||
969 | case CTL_11B: | ||
970 | for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); | ||
971 | i++) { | ||
972 | targetPowerCck.tPow2x[i] = | ||
973 | min((u16)targetPowerCck.tPow2x[i], | ||
974 | minCtlPower); | ||
975 | } | ||
976 | break; | ||
977 | case CTL_11G: | ||
978 | for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); | ||
979 | i++) { | ||
980 | targetPowerOfdm.tPow2x[i] = | ||
981 | min((u16)targetPowerOfdm.tPow2x[i], | ||
982 | minCtlPower); | ||
983 | } | ||
984 | break; | ||
985 | case CTL_2GHT20: | ||
986 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); | ||
987 | i++) { | ||
988 | targetPowerHt20.tPow2x[i] = | ||
989 | min((u16)targetPowerHt20.tPow2x[i], | ||
990 | minCtlPower); | ||
991 | } | ||
992 | break; | ||
993 | case CTL_11B_EXT: | ||
994 | targetPowerCckExt.tPow2x[0] = min((u16) | ||
995 | targetPowerCckExt.tPow2x[0], | ||
996 | minCtlPower); | ||
997 | break; | ||
998 | case CTL_11G_EXT: | ||
999 | targetPowerOfdmExt.tPow2x[0] = min((u16) | ||
1000 | targetPowerOfdmExt.tPow2x[0], | ||
1001 | minCtlPower); | ||
1002 | break; | ||
1003 | case CTL_2GHT40: | ||
1004 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); | ||
1005 | i++) { | ||
1006 | targetPowerHt40.tPow2x[i] = | ||
1007 | min((u16)targetPowerHt40.tPow2x[i], | ||
1008 | minCtlPower); | ||
1009 | } | ||
1010 | break; | ||
1011 | default: | ||
1012 | break; | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = | ||
1017 | ratesArray[rate18mb] = ratesArray[rate24mb] = | ||
1018 | targetPowerOfdm.tPow2x[0]; | ||
1019 | ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; | ||
1020 | ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; | ||
1021 | ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; | ||
1022 | ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; | ||
1023 | |||
1024 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) | ||
1025 | ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; | ||
1026 | |||
1027 | ratesArray[rate1l] = targetPowerCck.tPow2x[0]; | ||
1028 | ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; | ||
1029 | ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; | ||
1030 | ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; | ||
1031 | |||
1032 | if (IS_CHAN_HT40(chan)) { | ||
1033 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
1034 | ratesArray[rateHt40_0 + i] = | ||
1035 | targetPowerHt40.tPow2x[i]; | ||
1036 | } | ||
1037 | ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; | ||
1038 | ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; | ||
1039 | ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; | ||
1040 | ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; | ||
1041 | } | ||
1042 | } | ||
1043 | |||
1044 | static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | ||
1045 | struct ath9k_channel *chan, | ||
1046 | u16 cfgCtl, | ||
1047 | u8 twiceAntennaReduction, | ||
1048 | u8 twiceMaxRegulatoryPower, | ||
1049 | u8 powerLimit) | ||
1050 | { | ||
1051 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | ||
1052 | struct modal_eep_4k_header *pModal = &pEepData->modalHeader; | ||
1053 | int16_t ratesArray[Ar5416RateSize]; | ||
1054 | int16_t txPowerIndexOffset = 0; | ||
1055 | u8 ht40PowerIncForPdadc = 2; | ||
1056 | int i; | ||
1057 | |||
1058 | memset(ratesArray, 0, sizeof(ratesArray)); | ||
1059 | |||
1060 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1061 | AR5416_EEP_MINOR_VER_2) { | ||
1062 | ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; | ||
1063 | } | ||
1064 | |||
1065 | ath9k_hw_set_4k_power_per_rate_table(ah, chan, | ||
1066 | &ratesArray[0], cfgCtl, | ||
1067 | twiceAntennaReduction, | ||
1068 | twiceMaxRegulatoryPower, | ||
1069 | powerLimit); | ||
1070 | |||
1071 | ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); | ||
1072 | |||
1073 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | ||
1074 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
1075 | if (ratesArray[i] > AR5416_MAX_RATE_POWER) | ||
1076 | ratesArray[i] = AR5416_MAX_RATE_POWER; | ||
1077 | } | ||
1078 | |||
1079 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1080 | for (i = 0; i < Ar5416RateSize; i++) | ||
1081 | ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; | ||
1082 | } | ||
1083 | |||
1084 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, | ||
1085 | ATH9K_POW_SM(ratesArray[rate18mb], 24) | ||
1086 | | ATH9K_POW_SM(ratesArray[rate12mb], 16) | ||
1087 | | ATH9K_POW_SM(ratesArray[rate9mb], 8) | ||
1088 | | ATH9K_POW_SM(ratesArray[rate6mb], 0)); | ||
1089 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, | ||
1090 | ATH9K_POW_SM(ratesArray[rate54mb], 24) | ||
1091 | | ATH9K_POW_SM(ratesArray[rate48mb], 16) | ||
1092 | | ATH9K_POW_SM(ratesArray[rate36mb], 8) | ||
1093 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); | ||
1094 | |||
1095 | if (IS_CHAN_2GHZ(chan)) { | ||
1096 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
1097 | ATH9K_POW_SM(ratesArray[rate2s], 24) | ||
1098 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | ||
1099 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
1100 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | ||
1101 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
1102 | ATH9K_POW_SM(ratesArray[rate11s], 24) | ||
1103 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | ||
1104 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | ||
1105 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | ||
1106 | } | ||
1107 | |||
1108 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, | ||
1109 | ATH9K_POW_SM(ratesArray[rateHt20_3], 24) | ||
1110 | | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) | ||
1111 | | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) | ||
1112 | | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); | ||
1113 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, | ||
1114 | ATH9K_POW_SM(ratesArray[rateHt20_7], 24) | ||
1115 | | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) | ||
1116 | | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) | ||
1117 | | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); | ||
1118 | |||
1119 | if (IS_CHAN_HT40(chan)) { | ||
1120 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
1121 | ATH9K_POW_SM(ratesArray[rateHt40_3] + | ||
1122 | ht40PowerIncForPdadc, 24) | ||
1123 | | ATH9K_POW_SM(ratesArray[rateHt40_2] + | ||
1124 | ht40PowerIncForPdadc, 16) | ||
1125 | | ATH9K_POW_SM(ratesArray[rateHt40_1] + | ||
1126 | ht40PowerIncForPdadc, 8) | ||
1127 | | ATH9K_POW_SM(ratesArray[rateHt40_0] + | ||
1128 | ht40PowerIncForPdadc, 0)); | ||
1129 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
1130 | ATH9K_POW_SM(ratesArray[rateHt40_7] + | ||
1131 | ht40PowerIncForPdadc, 24) | ||
1132 | | ATH9K_POW_SM(ratesArray[rateHt40_6] + | ||
1133 | ht40PowerIncForPdadc, 16) | ||
1134 | | ATH9K_POW_SM(ratesArray[rateHt40_5] + | ||
1135 | ht40PowerIncForPdadc, 8) | ||
1136 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + | ||
1137 | ht40PowerIncForPdadc, 0)); | ||
1138 | |||
1139 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
1140 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
1141 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ||
1142 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
1143 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | ||
1144 | } | ||
1145 | |||
1146 | i = rate6mb; | ||
1147 | |||
1148 | if (IS_CHAN_HT40(chan)) | ||
1149 | i = rateHt40_0; | ||
1150 | else if (IS_CHAN_HT20(chan)) | ||
1151 | i = rateHt20_0; | ||
1152 | |||
1153 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
1154 | ah->regulatory.max_power_level = | ||
1155 | ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; | ||
1156 | else | ||
1157 | ah->regulatory.max_power_level = ratesArray[i]; | ||
1158 | |||
1159 | } | ||
1160 | |||
1161 | static void ath9k_hw_4k_set_addac(struct ath_hw *ah, | ||
1162 | struct ath9k_channel *chan) | ||
1163 | { | ||
1164 | struct modal_eep_4k_header *pModal; | ||
1165 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
1166 | u8 biaslevel; | ||
1167 | |||
1168 | if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) | ||
1169 | return; | ||
1170 | |||
1171 | if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) | ||
1172 | return; | ||
1173 | |||
1174 | pModal = &eep->modalHeader; | ||
1175 | |||
1176 | if (pModal->xpaBiasLvl != 0xff) { | ||
1177 | biaslevel = pModal->xpaBiasLvl; | ||
1178 | INI_RA(&ah->iniAddac, 7, 1) = | ||
1179 | (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; | ||
1180 | } | ||
1181 | } | ||
1182 | |||
1183 | static void ath9k_hw_4k_set_gain(struct ath_hw *ah, | ||
1184 | struct modal_eep_4k_header *pModal, | ||
1185 | struct ar5416_eeprom_4k *eep, | ||
1186 | u8 txRxAttenLocal, int regChainOffset) | ||
1187 | { | ||
1188 | REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, | ||
1189 | pModal->antCtrlChain[0]); | ||
1190 | |||
1191 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, | ||
1192 | (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & | ||
1193 | ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | | ||
1194 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | | ||
1195 | SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | | ||
1196 | SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); | ||
1197 | |||
1198 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1199 | AR5416_EEP_MINOR_VER_3) { | ||
1200 | txRxAttenLocal = pModal->txRxAttenCh[0]; | ||
1201 | |||
1202 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1203 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); | ||
1204 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1205 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); | ||
1206 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1207 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | ||
1208 | pModal->xatten2Margin[0]); | ||
1209 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1210 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); | ||
1211 | |||
1212 | /* Set the block 1 value to block 0 value */ | ||
1213 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, | ||
1214 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, | ||
1215 | pModal->bswMargin[0]); | ||
1216 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, | ||
1217 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); | ||
1218 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, | ||
1219 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | ||
1220 | pModal->xatten2Margin[0]); | ||
1221 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, | ||
1222 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, | ||
1223 | pModal->xatten2Db[0]); | ||
1224 | } | ||
1225 | |||
1226 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, | ||
1227 | AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); | ||
1228 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, | ||
1229 | AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); | ||
1230 | |||
1231 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, | ||
1232 | AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); | ||
1233 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, | ||
1234 | AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); | ||
1235 | |||
1236 | if (AR_SREV_9285_11(ah)) | ||
1237 | REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); | ||
1238 | } | ||
1239 | |||
1240 | /* | ||
1241 | * Read EEPROM header info and program the device for correct operation | ||
1242 | * given the channel value. | ||
1243 | */ | ||
1244 | static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, | ||
1245 | struct ath9k_channel *chan) | ||
1246 | { | ||
1247 | struct modal_eep_4k_header *pModal; | ||
1248 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
1249 | u8 txRxAttenLocal; | ||
1250 | u8 ob[5], db1[5], db2[5]; | ||
1251 | u8 ant_div_control1, ant_div_control2; | ||
1252 | u32 regVal; | ||
1253 | |||
1254 | pModal = &eep->modalHeader; | ||
1255 | txRxAttenLocal = 23; | ||
1256 | |||
1257 | REG_WRITE(ah, AR_PHY_SWITCH_COM, | ||
1258 | ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); | ||
1259 | |||
1260 | /* Single chain for 4K EEPROM*/ | ||
1261 | ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); | ||
1262 | |||
1263 | /* Initialize Ant Diversity settings from EEPROM */ | ||
1264 | if (pModal->version >= 3) { | ||
1265 | ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); | ||
1266 | ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); | ||
1267 | regVal = REG_READ(ah, 0x99ac); | ||
1268 | regVal &= (~(0x7f000000)); | ||
1269 | regVal |= ((ant_div_control1 & 0x1) << 24); | ||
1270 | regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); | ||
1271 | regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); | ||
1272 | regVal |= ((ant_div_control2 & 0x3) << 25); | ||
1273 | regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); | ||
1274 | REG_WRITE(ah, 0x99ac, regVal); | ||
1275 | regVal = REG_READ(ah, 0x99ac); | ||
1276 | regVal = REG_READ(ah, 0xa208); | ||
1277 | regVal &= (~(0x1 << 13)); | ||
1278 | regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); | ||
1279 | REG_WRITE(ah, 0xa208, regVal); | ||
1280 | regVal = REG_READ(ah, 0xa208); | ||
1281 | } | ||
1282 | |||
1283 | if (pModal->version >= 2) { | ||
1284 | ob[0] = (pModal->ob_01 & 0xf); | ||
1285 | ob[1] = (pModal->ob_01 >> 4) & 0xf; | ||
1286 | ob[2] = (pModal->ob_234 & 0xf); | ||
1287 | ob[3] = ((pModal->ob_234 >> 4) & 0xf); | ||
1288 | ob[4] = ((pModal->ob_234 >> 8) & 0xf); | ||
1289 | |||
1290 | db1[0] = (pModal->db1_01 & 0xf); | ||
1291 | db1[1] = ((pModal->db1_01 >> 4) & 0xf); | ||
1292 | db1[2] = (pModal->db1_234 & 0xf); | ||
1293 | db1[3] = ((pModal->db1_234 >> 4) & 0xf); | ||
1294 | db1[4] = ((pModal->db1_234 >> 8) & 0xf); | ||
1295 | |||
1296 | db2[0] = (pModal->db2_01 & 0xf); | ||
1297 | db2[1] = ((pModal->db2_01 >> 4) & 0xf); | ||
1298 | db2[2] = (pModal->db2_234 & 0xf); | ||
1299 | db2[3] = ((pModal->db2_234 >> 4) & 0xf); | ||
1300 | db2[4] = ((pModal->db2_234 >> 8) & 0xf); | ||
1301 | |||
1302 | } else if (pModal->version == 1) { | ||
1303 | ob[0] = (pModal->ob_01 & 0xf); | ||
1304 | ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; | ||
1305 | db1[0] = (pModal->db1_01 & 0xf); | ||
1306 | db1[1] = db1[2] = db1[3] = | ||
1307 | db1[4] = ((pModal->db1_01 >> 4) & 0xf); | ||
1308 | db2[0] = (pModal->db2_01 & 0xf); | ||
1309 | db2[1] = db2[2] = db2[3] = | ||
1310 | db2[4] = ((pModal->db2_01 >> 4) & 0xf); | ||
1311 | } else { | ||
1312 | int i; | ||
1313 | for (i = 0; i < 5; i++) { | ||
1314 | ob[i] = pModal->ob_01; | ||
1315 | db1[i] = pModal->db1_01; | ||
1316 | db2[i] = pModal->db1_01; | ||
1317 | } | ||
1318 | } | ||
1319 | |||
1320 | if (AR_SREV_9271(ah)) { | ||
1321 | ath9k_hw_analog_shift_rmw(ah, | ||
1322 | AR9285_AN_RF2G3, | ||
1323 | AR9271_AN_RF2G3_OB_cck, | ||
1324 | AR9271_AN_RF2G3_OB_cck_S, | ||
1325 | ob[0]); | ||
1326 | ath9k_hw_analog_shift_rmw(ah, | ||
1327 | AR9285_AN_RF2G3, | ||
1328 | AR9271_AN_RF2G3_OB_psk, | ||
1329 | AR9271_AN_RF2G3_OB_psk_S, | ||
1330 | ob[1]); | ||
1331 | ath9k_hw_analog_shift_rmw(ah, | ||
1332 | AR9285_AN_RF2G3, | ||
1333 | AR9271_AN_RF2G3_OB_qam, | ||
1334 | AR9271_AN_RF2G3_OB_qam_S, | ||
1335 | ob[2]); | ||
1336 | ath9k_hw_analog_shift_rmw(ah, | ||
1337 | AR9285_AN_RF2G3, | ||
1338 | AR9271_AN_RF2G3_DB_1, | ||
1339 | AR9271_AN_RF2G3_DB_1_S, | ||
1340 | db1[0]); | ||
1341 | ath9k_hw_analog_shift_rmw(ah, | ||
1342 | AR9285_AN_RF2G4, | ||
1343 | AR9271_AN_RF2G4_DB_2, | ||
1344 | AR9271_AN_RF2G4_DB_2_S, | ||
1345 | db2[0]); | ||
1346 | } else { | ||
1347 | ath9k_hw_analog_shift_rmw(ah, | ||
1348 | AR9285_AN_RF2G3, | ||
1349 | AR9285_AN_RF2G3_OB_0, | ||
1350 | AR9285_AN_RF2G3_OB_0_S, | ||
1351 | ob[0]); | ||
1352 | ath9k_hw_analog_shift_rmw(ah, | ||
1353 | AR9285_AN_RF2G3, | ||
1354 | AR9285_AN_RF2G3_OB_1, | ||
1355 | AR9285_AN_RF2G3_OB_1_S, | ||
1356 | ob[1]); | ||
1357 | ath9k_hw_analog_shift_rmw(ah, | ||
1358 | AR9285_AN_RF2G3, | ||
1359 | AR9285_AN_RF2G3_OB_2, | ||
1360 | AR9285_AN_RF2G3_OB_2_S, | ||
1361 | ob[2]); | ||
1362 | ath9k_hw_analog_shift_rmw(ah, | ||
1363 | AR9285_AN_RF2G3, | ||
1364 | AR9285_AN_RF2G3_OB_3, | ||
1365 | AR9285_AN_RF2G3_OB_3_S, | ||
1366 | ob[3]); | ||
1367 | ath9k_hw_analog_shift_rmw(ah, | ||
1368 | AR9285_AN_RF2G3, | ||
1369 | AR9285_AN_RF2G3_OB_4, | ||
1370 | AR9285_AN_RF2G3_OB_4_S, | ||
1371 | ob[4]); | ||
1372 | |||
1373 | ath9k_hw_analog_shift_rmw(ah, | ||
1374 | AR9285_AN_RF2G3, | ||
1375 | AR9285_AN_RF2G3_DB1_0, | ||
1376 | AR9285_AN_RF2G3_DB1_0_S, | ||
1377 | db1[0]); | ||
1378 | ath9k_hw_analog_shift_rmw(ah, | ||
1379 | AR9285_AN_RF2G3, | ||
1380 | AR9285_AN_RF2G3_DB1_1, | ||
1381 | AR9285_AN_RF2G3_DB1_1_S, | ||
1382 | db1[1]); | ||
1383 | ath9k_hw_analog_shift_rmw(ah, | ||
1384 | AR9285_AN_RF2G3, | ||
1385 | AR9285_AN_RF2G3_DB1_2, | ||
1386 | AR9285_AN_RF2G3_DB1_2_S, | ||
1387 | db1[2]); | ||
1388 | ath9k_hw_analog_shift_rmw(ah, | ||
1389 | AR9285_AN_RF2G4, | ||
1390 | AR9285_AN_RF2G4_DB1_3, | ||
1391 | AR9285_AN_RF2G4_DB1_3_S, | ||
1392 | db1[3]); | ||
1393 | ath9k_hw_analog_shift_rmw(ah, | ||
1394 | AR9285_AN_RF2G4, | ||
1395 | AR9285_AN_RF2G4_DB1_4, | ||
1396 | AR9285_AN_RF2G4_DB1_4_S, db1[4]); | ||
1397 | |||
1398 | ath9k_hw_analog_shift_rmw(ah, | ||
1399 | AR9285_AN_RF2G4, | ||
1400 | AR9285_AN_RF2G4_DB2_0, | ||
1401 | AR9285_AN_RF2G4_DB2_0_S, | ||
1402 | db2[0]); | ||
1403 | ath9k_hw_analog_shift_rmw(ah, | ||
1404 | AR9285_AN_RF2G4, | ||
1405 | AR9285_AN_RF2G4_DB2_1, | ||
1406 | AR9285_AN_RF2G4_DB2_1_S, | ||
1407 | db2[1]); | ||
1408 | ath9k_hw_analog_shift_rmw(ah, | ||
1409 | AR9285_AN_RF2G4, | ||
1410 | AR9285_AN_RF2G4_DB2_2, | ||
1411 | AR9285_AN_RF2G4_DB2_2_S, | ||
1412 | db2[2]); | ||
1413 | ath9k_hw_analog_shift_rmw(ah, | ||
1414 | AR9285_AN_RF2G4, | ||
1415 | AR9285_AN_RF2G4_DB2_3, | ||
1416 | AR9285_AN_RF2G4_DB2_3_S, | ||
1417 | db2[3]); | ||
1418 | ath9k_hw_analog_shift_rmw(ah, | ||
1419 | AR9285_AN_RF2G4, | ||
1420 | AR9285_AN_RF2G4_DB2_4, | ||
1421 | AR9285_AN_RF2G4_DB2_4_S, | ||
1422 | db2[4]); | ||
1423 | } | ||
1424 | |||
1425 | |||
1426 | if (AR_SREV_9285_11(ah)) | ||
1427 | REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); | ||
1428 | |||
1429 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, | ||
1430 | pModal->switchSettling); | ||
1431 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, | ||
1432 | pModal->adcDesiredSize); | ||
1433 | |||
1434 | REG_WRITE(ah, AR_PHY_RF_CTL4, | ||
1435 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | | ||
1436 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | | ||
1437 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | | ||
1438 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); | ||
1439 | |||
1440 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, | ||
1441 | pModal->txEndToRxOn); | ||
1442 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, | ||
1443 | pModal->thresh62); | ||
1444 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, | ||
1445 | pModal->thresh62); | ||
1446 | |||
1447 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1448 | AR5416_EEP_MINOR_VER_2) { | ||
1449 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, | ||
1450 | pModal->txFrameToDataStart); | ||
1451 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, | ||
1452 | pModal->txFrameToPaOn); | ||
1453 | } | ||
1454 | |||
1455 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1456 | AR5416_EEP_MINOR_VER_3) { | ||
1457 | if (IS_CHAN_HT40(chan)) | ||
1458 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
1459 | AR_PHY_SETTLING_SWITCH, | ||
1460 | pModal->swSettleHt40); | ||
1461 | } | ||
1462 | } | ||
1463 | |||
1464 | static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah, | ||
1465 | struct ath9k_channel *chan) | ||
1466 | { | ||
1467 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
1468 | struct modal_eep_4k_header *pModal = &eep->modalHeader; | ||
1469 | |||
1470 | return pModal->antCtrlCommon & 0xFFFF; | ||
1471 | } | ||
1472 | |||
1473 | static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah, | ||
1474 | enum ieee80211_band freq_band) | ||
1475 | { | ||
1476 | return 1; | ||
1477 | } | ||
1478 | |||
1479 | static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) | ||
1480 | { | ||
1481 | #define EEP_MAP4K_SPURCHAN \ | ||
1482 | (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) | ||
1483 | |||
1484 | u16 spur_val = AR_NO_SPUR; | ||
1485 | |||
1486 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1487 | "Getting spur idx %d is2Ghz. %d val %x\n", | ||
1488 | i, is2GHz, ah->config.spurchans[i][is2GHz]); | ||
1489 | |||
1490 | switch (ah->config.spurmode) { | ||
1491 | case SPUR_DISABLE: | ||
1492 | break; | ||
1493 | case SPUR_ENABLE_IOCTL: | ||
1494 | spur_val = ah->config.spurchans[i][is2GHz]; | ||
1495 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1496 | "Getting spur val from new loc. %d\n", spur_val); | ||
1497 | break; | ||
1498 | case SPUR_ENABLE_EEPROM: | ||
1499 | spur_val = EEP_MAP4K_SPURCHAN; | ||
1500 | break; | ||
1501 | } | ||
1502 | |||
1503 | return spur_val; | ||
1504 | |||
1505 | #undef EEP_MAP4K_SPURCHAN | ||
1506 | } | ||
1507 | |||
1508 | static struct eeprom_ops eep_4k_ops = { | ||
1509 | .check_eeprom = ath9k_hw_4k_check_eeprom, | ||
1510 | .get_eeprom = ath9k_hw_4k_get_eeprom, | ||
1511 | .fill_eeprom = ath9k_hw_4k_fill_eeprom, | ||
1512 | .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, | ||
1513 | .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, | ||
1514 | .get_num_ant_config = ath9k_hw_4k_get_num_ant_config, | ||
1515 | .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg, | ||
1516 | .set_board_values = ath9k_hw_4k_set_board_values, | ||
1517 | .set_addac = ath9k_hw_4k_set_addac, | ||
1518 | .set_txpower = ath9k_hw_4k_set_txpower, | ||
1519 | .get_spur_channel = ath9k_hw_4k_get_spur_channel | ||
1520 | }; | ||
1521 | |||
1522 | /************************************************/ | ||
1523 | /* EEPROM Operations for non-4K (Default) cards */ | ||
1524 | /************************************************/ | ||
1525 | |||
1526 | static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah) | ||
1527 | { | ||
1528 | return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF); | ||
1529 | } | ||
1530 | |||
1531 | static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) | ||
1532 | { | ||
1533 | return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF); | ||
1534 | } | ||
1535 | |||
1536 | static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) | ||
1537 | { | ||
1538 | #define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) | ||
1539 | u16 *eep_data = (u16 *)&ah->eeprom.def; | ||
1540 | int addr, ar5416_eep_start_loc = 0x100; | ||
1541 | |||
1542 | for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { | ||
1543 | if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, | ||
1544 | eep_data)) { | ||
1545 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
1546 | "Unable to read eeprom region\n"); | ||
1547 | return false; | ||
1548 | } | ||
1549 | eep_data++; | ||
1550 | } | ||
1551 | return true; | ||
1552 | #undef SIZE_EEPROM_DEF | ||
1553 | } | ||
1554 | |||
1555 | static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) | ||
1556 | { | ||
1557 | struct ar5416_eeprom_def *eep = | ||
1558 | (struct ar5416_eeprom_def *) &ah->eeprom.def; | ||
1559 | u16 *eepdata, temp, magic, magic2; | ||
1560 | u32 sum = 0, el; | ||
1561 | bool need_swap = false; | ||
1562 | int i, addr, size; | ||
1563 | |||
1564 | if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { | ||
1565 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n"); | ||
1566 | return false; | ||
1567 | } | ||
1568 | |||
1569 | if (!ath9k_hw_use_flash(ah)) { | ||
1570 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
1571 | "Read Magic = 0x%04X\n", magic); | ||
1572 | |||
1573 | if (magic != AR5416_EEPROM_MAGIC) { | ||
1574 | magic2 = swab16(magic); | ||
1575 | |||
1576 | if (magic2 == AR5416_EEPROM_MAGIC) { | ||
1577 | size = sizeof(struct ar5416_eeprom_def); | ||
1578 | need_swap = true; | ||
1579 | eepdata = (u16 *) (&ah->eeprom); | ||
1580 | |||
1581 | for (addr = 0; addr < size / sizeof(u16); addr++) { | ||
1582 | temp = swab16(*eepdata); | ||
1583 | *eepdata = temp; | ||
1584 | eepdata++; | ||
1585 | } | ||
1586 | } else { | ||
1587 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
1588 | "Invalid EEPROM Magic. " | ||
1589 | "Endianness mismatch.\n"); | ||
1590 | return -EINVAL; | ||
1591 | } | ||
1592 | } | ||
1593 | } | ||
1594 | |||
1595 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", | ||
1596 | need_swap ? "True" : "False"); | ||
1597 | |||
1598 | if (need_swap) | ||
1599 | el = swab16(ah->eeprom.def.baseEepHeader.length); | ||
1600 | else | ||
1601 | el = ah->eeprom.def.baseEepHeader.length; | ||
1602 | |||
1603 | if (el > sizeof(struct ar5416_eeprom_def)) | ||
1604 | el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); | ||
1605 | else | ||
1606 | el = el / sizeof(u16); | ||
1607 | |||
1608 | eepdata = (u16 *)(&ah->eeprom); | ||
1609 | |||
1610 | for (i = 0; i < el; i++) | ||
1611 | sum ^= *eepdata++; | ||
1612 | |||
1613 | if (need_swap) { | ||
1614 | u32 integer, j; | ||
1615 | u16 word; | ||
1616 | |||
1617 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
1618 | "EEPROM Endianness is not native.. Changing.\n"); | ||
1619 | |||
1620 | word = swab16(eep->baseEepHeader.length); | ||
1621 | eep->baseEepHeader.length = word; | ||
1622 | |||
1623 | word = swab16(eep->baseEepHeader.checksum); | ||
1624 | eep->baseEepHeader.checksum = word; | ||
1625 | |||
1626 | word = swab16(eep->baseEepHeader.version); | ||
1627 | eep->baseEepHeader.version = word; | ||
1628 | |||
1629 | word = swab16(eep->baseEepHeader.regDmn[0]); | ||
1630 | eep->baseEepHeader.regDmn[0] = word; | ||
1631 | |||
1632 | word = swab16(eep->baseEepHeader.regDmn[1]); | ||
1633 | eep->baseEepHeader.regDmn[1] = word; | ||
1634 | |||
1635 | word = swab16(eep->baseEepHeader.rfSilent); | ||
1636 | eep->baseEepHeader.rfSilent = word; | ||
1637 | |||
1638 | word = swab16(eep->baseEepHeader.blueToothOptions); | ||
1639 | eep->baseEepHeader.blueToothOptions = word; | ||
1640 | |||
1641 | word = swab16(eep->baseEepHeader.deviceCap); | ||
1642 | eep->baseEepHeader.deviceCap = word; | ||
1643 | |||
1644 | for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { | ||
1645 | struct modal_eep_header *pModal = | ||
1646 | &eep->modalHeader[j]; | ||
1647 | integer = swab32(pModal->antCtrlCommon); | ||
1648 | pModal->antCtrlCommon = integer; | ||
1649 | |||
1650 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
1651 | integer = swab32(pModal->antCtrlChain[i]); | ||
1652 | pModal->antCtrlChain[i] = integer; | ||
1653 | } | ||
1654 | |||
1655 | for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { | ||
1656 | word = swab16(pModal->spurChans[i].spurChan); | ||
1657 | pModal->spurChans[i].spurChan = word; | ||
1658 | } | ||
1659 | } | ||
1660 | } | ||
1661 | |||
1662 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || | ||
1663 | ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { | ||
1664 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
1665 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", | ||
1666 | sum, ah->eep_ops->get_eeprom_ver(ah)); | ||
1667 | return -EINVAL; | ||
1668 | } | ||
1669 | |||
1670 | return 0; | ||
1671 | } | ||
1672 | |||
1673 | static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, | ||
1674 | enum eeprom_param param) | ||
1675 | { | ||
1676 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
1677 | struct modal_eep_header *pModal = eep->modalHeader; | ||
1678 | struct base_eep_header *pBase = &eep->baseEepHeader; | ||
1679 | |||
1680 | switch (param) { | ||
1681 | case EEP_NFTHRESH_5: | ||
1682 | return pModal[0].noiseFloorThreshCh[0]; | ||
1683 | case EEP_NFTHRESH_2: | ||
1684 | return pModal[1].noiseFloorThreshCh[0]; | ||
1685 | case AR_EEPROM_MAC(0): | ||
1686 | return pBase->macAddr[0] << 8 | pBase->macAddr[1]; | ||
1687 | case AR_EEPROM_MAC(1): | ||
1688 | return pBase->macAddr[2] << 8 | pBase->macAddr[3]; | ||
1689 | case AR_EEPROM_MAC(2): | ||
1690 | return pBase->macAddr[4] << 8 | pBase->macAddr[5]; | ||
1691 | case EEP_REG_0: | ||
1692 | return pBase->regDmn[0]; | ||
1693 | case EEP_REG_1: | ||
1694 | return pBase->regDmn[1]; | ||
1695 | case EEP_OP_CAP: | ||
1696 | return pBase->deviceCap; | ||
1697 | case EEP_OP_MODE: | ||
1698 | return pBase->opCapFlags; | ||
1699 | case EEP_RF_SILENT: | ||
1700 | return pBase->rfSilent; | ||
1701 | case EEP_OB_5: | ||
1702 | return pModal[0].ob; | ||
1703 | case EEP_DB_5: | ||
1704 | return pModal[0].db; | ||
1705 | case EEP_OB_2: | ||
1706 | return pModal[1].ob; | ||
1707 | case EEP_DB_2: | ||
1708 | return pModal[1].db; | ||
1709 | case EEP_MINOR_REV: | ||
1710 | return AR5416_VER_MASK; | ||
1711 | case EEP_TX_MASK: | ||
1712 | return pBase->txMask; | ||
1713 | case EEP_RX_MASK: | ||
1714 | return pBase->rxMask; | ||
1715 | case EEP_RXGAIN_TYPE: | ||
1716 | return pBase->rxGainType; | ||
1717 | case EEP_TXGAIN_TYPE: | ||
1718 | return pBase->txGainType; | ||
1719 | case EEP_OL_PWRCTRL: | ||
1720 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
1721 | return pBase->openLoopPwrCntl ? true : false; | ||
1722 | else | ||
1723 | return false; | ||
1724 | case EEP_RC_CHAIN_MASK: | ||
1725 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
1726 | return pBase->rcChainMask; | ||
1727 | else | ||
1728 | return 0; | ||
1729 | case EEP_DAC_HPWR_5G: | ||
1730 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) | ||
1731 | return pBase->dacHiPwrMode_5G; | ||
1732 | else | ||
1733 | return 0; | ||
1734 | case EEP_FRAC_N_5G: | ||
1735 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22) | ||
1736 | return pBase->frac_n_5g; | ||
1737 | else | ||
1738 | return 0; | ||
1739 | default: | ||
1740 | return 0; | ||
1741 | } | ||
1742 | } | ||
1743 | |||
1744 | static void ath9k_hw_def_set_gain(struct ath_hw *ah, | ||
1745 | struct modal_eep_header *pModal, | ||
1746 | struct ar5416_eeprom_def *eep, | ||
1747 | u8 txRxAttenLocal, int regChainOffset, int i) | ||
1748 | { | ||
1749 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { | ||
1750 | txRxAttenLocal = pModal->txRxAttenCh[i]; | ||
1751 | |||
1752 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1753 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1754 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, | ||
1755 | pModal->bswMargin[i]); | ||
1756 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1757 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, | ||
1758 | pModal->bswAtten[i]); | ||
1759 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1760 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | ||
1761 | pModal->xatten2Margin[i]); | ||
1762 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1763 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, | ||
1764 | pModal->xatten2Db[i]); | ||
1765 | } else { | ||
1766 | REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1767 | (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & | ||
1768 | ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | ||
1769 | | SM(pModal-> bswMargin[i], | ||
1770 | AR_PHY_GAIN_2GHZ_BSW_MARGIN)); | ||
1771 | REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1772 | (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & | ||
1773 | ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | ||
1774 | | SM(pModal->bswAtten[i], | ||
1775 | AR_PHY_GAIN_2GHZ_BSW_ATTEN)); | ||
1776 | } | ||
1777 | } | ||
1778 | |||
1779 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1780 | REG_RMW_FIELD(ah, | ||
1781 | AR_PHY_RXGAIN + regChainOffset, | ||
1782 | AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); | ||
1783 | REG_RMW_FIELD(ah, | ||
1784 | AR_PHY_RXGAIN + regChainOffset, | ||
1785 | AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]); | ||
1786 | } else { | ||
1787 | REG_WRITE(ah, | ||
1788 | AR_PHY_RXGAIN + regChainOffset, | ||
1789 | (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & | ||
1790 | ~AR_PHY_RXGAIN_TXRX_ATTEN) | ||
1791 | | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN)); | ||
1792 | REG_WRITE(ah, | ||
1793 | AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1794 | (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & | ||
1795 | ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | | ||
1796 | SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); | ||
1797 | } | ||
1798 | } | ||
1799 | |||
1800 | static void ath9k_hw_def_set_board_values(struct ath_hw *ah, | ||
1801 | struct ath9k_channel *chan) | ||
1802 | { | ||
1803 | struct modal_eep_header *pModal; | ||
1804 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
1805 | int i, regChainOffset; | ||
1806 | u8 txRxAttenLocal; | ||
1807 | |||
1808 | pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
1809 | txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; | ||
1810 | |||
1811 | REG_WRITE(ah, AR_PHY_SWITCH_COM, | ||
1812 | ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); | ||
1813 | |||
1814 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
1815 | if (AR_SREV_9280(ah)) { | ||
1816 | if (i >= 2) | ||
1817 | break; | ||
1818 | } | ||
1819 | |||
1820 | if (AR_SREV_5416_20_OR_LATER(ah) && | ||
1821 | (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) | ||
1822 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; | ||
1823 | else | ||
1824 | regChainOffset = i * 0x1000; | ||
1825 | |||
1826 | REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, | ||
1827 | pModal->antCtrlChain[i]); | ||
1828 | |||
1829 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, | ||
1830 | (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & | ||
1831 | ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | | ||
1832 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | | ||
1833 | SM(pModal->iqCalICh[i], | ||
1834 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | | ||
1835 | SM(pModal->iqCalQCh[i], | ||
1836 | AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); | ||
1837 | |||
1838 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) | ||
1839 | ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal, | ||
1840 | regChainOffset, i); | ||
1841 | } | ||
1842 | |||
1843 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1844 | if (IS_CHAN_2GHZ(chan)) { | ||
1845 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, | ||
1846 | AR_AN_RF2G1_CH0_OB, | ||
1847 | AR_AN_RF2G1_CH0_OB_S, | ||
1848 | pModal->ob); | ||
1849 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, | ||
1850 | AR_AN_RF2G1_CH0_DB, | ||
1851 | AR_AN_RF2G1_CH0_DB_S, | ||
1852 | pModal->db); | ||
1853 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, | ||
1854 | AR_AN_RF2G1_CH1_OB, | ||
1855 | AR_AN_RF2G1_CH1_OB_S, | ||
1856 | pModal->ob_ch1); | ||
1857 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, | ||
1858 | AR_AN_RF2G1_CH1_DB, | ||
1859 | AR_AN_RF2G1_CH1_DB_S, | ||
1860 | pModal->db_ch1); | ||
1861 | } else { | ||
1862 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, | ||
1863 | AR_AN_RF5G1_CH0_OB5, | ||
1864 | AR_AN_RF5G1_CH0_OB5_S, | ||
1865 | pModal->ob); | ||
1866 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, | ||
1867 | AR_AN_RF5G1_CH0_DB5, | ||
1868 | AR_AN_RF5G1_CH0_DB5_S, | ||
1869 | pModal->db); | ||
1870 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, | ||
1871 | AR_AN_RF5G1_CH1_OB5, | ||
1872 | AR_AN_RF5G1_CH1_OB5_S, | ||
1873 | pModal->ob_ch1); | ||
1874 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, | ||
1875 | AR_AN_RF5G1_CH1_DB5, | ||
1876 | AR_AN_RF5G1_CH1_DB5_S, | ||
1877 | pModal->db_ch1); | ||
1878 | } | ||
1879 | ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, | ||
1880 | AR_AN_TOP2_XPABIAS_LVL, | ||
1881 | AR_AN_TOP2_XPABIAS_LVL_S, | ||
1882 | pModal->xpaBiasLvl); | ||
1883 | ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, | ||
1884 | AR_AN_TOP2_LOCALBIAS, | ||
1885 | AR_AN_TOP2_LOCALBIAS_S, | ||
1886 | pModal->local_bias); | ||
1887 | REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, | ||
1888 | pModal->force_xpaon); | ||
1889 | } | ||
1890 | |||
1891 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, | ||
1892 | pModal->switchSettling); | ||
1893 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, | ||
1894 | pModal->adcDesiredSize); | ||
1895 | |||
1896 | if (!AR_SREV_9280_10_OR_LATER(ah)) | ||
1897 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, | ||
1898 | AR_PHY_DESIRED_SZ_PGA, | ||
1899 | pModal->pgaDesiredSize); | ||
1900 | |||
1901 | REG_WRITE(ah, AR_PHY_RF_CTL4, | ||
1902 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | ||
1903 | | SM(pModal->txEndToXpaOff, | ||
1904 | AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | ||
1905 | | SM(pModal->txFrameToXpaOn, | ||
1906 | AR_PHY_RF_CTL4_FRAME_XPAA_ON) | ||
1907 | | SM(pModal->txFrameToXpaOn, | ||
1908 | AR_PHY_RF_CTL4_FRAME_XPAB_ON)); | ||
1909 | |||
1910 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, | ||
1911 | pModal->txEndToRxOn); | ||
1912 | |||
1913 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1914 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, | ||
1915 | pModal->thresh62); | ||
1916 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, | ||
1917 | AR_PHY_EXT_CCA0_THRESH62, | ||
1918 | pModal->thresh62); | ||
1919 | } else { | ||
1920 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, | ||
1921 | pModal->thresh62); | ||
1922 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, | ||
1923 | AR_PHY_EXT_CCA_THRESH62, | ||
1924 | pModal->thresh62); | ||
1925 | } | ||
1926 | |||
1927 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) { | ||
1928 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, | ||
1929 | AR_PHY_TX_END_DATA_START, | ||
1930 | pModal->txFrameToDataStart); | ||
1931 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, | ||
1932 | pModal->txFrameToPaOn); | ||
1933 | } | ||
1934 | |||
1935 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { | ||
1936 | if (IS_CHAN_HT40(chan)) | ||
1937 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
1938 | AR_PHY_SETTLING_SWITCH, | ||
1939 | pModal->swSettleHt40); | ||
1940 | } | ||
1941 | |||
1942 | if (AR_SREV_9280_20_OR_LATER(ah) && | ||
1943 | AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
1944 | REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, | ||
1945 | AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, | ||
1946 | pModal->miscBits); | ||
1947 | |||
1948 | |||
1949 | if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { | ||
1950 | if (IS_CHAN_2GHZ(chan)) | ||
1951 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, | ||
1952 | eep->baseEepHeader.dacLpMode); | ||
1953 | else if (eep->baseEepHeader.dacHiPwrMode_5G) | ||
1954 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0); | ||
1955 | else | ||
1956 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, | ||
1957 | eep->baseEepHeader.dacLpMode); | ||
1958 | |||
1959 | REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, | ||
1960 | pModal->miscBits >> 2); | ||
1961 | |||
1962 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, | ||
1963 | AR_PHY_TX_DESIRED_SCALE_CCK, | ||
1964 | eep->baseEepHeader.desiredScaleCCK); | ||
1965 | } | ||
1966 | } | ||
1967 | |||
1968 | static void ath9k_hw_def_set_addac(struct ath_hw *ah, | ||
1969 | struct ath9k_channel *chan) | ||
1970 | { | ||
1971 | #define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) | ||
1972 | struct modal_eep_header *pModal; | ||
1973 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
1974 | u8 biaslevel; | ||
1975 | |||
1976 | if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) | ||
1977 | return; | ||
1978 | |||
1979 | if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) | ||
1980 | return; | ||
1981 | |||
1982 | pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
1983 | |||
1984 | if (pModal->xpaBiasLvl != 0xff) { | ||
1985 | biaslevel = pModal->xpaBiasLvl; | ||
1986 | } else { | ||
1987 | u16 resetFreqBin, freqBin, freqCount = 0; | ||
1988 | struct chan_centers centers; | ||
1989 | |||
1990 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
1991 | |||
1992 | resetFreqBin = FREQ2FBIN(centers.synth_center, | ||
1993 | IS_CHAN_2GHZ(chan)); | ||
1994 | freqBin = XPA_LVL_FREQ(0) & 0xff; | ||
1995 | biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); | ||
1996 | |||
1997 | freqCount++; | ||
1998 | |||
1999 | while (freqCount < 3) { | ||
2000 | if (XPA_LVL_FREQ(freqCount) == 0x0) | ||
2001 | break; | ||
2002 | |||
2003 | freqBin = XPA_LVL_FREQ(freqCount) & 0xff; | ||
2004 | if (resetFreqBin >= freqBin) | ||
2005 | biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); | ||
2006 | else | ||
2007 | break; | ||
2008 | freqCount++; | ||
2009 | } | ||
2010 | } | ||
2011 | |||
2012 | if (IS_CHAN_2GHZ(chan)) { | ||
2013 | INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac, | ||
2014 | 7, 1) & (~0x18)) | biaslevel << 3; | ||
2015 | } else { | ||
2016 | INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac, | ||
2017 | 6, 1) & (~0xc0)) | biaslevel << 6; | ||
2018 | } | ||
2019 | #undef XPA_LVL_FREQ | ||
2020 | } | ||
2021 | |||
2022 | static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, | ||
2023 | struct ath9k_channel *chan, | ||
2024 | struct cal_data_per_freq *pRawDataSet, | ||
2025 | u8 *bChans, u16 availPiers, | ||
2026 | u16 tPdGainOverlap, int16_t *pMinCalPower, | ||
2027 | u16 *pPdGainBoundaries, u8 *pPDADCValues, | ||
2028 | u16 numXpdGains) | ||
2029 | { | ||
2030 | int i, j, k; | ||
2031 | int16_t ss; | ||
2032 | u16 idxL = 0, idxR = 0, numPiers; | ||
2033 | static u8 vpdTableL[AR5416_NUM_PD_GAINS] | ||
2034 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
2035 | static u8 vpdTableR[AR5416_NUM_PD_GAINS] | ||
2036 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
2037 | static u8 vpdTableI[AR5416_NUM_PD_GAINS] | ||
2038 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
2039 | |||
2040 | u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; | ||
2041 | u8 minPwrT4[AR5416_NUM_PD_GAINS]; | ||
2042 | u8 maxPwrT4[AR5416_NUM_PD_GAINS]; | ||
2043 | int16_t vpdStep; | ||
2044 | int16_t tmpVal; | ||
2045 | u16 sizeCurrVpdTable, maxIndex, tgtIndex; | ||
2046 | bool match; | ||
2047 | int16_t minDelta = 0; | ||
2048 | struct chan_centers centers; | ||
2049 | |||
2050 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
2051 | |||
2052 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
2053 | if (bChans[numPiers] == AR5416_BCHAN_UNUSED) | ||
2054 | break; | ||
2055 | } | ||
2056 | |||
2057 | match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, | ||
2058 | IS_CHAN_2GHZ(chan)), | ||
2059 | bChans, numPiers, &idxL, &idxR); | ||
2060 | |||
2061 | if (match) { | ||
2062 | for (i = 0; i < numXpdGains; i++) { | ||
2063 | minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; | ||
2064 | maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; | ||
2065 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
2066 | pRawDataSet[idxL].pwrPdg[i], | ||
2067 | pRawDataSet[idxL].vpdPdg[i], | ||
2068 | AR5416_PD_GAIN_ICEPTS, | ||
2069 | vpdTableI[i]); | ||
2070 | } | ||
2071 | } else { | ||
2072 | for (i = 0; i < numXpdGains; i++) { | ||
2073 | pVpdL = pRawDataSet[idxL].vpdPdg[i]; | ||
2074 | pPwrL = pRawDataSet[idxL].pwrPdg[i]; | ||
2075 | pVpdR = pRawDataSet[idxR].vpdPdg[i]; | ||
2076 | pPwrR = pRawDataSet[idxR].pwrPdg[i]; | ||
2077 | |||
2078 | minPwrT4[i] = max(pPwrL[0], pPwrR[0]); | ||
2079 | |||
2080 | maxPwrT4[i] = | ||
2081 | min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], | ||
2082 | pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); | ||
2083 | |||
2084 | |||
2085 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
2086 | pPwrL, pVpdL, | ||
2087 | AR5416_PD_GAIN_ICEPTS, | ||
2088 | vpdTableL[i]); | ||
2089 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
2090 | pPwrR, pVpdR, | ||
2091 | AR5416_PD_GAIN_ICEPTS, | ||
2092 | vpdTableR[i]); | ||
2093 | |||
2094 | for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { | ||
2095 | vpdTableI[i][j] = | ||
2096 | (u8)(ath9k_hw_interpolate((u16) | ||
2097 | FREQ2FBIN(centers. | ||
2098 | synth_center, | ||
2099 | IS_CHAN_2GHZ | ||
2100 | (chan)), | ||
2101 | bChans[idxL], bChans[idxR], | ||
2102 | vpdTableL[i][j], vpdTableR[i][j])); | ||
2103 | } | ||
2104 | } | ||
2105 | } | ||
2106 | |||
2107 | *pMinCalPower = (int16_t)(minPwrT4[0] / 2); | ||
2108 | |||
2109 | k = 0; | ||
2110 | |||
2111 | for (i = 0; i < numXpdGains; i++) { | ||
2112 | if (i == (numXpdGains - 1)) | ||
2113 | pPdGainBoundaries[i] = | ||
2114 | (u16)(maxPwrT4[i] / 2); | ||
2115 | else | ||
2116 | pPdGainBoundaries[i] = | ||
2117 | (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); | ||
2118 | |||
2119 | pPdGainBoundaries[i] = | ||
2120 | min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); | ||
2121 | |||
2122 | if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { | ||
2123 | minDelta = pPdGainBoundaries[0] - 23; | ||
2124 | pPdGainBoundaries[0] = 23; | ||
2125 | } else { | ||
2126 | minDelta = 0; | ||
2127 | } | ||
2128 | |||
2129 | if (i == 0) { | ||
2130 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
2131 | ss = (int16_t)(0 - (minPwrT4[i] / 2)); | ||
2132 | else | ||
2133 | ss = 0; | ||
2134 | } else { | ||
2135 | ss = (int16_t)((pPdGainBoundaries[i - 1] - | ||
2136 | (minPwrT4[i] / 2)) - | ||
2137 | tPdGainOverlap + 1 + minDelta); | ||
2138 | } | ||
2139 | vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); | ||
2140 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
2141 | |||
2142 | while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
2143 | tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); | ||
2144 | pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); | ||
2145 | ss++; | ||
2146 | } | ||
2147 | |||
2148 | sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); | ||
2149 | tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - | ||
2150 | (minPwrT4[i] / 2)); | ||
2151 | maxIndex = (tgtIndex < sizeCurrVpdTable) ? | ||
2152 | tgtIndex : sizeCurrVpdTable; | ||
2153 | |||
2154 | while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
2155 | pPDADCValues[k++] = vpdTableI[i][ss++]; | ||
2156 | } | ||
2157 | |||
2158 | vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - | ||
2159 | vpdTableI[i][sizeCurrVpdTable - 2]); | ||
2160 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
2161 | |||
2162 | if (tgtIndex > maxIndex) { | ||
2163 | while ((ss <= tgtIndex) && | ||
2164 | (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
2165 | tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + | ||
2166 | (ss - maxIndex + 1) * vpdStep)); | ||
2167 | pPDADCValues[k++] = (u8)((tmpVal > 255) ? | ||
2168 | 255 : tmpVal); | ||
2169 | ss++; | ||
2170 | } | ||
2171 | } | ||
2172 | } | ||
2173 | |||
2174 | while (i < AR5416_PD_GAINS_IN_MASK) { | ||
2175 | pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; | ||
2176 | i++; | ||
2177 | } | ||
2178 | |||
2179 | while (k < AR5416_NUM_PDADC_VALUES) { | ||
2180 | pPDADCValues[k] = pPDADCValues[k - 1]; | ||
2181 | k++; | ||
2182 | } | ||
2183 | |||
2184 | return; | ||
2185 | } | ||
2186 | |||
2187 | static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | ||
2188 | struct ath9k_channel *chan, | ||
2189 | int16_t *pTxPowerIndexOffset) | ||
2190 | { | ||
2191 | #define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) | ||
2192 | #define SM_PDGAIN_B(x, y) \ | ||
2193 | SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y) | ||
2194 | |||
2195 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; | ||
2196 | struct cal_data_per_freq *pRawDataset; | ||
2197 | u8 *pCalBChans = NULL; | ||
2198 | u16 pdGainOverlap_t2; | ||
2199 | static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; | ||
2200 | u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; | ||
2201 | u16 numPiers, i, j; | ||
2202 | int16_t tMinCalPower; | ||
2203 | u16 numXpdGain, xpdMask; | ||
2204 | u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; | ||
2205 | u32 reg32, regOffset, regChainOffset; | ||
2206 | int16_t modalIdx; | ||
2207 | |||
2208 | modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; | ||
2209 | xpdMask = pEepData->modalHeader[modalIdx].xpdGain; | ||
2210 | |||
2211 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
2212 | AR5416_EEP_MINOR_VER_2) { | ||
2213 | pdGainOverlap_t2 = | ||
2214 | pEepData->modalHeader[modalIdx].pdGainOverlap; | ||
2215 | } else { | ||
2216 | pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), | ||
2217 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); | ||
2218 | } | ||
2219 | |||
2220 | if (IS_CHAN_2GHZ(chan)) { | ||
2221 | pCalBChans = pEepData->calFreqPier2G; | ||
2222 | numPiers = AR5416_NUM_2G_CAL_PIERS; | ||
2223 | } else { | ||
2224 | pCalBChans = pEepData->calFreqPier5G; | ||
2225 | numPiers = AR5416_NUM_5G_CAL_PIERS; | ||
2226 | } | ||
2227 | |||
2228 | if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) { | ||
2229 | pRawDataset = pEepData->calPierData2G[0]; | ||
2230 | ah->initPDADC = ((struct calDataPerFreqOpLoop *) | ||
2231 | pRawDataset)->vpdPdg[0][0]; | ||
2232 | } | ||
2233 | |||
2234 | numXpdGain = 0; | ||
2235 | |||
2236 | for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { | ||
2237 | if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { | ||
2238 | if (numXpdGain >= AR5416_NUM_PD_GAINS) | ||
2239 | break; | ||
2240 | xpdGainValues[numXpdGain] = | ||
2241 | (u16)(AR5416_PD_GAINS_IN_MASK - i); | ||
2242 | numXpdGain++; | ||
2243 | } | ||
2244 | } | ||
2245 | |||
2246 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, | ||
2247 | (numXpdGain - 1) & 0x3); | ||
2248 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, | ||
2249 | xpdGainValues[0]); | ||
2250 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, | ||
2251 | xpdGainValues[1]); | ||
2252 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, | ||
2253 | xpdGainValues[2]); | ||
2254 | |||
2255 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
2256 | if (AR_SREV_5416_20_OR_LATER(ah) && | ||
2257 | (ah->rxchainmask == 5 || ah->txchainmask == 5) && | ||
2258 | (i != 0)) { | ||
2259 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; | ||
2260 | } else | ||
2261 | regChainOffset = i * 0x1000; | ||
2262 | |||
2263 | if (pEepData->baseEepHeader.txMask & (1 << i)) { | ||
2264 | if (IS_CHAN_2GHZ(chan)) | ||
2265 | pRawDataset = pEepData->calPierData2G[i]; | ||
2266 | else | ||
2267 | pRawDataset = pEepData->calPierData5G[i]; | ||
2268 | |||
2269 | |||
2270 | if (OLC_FOR_AR9280_20_LATER) { | ||
2271 | u8 pcdacIdx; | ||
2272 | u8 txPower; | ||
2273 | |||
2274 | ath9k_get_txgain_index(ah, chan, | ||
2275 | (struct calDataPerFreqOpLoop *)pRawDataset, | ||
2276 | pCalBChans, numPiers, &txPower, &pcdacIdx); | ||
2277 | ath9k_olc_get_pdadcs(ah, pcdacIdx, | ||
2278 | txPower/2, pdadcValues); | ||
2279 | } else { | ||
2280 | ath9k_hw_get_def_gain_boundaries_pdadcs(ah, | ||
2281 | chan, pRawDataset, | ||
2282 | pCalBChans, numPiers, | ||
2283 | pdGainOverlap_t2, | ||
2284 | &tMinCalPower, | ||
2285 | gainBoundaries, | ||
2286 | pdadcValues, | ||
2287 | numXpdGain); | ||
2288 | } | ||
2289 | |||
2290 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { | ||
2291 | if (OLC_FOR_AR9280_20_LATER) { | ||
2292 | REG_WRITE(ah, | ||
2293 | AR_PHY_TPCRG5 + regChainOffset, | ||
2294 | SM(0x6, | ||
2295 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | | ||
2296 | SM_PD_GAIN(1) | SM_PD_GAIN(2) | | ||
2297 | SM_PD_GAIN(3) | SM_PD_GAIN(4)); | ||
2298 | } else { | ||
2299 | REG_WRITE(ah, | ||
2300 | AR_PHY_TPCRG5 + regChainOffset, | ||
2301 | SM(pdGainOverlap_t2, | ||
2302 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| | ||
2303 | SM_PDGAIN_B(0, 1) | | ||
2304 | SM_PDGAIN_B(1, 2) | | ||
2305 | SM_PDGAIN_B(2, 3) | | ||
2306 | SM_PDGAIN_B(3, 4)); | ||
2307 | } | ||
2308 | } | ||
2309 | |||
2310 | regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; | ||
2311 | for (j = 0; j < 32; j++) { | ||
2312 | reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | | ||
2313 | ((pdadcValues[4 * j + 1] & 0xFF) << 8) | | ||
2314 | ((pdadcValues[4 * j + 2] & 0xFF) << 16)| | ||
2315 | ((pdadcValues[4 * j + 3] & 0xFF) << 24); | ||
2316 | REG_WRITE(ah, regOffset, reg32); | ||
2317 | |||
2318 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2319 | "PDADC (%d,%4x): %4.4x %8.8x\n", | ||
2320 | i, regChainOffset, regOffset, | ||
2321 | reg32); | ||
2322 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2323 | "PDADC: Chain %d | PDADC %3d " | ||
2324 | "Value %3d | PDADC %3d Value %3d | " | ||
2325 | "PDADC %3d Value %3d | PDADC %3d " | ||
2326 | "Value %3d |\n", | ||
2327 | i, 4 * j, pdadcValues[4 * j], | ||
2328 | 4 * j + 1, pdadcValues[4 * j + 1], | ||
2329 | 4 * j + 2, pdadcValues[4 * j + 2], | ||
2330 | 4 * j + 3, | ||
2331 | pdadcValues[4 * j + 3]); | ||
2332 | |||
2333 | regOffset += 4; | ||
2334 | } | ||
2335 | } | ||
2336 | } | ||
2337 | |||
2338 | *pTxPowerIndexOffset = 0; | ||
2339 | #undef SM_PD_GAIN | ||
2340 | #undef SM_PDGAIN_B | ||
2341 | } | ||
2342 | |||
2343 | static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, | ||
2344 | struct ath9k_channel *chan, | ||
2345 | int16_t *ratesArray, | ||
2346 | u16 cfgCtl, | ||
2347 | u16 AntennaReduction, | ||
2348 | u16 twiceMaxRegulatoryPower, | ||
2349 | u16 powerLimit) | ||
2350 | { | ||
2351 | #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ | ||
2352 | #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ | ||
2353 | |||
2354 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; | ||
2355 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
2356 | static const u16 tpScaleReductionTable[5] = | ||
2357 | { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; | ||
2358 | |||
2359 | int i; | ||
2360 | int16_t twiceLargestAntenna; | ||
2361 | struct cal_ctl_data *rep; | ||
2362 | struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { | ||
2363 | 0, { 0, 0, 0, 0} | ||
2364 | }; | ||
2365 | struct cal_target_power_leg targetPowerOfdmExt = { | ||
2366 | 0, { 0, 0, 0, 0} }, targetPowerCckExt = { | ||
2367 | 0, { 0, 0, 0, 0 } | ||
2368 | }; | ||
2369 | struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { | ||
2370 | 0, {0, 0, 0, 0} | ||
2371 | }; | ||
2372 | u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; | ||
2373 | u16 ctlModesFor11a[] = | ||
2374 | { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; | ||
2375 | u16 ctlModesFor11g[] = | ||
2376 | { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, | ||
2377 | CTL_2GHT40 | ||
2378 | }; | ||
2379 | u16 numCtlModes, *pCtlMode, ctlMode, freq; | ||
2380 | struct chan_centers centers; | ||
2381 | int tx_chainmask; | ||
2382 | u16 twiceMinEdgePower; | ||
2383 | |||
2384 | tx_chainmask = ah->txchainmask; | ||
2385 | |||
2386 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
2387 | |||
2388 | twiceLargestAntenna = max( | ||
2389 | pEepData->modalHeader | ||
2390 | [IS_CHAN_2GHZ(chan)].antennaGainCh[0], | ||
2391 | pEepData->modalHeader | ||
2392 | [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); | ||
2393 | |||
2394 | twiceLargestAntenna = max((u8)twiceLargestAntenna, | ||
2395 | pEepData->modalHeader | ||
2396 | [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); | ||
2397 | |||
2398 | twiceLargestAntenna = (int16_t)min(AntennaReduction - | ||
2399 | twiceLargestAntenna, 0); | ||
2400 | |||
2401 | maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; | ||
2402 | |||
2403 | if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { | ||
2404 | maxRegAllowedPower -= | ||
2405 | (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); | ||
2406 | } | ||
2407 | |||
2408 | scaledPower = min(powerLimit, maxRegAllowedPower); | ||
2409 | |||
2410 | switch (ar5416_get_ntxchains(tx_chainmask)) { | ||
2411 | case 1: | ||
2412 | break; | ||
2413 | case 2: | ||
2414 | scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; | ||
2415 | break; | ||
2416 | case 3: | ||
2417 | scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; | ||
2418 | break; | ||
2419 | } | ||
2420 | |||
2421 | scaledPower = max((u16)0, scaledPower); | ||
2422 | |||
2423 | if (IS_CHAN_2GHZ(chan)) { | ||
2424 | numCtlModes = ARRAY_SIZE(ctlModesFor11g) - | ||
2425 | SUB_NUM_CTL_MODES_AT_2G_40; | ||
2426 | pCtlMode = ctlModesFor11g; | ||
2427 | |||
2428 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
2429 | pEepData->calTargetPowerCck, | ||
2430 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
2431 | &targetPowerCck, 4, false); | ||
2432 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
2433 | pEepData->calTargetPower2G, | ||
2434 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
2435 | &targetPowerOfdm, 4, false); | ||
2436 | ath9k_hw_get_target_powers(ah, chan, | ||
2437 | pEepData->calTargetPower2GHT20, | ||
2438 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
2439 | &targetPowerHt20, 8, false); | ||
2440 | |||
2441 | if (IS_CHAN_HT40(chan)) { | ||
2442 | numCtlModes = ARRAY_SIZE(ctlModesFor11g); | ||
2443 | ath9k_hw_get_target_powers(ah, chan, | ||
2444 | pEepData->calTargetPower2GHT40, | ||
2445 | AR5416_NUM_2G_40_TARGET_POWERS, | ||
2446 | &targetPowerHt40, 8, true); | ||
2447 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
2448 | pEepData->calTargetPowerCck, | ||
2449 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
2450 | &targetPowerCckExt, 4, true); | ||
2451 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
2452 | pEepData->calTargetPower2G, | ||
2453 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
2454 | &targetPowerOfdmExt, 4, true); | ||
2455 | } | ||
2456 | } else { | ||
2457 | numCtlModes = ARRAY_SIZE(ctlModesFor11a) - | ||
2458 | SUB_NUM_CTL_MODES_AT_5G_40; | ||
2459 | pCtlMode = ctlModesFor11a; | ||
2460 | |||
2461 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
2462 | pEepData->calTargetPower5G, | ||
2463 | AR5416_NUM_5G_20_TARGET_POWERS, | ||
2464 | &targetPowerOfdm, 4, false); | ||
2465 | ath9k_hw_get_target_powers(ah, chan, | ||
2466 | pEepData->calTargetPower5GHT20, | ||
2467 | AR5416_NUM_5G_20_TARGET_POWERS, | ||
2468 | &targetPowerHt20, 8, false); | ||
2469 | |||
2470 | if (IS_CHAN_HT40(chan)) { | ||
2471 | numCtlModes = ARRAY_SIZE(ctlModesFor11a); | ||
2472 | ath9k_hw_get_target_powers(ah, chan, | ||
2473 | pEepData->calTargetPower5GHT40, | ||
2474 | AR5416_NUM_5G_40_TARGET_POWERS, | ||
2475 | &targetPowerHt40, 8, true); | ||
2476 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
2477 | pEepData->calTargetPower5G, | ||
2478 | AR5416_NUM_5G_20_TARGET_POWERS, | ||
2479 | &targetPowerOfdmExt, 4, true); | ||
2480 | } | ||
2481 | } | ||
2482 | |||
2483 | for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { | ||
2484 | bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || | ||
2485 | (pCtlMode[ctlMode] == CTL_2GHT40); | ||
2486 | if (isHt40CtlMode) | ||
2487 | freq = centers.synth_center; | ||
2488 | else if (pCtlMode[ctlMode] & EXT_ADDITIVE) | ||
2489 | freq = centers.ext_center; | ||
2490 | else | ||
2491 | freq = centers.ctl_center; | ||
2492 | |||
2493 | if (ah->eep_ops->get_eeprom_ver(ah) == 14 && | ||
2494 | ah->eep_ops->get_eeprom_rev(ah) <= 2) | ||
2495 | twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
2496 | |||
2497 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2498 | "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " | ||
2499 | "EXT_ADDITIVE %d\n", | ||
2500 | ctlMode, numCtlModes, isHt40CtlMode, | ||
2501 | (pCtlMode[ctlMode] & EXT_ADDITIVE)); | ||
2502 | |||
2503 | for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { | ||
2504 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2505 | " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " | ||
2506 | "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " | ||
2507 | "chan %d\n", | ||
2508 | i, cfgCtl, pCtlMode[ctlMode], | ||
2509 | pEepData->ctlIndex[i], chan->channel); | ||
2510 | |||
2511 | if ((((cfgCtl & ~CTL_MODE_M) | | ||
2512 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
2513 | pEepData->ctlIndex[i]) || | ||
2514 | (((cfgCtl & ~CTL_MODE_M) | | ||
2515 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
2516 | ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { | ||
2517 | rep = &(pEepData->ctlData[i]); | ||
2518 | |||
2519 | twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, | ||
2520 | rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], | ||
2521 | IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); | ||
2522 | |||
2523 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2524 | " MATCH-EE_IDX %d: ch %d is2 %d " | ||
2525 | "2xMinEdge %d chainmask %d chains %d\n", | ||
2526 | i, freq, IS_CHAN_2GHZ(chan), | ||
2527 | twiceMinEdgePower, tx_chainmask, | ||
2528 | ar5416_get_ntxchains | ||
2529 | (tx_chainmask)); | ||
2530 | if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { | ||
2531 | twiceMaxEdgePower = min(twiceMaxEdgePower, | ||
2532 | twiceMinEdgePower); | ||
2533 | } else { | ||
2534 | twiceMaxEdgePower = twiceMinEdgePower; | ||
2535 | break; | ||
2536 | } | ||
2537 | } | ||
2538 | } | ||
2539 | |||
2540 | minCtlPower = min(twiceMaxEdgePower, scaledPower); | ||
2541 | |||
2542 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2543 | " SEL-Min ctlMode %d pCtlMode %d " | ||
2544 | "2xMaxEdge %d sP %d minCtlPwr %d\n", | ||
2545 | ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, | ||
2546 | scaledPower, minCtlPower); | ||
2547 | |||
2548 | switch (pCtlMode[ctlMode]) { | ||
2549 | case CTL_11B: | ||
2550 | for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { | ||
2551 | targetPowerCck.tPow2x[i] = | ||
2552 | min((u16)targetPowerCck.tPow2x[i], | ||
2553 | minCtlPower); | ||
2554 | } | ||
2555 | break; | ||
2556 | case CTL_11A: | ||
2557 | case CTL_11G: | ||
2558 | for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { | ||
2559 | targetPowerOfdm.tPow2x[i] = | ||
2560 | min((u16)targetPowerOfdm.tPow2x[i], | ||
2561 | minCtlPower); | ||
2562 | } | ||
2563 | break; | ||
2564 | case CTL_5GHT20: | ||
2565 | case CTL_2GHT20: | ||
2566 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { | ||
2567 | targetPowerHt20.tPow2x[i] = | ||
2568 | min((u16)targetPowerHt20.tPow2x[i], | ||
2569 | minCtlPower); | ||
2570 | } | ||
2571 | break; | ||
2572 | case CTL_11B_EXT: | ||
2573 | targetPowerCckExt.tPow2x[0] = min((u16) | ||
2574 | targetPowerCckExt.tPow2x[0], | ||
2575 | minCtlPower); | ||
2576 | break; | ||
2577 | case CTL_11A_EXT: | ||
2578 | case CTL_11G_EXT: | ||
2579 | targetPowerOfdmExt.tPow2x[0] = min((u16) | ||
2580 | targetPowerOfdmExt.tPow2x[0], | ||
2581 | minCtlPower); | ||
2582 | break; | ||
2583 | case CTL_5GHT40: | ||
2584 | case CTL_2GHT40: | ||
2585 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
2586 | targetPowerHt40.tPow2x[i] = | ||
2587 | min((u16)targetPowerHt40.tPow2x[i], | ||
2588 | minCtlPower); | ||
2589 | } | ||
2590 | break; | ||
2591 | default: | ||
2592 | break; | ||
2593 | } | ||
2594 | } | ||
2595 | |||
2596 | ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = | ||
2597 | ratesArray[rate18mb] = ratesArray[rate24mb] = | ||
2598 | targetPowerOfdm.tPow2x[0]; | ||
2599 | ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; | ||
2600 | ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; | ||
2601 | ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; | ||
2602 | ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; | ||
2603 | |||
2604 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) | ||
2605 | ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; | ||
2606 | |||
2607 | if (IS_CHAN_2GHZ(chan)) { | ||
2608 | ratesArray[rate1l] = targetPowerCck.tPow2x[0]; | ||
2609 | ratesArray[rate2s] = ratesArray[rate2l] = | ||
2610 | targetPowerCck.tPow2x[1]; | ||
2611 | ratesArray[rate5_5s] = ratesArray[rate5_5l] = | ||
2612 | targetPowerCck.tPow2x[2]; | ||
2613 | ratesArray[rate11s] = ratesArray[rate11l] = | ||
2614 | targetPowerCck.tPow2x[3]; | ||
2615 | } | ||
2616 | if (IS_CHAN_HT40(chan)) { | ||
2617 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
2618 | ratesArray[rateHt40_0 + i] = | ||
2619 | targetPowerHt40.tPow2x[i]; | ||
2620 | } | ||
2621 | ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; | ||
2622 | ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; | ||
2623 | ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; | ||
2624 | if (IS_CHAN_2GHZ(chan)) { | ||
2625 | ratesArray[rateExtCck] = | ||
2626 | targetPowerCckExt.tPow2x[0]; | ||
2627 | } | ||
2628 | } | ||
2629 | } | ||
2630 | |||
2631 | static void ath9k_hw_def_set_txpower(struct ath_hw *ah, | ||
2632 | struct ath9k_channel *chan, | ||
2633 | u16 cfgCtl, | ||
2634 | u8 twiceAntennaReduction, | ||
2635 | u8 twiceMaxRegulatoryPower, | ||
2636 | u8 powerLimit) | ||
2637 | { | ||
2638 | #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) | ||
2639 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; | ||
2640 | struct modal_eep_header *pModal = | ||
2641 | &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
2642 | int16_t ratesArray[Ar5416RateSize]; | ||
2643 | int16_t txPowerIndexOffset = 0; | ||
2644 | u8 ht40PowerIncForPdadc = 2; | ||
2645 | int i, cck_ofdm_delta = 0; | ||
2646 | |||
2647 | memset(ratesArray, 0, sizeof(ratesArray)); | ||
2648 | |||
2649 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
2650 | AR5416_EEP_MINOR_VER_2) { | ||
2651 | ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; | ||
2652 | } | ||
2653 | |||
2654 | ath9k_hw_set_def_power_per_rate_table(ah, chan, | ||
2655 | &ratesArray[0], cfgCtl, | ||
2656 | twiceAntennaReduction, | ||
2657 | twiceMaxRegulatoryPower, | ||
2658 | powerLimit); | ||
2659 | |||
2660 | ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset); | ||
2661 | |||
2662 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | ||
2663 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
2664 | if (ratesArray[i] > AR5416_MAX_RATE_POWER) | ||
2665 | ratesArray[i] = AR5416_MAX_RATE_POWER; | ||
2666 | } | ||
2667 | |||
2668 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
2669 | for (i = 0; i < Ar5416RateSize; i++) | ||
2670 | ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; | ||
2671 | } | ||
2672 | |||
2673 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, | ||
2674 | ATH9K_POW_SM(ratesArray[rate18mb], 24) | ||
2675 | | ATH9K_POW_SM(ratesArray[rate12mb], 16) | ||
2676 | | ATH9K_POW_SM(ratesArray[rate9mb], 8) | ||
2677 | | ATH9K_POW_SM(ratesArray[rate6mb], 0)); | ||
2678 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, | ||
2679 | ATH9K_POW_SM(ratesArray[rate54mb], 24) | ||
2680 | | ATH9K_POW_SM(ratesArray[rate48mb], 16) | ||
2681 | | ATH9K_POW_SM(ratesArray[rate36mb], 8) | ||
2682 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); | ||
2683 | |||
2684 | if (IS_CHAN_2GHZ(chan)) { | ||
2685 | if (OLC_FOR_AR9280_20_LATER) { | ||
2686 | cck_ofdm_delta = 2; | ||
2687 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
2688 | ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24) | ||
2689 | | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16) | ||
2690 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
2691 | | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0)); | ||
2692 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
2693 | ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24) | ||
2694 | | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16) | ||
2695 | | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8) | ||
2696 | | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0)); | ||
2697 | } else { | ||
2698 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
2699 | ATH9K_POW_SM(ratesArray[rate2s], 24) | ||
2700 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | ||
2701 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
2702 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | ||
2703 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
2704 | ATH9K_POW_SM(ratesArray[rate11s], 24) | ||
2705 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | ||
2706 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | ||
2707 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | ||
2708 | } | ||
2709 | } | ||
2710 | |||
2711 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, | ||
2712 | ATH9K_POW_SM(ratesArray[rateHt20_3], 24) | ||
2713 | | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) | ||
2714 | | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) | ||
2715 | | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); | ||
2716 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, | ||
2717 | ATH9K_POW_SM(ratesArray[rateHt20_7], 24) | ||
2718 | | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) | ||
2719 | | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) | ||
2720 | | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); | ||
2721 | |||
2722 | if (IS_CHAN_HT40(chan)) { | ||
2723 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
2724 | ATH9K_POW_SM(ratesArray[rateHt40_3] + | ||
2725 | ht40PowerIncForPdadc, 24) | ||
2726 | | ATH9K_POW_SM(ratesArray[rateHt40_2] + | ||
2727 | ht40PowerIncForPdadc, 16) | ||
2728 | | ATH9K_POW_SM(ratesArray[rateHt40_1] + | ||
2729 | ht40PowerIncForPdadc, 8) | ||
2730 | | ATH9K_POW_SM(ratesArray[rateHt40_0] + | ||
2731 | ht40PowerIncForPdadc, 0)); | ||
2732 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
2733 | ATH9K_POW_SM(ratesArray[rateHt40_7] + | ||
2734 | ht40PowerIncForPdadc, 24) | ||
2735 | | ATH9K_POW_SM(ratesArray[rateHt40_6] + | ||
2736 | ht40PowerIncForPdadc, 16) | ||
2737 | | ATH9K_POW_SM(ratesArray[rateHt40_5] + | ||
2738 | ht40PowerIncForPdadc, 8) | ||
2739 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + | ||
2740 | ht40PowerIncForPdadc, 0)); | ||
2741 | if (OLC_FOR_AR9280_20_LATER) { | ||
2742 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
2743 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
2744 | | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16) | ||
2745 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
2746 | | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0)); | ||
2747 | } else { | ||
2748 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
2749 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
2750 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ||
2751 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
2752 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | ||
2753 | } | ||
2754 | } | ||
2755 | |||
2756 | REG_WRITE(ah, AR_PHY_POWER_TX_SUB, | ||
2757 | ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) | ||
2758 | | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); | ||
2759 | |||
2760 | i = rate6mb; | ||
2761 | |||
2762 | if (IS_CHAN_HT40(chan)) | ||
2763 | i = rateHt40_0; | ||
2764 | else if (IS_CHAN_HT20(chan)) | ||
2765 | i = rateHt20_0; | ||
2766 | |||
2767 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
2768 | ah->regulatory.max_power_level = | ||
2769 | ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; | ||
2770 | else | ||
2771 | ah->regulatory.max_power_level = ratesArray[i]; | ||
2772 | |||
2773 | switch(ar5416_get_ntxchains(ah->txchainmask)) { | ||
2774 | case 1: | ||
2775 | break; | ||
2776 | case 2: | ||
2777 | ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; | ||
2778 | break; | ||
2779 | case 3: | ||
2780 | ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; | ||
2781 | break; | ||
2782 | default: | ||
2783 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2784 | "Invalid chainmask configuration\n"); | ||
2785 | break; | ||
2786 | } | ||
2787 | } | ||
2788 | |||
2789 | static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, | ||
2790 | enum ieee80211_band freq_band) | ||
2791 | { | ||
2792 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
2793 | struct modal_eep_header *pModal = | ||
2794 | &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]); | ||
2795 | struct base_eep_header *pBase = &eep->baseEepHeader; | ||
2796 | u8 num_ant_config; | ||
2797 | |||
2798 | num_ant_config = 1; | ||
2799 | |||
2800 | if (pBase->version >= 0x0E0D) | ||
2801 | if (pModal->useAnt1) | ||
2802 | num_ant_config += 1; | ||
2803 | |||
2804 | return num_ant_config; | ||
2805 | } | ||
2806 | |||
2807 | static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah, | ||
2808 | struct ath9k_channel *chan) | ||
2809 | { | ||
2810 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
2811 | struct modal_eep_header *pModal = | ||
2812 | &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
2813 | |||
2814 | return pModal->antCtrlCommon & 0xFFFF; | ||
2815 | } | ||
2816 | |||
2817 | static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) | ||
2818 | { | ||
2819 | #define EEP_DEF_SPURCHAN \ | ||
2820 | (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) | ||
2821 | |||
2822 | u16 spur_val = AR_NO_SPUR; | ||
2823 | |||
2824 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
2825 | "Getting spur idx %d is2Ghz. %d val %x\n", | ||
2826 | i, is2GHz, ah->config.spurchans[i][is2GHz]); | ||
2827 | |||
2828 | switch (ah->config.spurmode) { | ||
2829 | case SPUR_DISABLE: | ||
2830 | break; | ||
2831 | case SPUR_ENABLE_IOCTL: | ||
2832 | spur_val = ah->config.spurchans[i][is2GHz]; | ||
2833 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
2834 | "Getting spur val from new loc. %d\n", spur_val); | ||
2835 | break; | ||
2836 | case SPUR_ENABLE_EEPROM: | ||
2837 | spur_val = EEP_DEF_SPURCHAN; | ||
2838 | break; | ||
2839 | } | ||
2840 | |||
2841 | return spur_val; | ||
2842 | |||
2843 | #undef EEP_DEF_SPURCHAN | ||
2844 | } | ||
2845 | |||
2846 | static struct eeprom_ops eep_def_ops = { | ||
2847 | .check_eeprom = ath9k_hw_def_check_eeprom, | ||
2848 | .get_eeprom = ath9k_hw_def_get_eeprom, | ||
2849 | .fill_eeprom = ath9k_hw_def_fill_eeprom, | ||
2850 | .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver, | ||
2851 | .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev, | ||
2852 | .get_num_ant_config = ath9k_hw_def_get_num_ant_config, | ||
2853 | .get_eeprom_antenna_cfg = ath9k_hw_def_get_eeprom_antenna_cfg, | ||
2854 | .set_board_values = ath9k_hw_def_set_board_values, | ||
2855 | .set_addac = ath9k_hw_def_set_addac, | ||
2856 | .set_txpower = ath9k_hw_def_set_txpower, | ||
2857 | .get_spur_channel = ath9k_hw_def_get_spur_channel | ||
2858 | }; | ||
2859 | |||
2860 | |||
2861 | static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) | ||
2862 | { | ||
2863 | return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF; | ||
2864 | } | ||
2865 | |||
2866 | static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah) | ||
2867 | { | ||
2868 | return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF; | ||
2869 | } | ||
2870 | |||
2871 | static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) | ||
2872 | { | ||
2873 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
2874 | u16 *eep_data; | ||
2875 | int addr, eep_start_loc = AR9287_EEP_START_LOC; | ||
2876 | eep_data = (u16 *)eep; | ||
2877 | if (!ath9k_hw_use_flash(ah)) { | ||
2878 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2879 | "Reading from EEPROM, not flash\n"); | ||
2880 | } | ||
2881 | |||
2882 | for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); | ||
2883 | addr++) { | ||
2884 | if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { | ||
2885 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2886 | "Unable to read eeprom region \n"); | ||
2887 | return false; | ||
2888 | } | ||
2889 | eep_data++; | ||
2890 | } | ||
2891 | return true; | ||
2892 | } | ||
2893 | static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) | ||
2894 | { | ||
2895 | u32 sum = 0, el, integer; | ||
2896 | u16 temp, word, magic, magic2, *eepdata; | ||
2897 | int i, addr; | ||
2898 | bool need_swap = false; | ||
2899 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
2900 | |||
2901 | if (!ath9k_hw_use_flash(ah)) { | ||
2902 | if (!ath9k_hw_nvram_read | ||
2903 | (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { | ||
2904 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
2905 | "Reading Magic # failed\n"); | ||
2906 | return false; | ||
2907 | } | ||
2908 | |||
2909 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2910 | "Read Magic = 0x%04X\n", magic); | ||
2911 | if (magic != AR5416_EEPROM_MAGIC) { | ||
2912 | |||
2913 | |||
2914 | magic2 = swab16(magic); | ||
2915 | |||
2916 | if (magic2 == AR5416_EEPROM_MAGIC) { | ||
2917 | need_swap = true; | ||
2918 | eepdata = (u16 *)(&ah->eeprom); | ||
2919 | |||
2920 | for (addr = 0; | ||
2921 | addr < sizeof(struct ar9287_eeprom) / sizeof(u16); | ||
2922 | addr++) { | ||
2923 | temp = swab16(*eepdata); | ||
2924 | *eepdata = temp; | ||
2925 | eepdata++; | ||
2926 | } | ||
2927 | } else { | ||
2928 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
2929 | "Invalid EEPROM Magic. " | ||
2930 | "endianness mismatch.\n"); | ||
2931 | return -EINVAL; } | ||
2932 | } | ||
2933 | } | ||
2934 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? | ||
2935 | "True" : "False"); | ||
2936 | |||
2937 | if (need_swap) | ||
2938 | el = swab16(ah->eeprom.map9287.baseEepHeader.length); | ||
2939 | else | ||
2940 | el = ah->eeprom.map9287.baseEepHeader.length; | ||
2941 | |||
2942 | if (el > sizeof(struct ar9287_eeprom)) | ||
2943 | el = sizeof(struct ar9287_eeprom) / sizeof(u16); | ||
2944 | else | ||
2945 | el = el / sizeof(u16); | ||
2946 | |||
2947 | eepdata = (u16 *)(&ah->eeprom); | ||
2948 | for (i = 0; i < el; i++) | ||
2949 | sum ^= *eepdata++; | ||
2950 | |||
2951 | if (need_swap) { | ||
2952 | word = swab16(eep->baseEepHeader.length); | ||
2953 | eep->baseEepHeader.length = word; | ||
2954 | |||
2955 | word = swab16(eep->baseEepHeader.checksum); | ||
2956 | eep->baseEepHeader.checksum = word; | ||
2957 | |||
2958 | word = swab16(eep->baseEepHeader.version); | ||
2959 | eep->baseEepHeader.version = word; | ||
2960 | |||
2961 | word = swab16(eep->baseEepHeader.regDmn[0]); | ||
2962 | eep->baseEepHeader.regDmn[0] = word; | ||
2963 | |||
2964 | word = swab16(eep->baseEepHeader.regDmn[1]); | ||
2965 | eep->baseEepHeader.regDmn[1] = word; | ||
2966 | |||
2967 | word = swab16(eep->baseEepHeader.rfSilent); | ||
2968 | eep->baseEepHeader.rfSilent = word; | ||
2969 | |||
2970 | word = swab16(eep->baseEepHeader.blueToothOptions); | ||
2971 | eep->baseEepHeader.blueToothOptions = word; | ||
2972 | |||
2973 | word = swab16(eep->baseEepHeader.deviceCap); | ||
2974 | eep->baseEepHeader.deviceCap = word; | ||
2975 | |||
2976 | integer = swab32(eep->modalHeader.antCtrlCommon); | ||
2977 | eep->modalHeader.antCtrlCommon = integer; | ||
2978 | |||
2979 | for (i = 0; i < AR9287_MAX_CHAINS; i++) { | ||
2980 | integer = swab32(eep->modalHeader.antCtrlChain[i]); | ||
2981 | eep->modalHeader.antCtrlChain[i] = integer; | ||
2982 | } | ||
2983 | |||
2984 | for (i = 0; i < AR9287_EEPROM_MODAL_SPURS; i++) { | ||
2985 | word = swab16(eep->modalHeader.spurChans[i].spurChan); | ||
2986 | eep->modalHeader.spurChans[i].spurChan = word; | ||
2987 | } | ||
2988 | } | ||
2989 | |||
2990 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER | ||
2991 | || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { | ||
2992 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
2993 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", | ||
2994 | sum, ah->eep_ops->get_eeprom_ver(ah)); | ||
2995 | return -EINVAL; | ||
2996 | } | ||
2997 | |||
2998 | return 0; | ||
2999 | } | ||
3000 | |||
3001 | static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, | ||
3002 | enum eeprom_param param) | ||
3003 | { | ||
3004 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
3005 | struct modal_eep_ar9287_header *pModal = &eep->modalHeader; | ||
3006 | struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; | ||
3007 | u16 ver_minor; | ||
3008 | |||
3009 | ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK; | ||
3010 | switch (param) { | ||
3011 | case EEP_NFTHRESH_2: | ||
3012 | return pModal->noiseFloorThreshCh[0]; | ||
3013 | case AR_EEPROM_MAC(0): | ||
3014 | return pBase->macAddr[0] << 8 | pBase->macAddr[1]; | ||
3015 | case AR_EEPROM_MAC(1): | ||
3016 | return pBase->macAddr[2] << 8 | pBase->macAddr[3]; | ||
3017 | case AR_EEPROM_MAC(2): | ||
3018 | return pBase->macAddr[4] << 8 | pBase->macAddr[5]; | ||
3019 | case EEP_REG_0: | ||
3020 | return pBase->regDmn[0]; | ||
3021 | case EEP_REG_1: | ||
3022 | return pBase->regDmn[1]; | ||
3023 | case EEP_OP_CAP: | ||
3024 | return pBase->deviceCap; | ||
3025 | case EEP_OP_MODE: | ||
3026 | return pBase->opCapFlags; | ||
3027 | case EEP_RF_SILENT: | ||
3028 | return pBase->rfSilent; | ||
3029 | case EEP_MINOR_REV: | ||
3030 | return ver_minor; | ||
3031 | case EEP_TX_MASK: | ||
3032 | return pBase->txMask; | ||
3033 | case EEP_RX_MASK: | ||
3034 | return pBase->rxMask; | ||
3035 | case EEP_DEV_TYPE: | ||
3036 | return pBase->deviceType; | ||
3037 | case EEP_OL_PWRCTRL: | ||
3038 | return pBase->openLoopPwrCntl; | ||
3039 | case EEP_TEMPSENSE_SLOPE: | ||
3040 | if (ver_minor >= AR9287_EEP_MINOR_VER_2) | ||
3041 | return pBase->tempSensSlope; | ||
3042 | else | ||
3043 | return 0; | ||
3044 | case EEP_TEMPSENSE_SLOPE_PAL_ON: | ||
3045 | if (ver_minor >= AR9287_EEP_MINOR_VER_3) | ||
3046 | return pBase->tempSensSlopePalOn; | ||
3047 | else | ||
3048 | return 0; | ||
3049 | default: | ||
3050 | return 0; | ||
3051 | } | ||
3052 | } | ||
3053 | |||
3054 | |||
3055 | static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, | ||
3056 | struct ath9k_channel *chan, | ||
3057 | struct cal_data_per_freq_ar9287 *pRawDataSet, | ||
3058 | u8 *bChans, u16 availPiers, | ||
3059 | u16 tPdGainOverlap, int16_t *pMinCalPower, | ||
3060 | u16 *pPdGainBoundaries, u8 *pPDADCValues, | ||
3061 | u16 numXpdGains) | ||
3062 | { | ||
3063 | #define TMP_VAL_VPD_TABLE \ | ||
3064 | ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); | ||
3065 | int i, j, k; | ||
3066 | int16_t ss; | ||
3067 | u16 idxL = 0, idxR = 0, numPiers; | ||
3068 | u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; | ||
3069 | u8 minPwrT4[AR9287_NUM_PD_GAINS]; | ||
3070 | u8 maxPwrT4[AR9287_NUM_PD_GAINS]; | ||
3071 | int16_t vpdStep; | ||
3072 | int16_t tmpVal; | ||
3073 | u16 sizeCurrVpdTable, maxIndex, tgtIndex; | ||
3074 | bool match; | ||
3075 | int16_t minDelta = 0; | ||
3076 | struct chan_centers centers; | ||
3077 | static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] | ||
3078 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
3079 | static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] | ||
3080 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
3081 | static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] | ||
3082 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
3083 | |||
3084 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
3085 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
3086 | if (bChans[numPiers] == AR9287_BCHAN_UNUSED) | ||
3087 | break; | ||
3088 | } | ||
3089 | |||
3090 | match = ath9k_hw_get_lower_upper_index( | ||
3091 | (u8)FREQ2FBIN(centers.synth_center, | ||
3092 | IS_CHAN_2GHZ(chan)), bChans, numPiers, | ||
3093 | &idxL, &idxR); | ||
3094 | |||
3095 | if (match) { | ||
3096 | for (i = 0; i < numXpdGains; i++) { | ||
3097 | minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; | ||
3098 | maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; | ||
3099 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
3100 | pRawDataSet[idxL].pwrPdg[i], | ||
3101 | pRawDataSet[idxL].vpdPdg[i], | ||
3102 | AR9287_PD_GAIN_ICEPTS, vpdTableI[i]); | ||
3103 | } | ||
3104 | } else { | ||
3105 | for (i = 0; i < numXpdGains; i++) { | ||
3106 | pVpdL = pRawDataSet[idxL].vpdPdg[i]; | ||
3107 | pPwrL = pRawDataSet[idxL].pwrPdg[i]; | ||
3108 | pVpdR = pRawDataSet[idxR].vpdPdg[i]; | ||
3109 | pPwrR = pRawDataSet[idxR].pwrPdg[i]; | ||
3110 | |||
3111 | minPwrT4[i] = max(pPwrL[0], pPwrR[0]); | ||
3112 | |||
3113 | maxPwrT4[i] = | ||
3114 | min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1], | ||
3115 | pPwrR[AR9287_PD_GAIN_ICEPTS - 1]); | ||
3116 | |||
3117 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
3118 | pPwrL, pVpdL, | ||
3119 | AR9287_PD_GAIN_ICEPTS, | ||
3120 | vpdTableL[i]); | ||
3121 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
3122 | pPwrR, pVpdR, | ||
3123 | AR9287_PD_GAIN_ICEPTS, | ||
3124 | vpdTableR[i]); | ||
3125 | |||
3126 | for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { | ||
3127 | vpdTableI[i][j] = | ||
3128 | (u8)(ath9k_hw_interpolate((u16) | ||
3129 | FREQ2FBIN(centers. synth_center, | ||
3130 | IS_CHAN_2GHZ(chan)), | ||
3131 | bChans[idxL], bChans[idxR], | ||
3132 | vpdTableL[i][j], vpdTableR[i][j])); | ||
3133 | } | ||
3134 | } | ||
3135 | } | ||
3136 | *pMinCalPower = (int16_t)(minPwrT4[0] / 2); | ||
3137 | |||
3138 | k = 0; | ||
3139 | for (i = 0; i < numXpdGains; i++) { | ||
3140 | if (i == (numXpdGains - 1)) | ||
3141 | pPdGainBoundaries[i] = (u16)(maxPwrT4[i] / 2); | ||
3142 | else | ||
3143 | pPdGainBoundaries[i] = (u16)((maxPwrT4[i] + | ||
3144 | minPwrT4[i+1]) / 4); | ||
3145 | |||
3146 | pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER, | ||
3147 | pPdGainBoundaries[i]); | ||
3148 | |||
3149 | |||
3150 | if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { | ||
3151 | minDelta = pPdGainBoundaries[0] - 23; | ||
3152 | pPdGainBoundaries[0] = 23; | ||
3153 | } else | ||
3154 | minDelta = 0; | ||
3155 | |||
3156 | if (i == 0) { | ||
3157 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
3158 | ss = (int16_t)(0 - (minPwrT4[i] / 2)); | ||
3159 | else | ||
3160 | ss = 0; | ||
3161 | } else | ||
3162 | ss = (int16_t)((pPdGainBoundaries[i-1] - | ||
3163 | (minPwrT4[i] / 2)) - | ||
3164 | tPdGainOverlap + 1 + minDelta); | ||
3165 | |||
3166 | vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); | ||
3167 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
3168 | while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) { | ||
3169 | tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); | ||
3170 | pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); | ||
3171 | ss++; | ||
3172 | } | ||
3173 | |||
3174 | sizeCurrVpdTable = (u8)((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); | ||
3175 | tgtIndex = (u8)(pPdGainBoundaries[i] + | ||
3176 | tPdGainOverlap - (minPwrT4[i] / 2)); | ||
3177 | maxIndex = (tgtIndex < sizeCurrVpdTable) ? | ||
3178 | tgtIndex : sizeCurrVpdTable; | ||
3179 | |||
3180 | while ((ss < maxIndex) && (k < (AR9287_NUM_PDADC_VALUES - 1))) | ||
3181 | pPDADCValues[k++] = vpdTableI[i][ss++]; | ||
3182 | |||
3183 | vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - | ||
3184 | vpdTableI[i][sizeCurrVpdTable - 2]); | ||
3185 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
3186 | if (tgtIndex > maxIndex) { | ||
3187 | while ((ss <= tgtIndex) && | ||
3188 | (k < (AR9287_NUM_PDADC_VALUES - 1))) { | ||
3189 | tmpVal = (int16_t) TMP_VAL_VPD_TABLE; | ||
3190 | pPDADCValues[k++] = (u8)((tmpVal > 255) ? | ||
3191 | 255 : tmpVal); | ||
3192 | ss++; | ||
3193 | } | ||
3194 | } | ||
3195 | } | ||
3196 | |||
3197 | while (i < AR9287_PD_GAINS_IN_MASK) { | ||
3198 | pPdGainBoundaries[i] = pPdGainBoundaries[i-1]; | ||
3199 | i++; | ||
3200 | } | ||
3201 | |||
3202 | while (k < AR9287_NUM_PDADC_VALUES) { | ||
3203 | pPDADCValues[k] = pPDADCValues[k-1]; | ||
3204 | k++; | ||
3205 | } | ||
3206 | |||
3207 | #undef TMP_VAL_VPD_TABLE | ||
3208 | } | ||
3209 | |||
3210 | static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, | ||
3211 | struct ath9k_channel *chan, | ||
3212 | struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, | ||
3213 | u8 *pCalChans, u16 availPiers, | ||
3214 | int8_t *pPwr) | ||
3215 | { | ||
3216 | u8 pcdac, i = 0; | ||
3217 | u16 idxL = 0, idxR = 0, numPiers; | ||
3218 | bool match; | ||
3219 | struct chan_centers centers; | ||
3220 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
3221 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
3222 | if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED) | ||
3223 | break; | ||
3224 | } | ||
3225 | |||
3226 | match = ath9k_hw_get_lower_upper_index( | ||
3227 | (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), | ||
3228 | pCalChans, numPiers, | ||
3229 | &idxL, &idxR); | ||
3230 | |||
3231 | if (match) { | ||
3232 | pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0]; | ||
3233 | *pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0]; | ||
3234 | } else { | ||
3235 | pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0]; | ||
3236 | *pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] + | ||
3237 | pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; | ||
3238 | } | ||
3239 | |||
3240 | while ((pcdac > ah->originalGain[i]) && | ||
3241 | (i < (AR9280_TX_GAIN_TABLE_SIZE - 1))) | ||
3242 | i++; | ||
3243 | } | ||
3244 | |||
3245 | static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, | ||
3246 | int32_t txPower, u16 chain) | ||
3247 | { | ||
3248 | u32 tmpVal; | ||
3249 | u32 a; | ||
3250 | |||
3251 | tmpVal = REG_READ(ah, 0xa270); | ||
3252 | tmpVal = tmpVal & 0xFCFFFFFF; | ||
3253 | tmpVal = tmpVal | (0x3 << 24); | ||
3254 | REG_WRITE(ah, 0xa270, tmpVal); | ||
3255 | |||
3256 | tmpVal = REG_READ(ah, 0xb270); | ||
3257 | tmpVal = tmpVal & 0xFCFFFFFF; | ||
3258 | tmpVal = tmpVal | (0x3 << 24); | ||
3259 | REG_WRITE(ah, 0xb270, tmpVal); | ||
3260 | |||
3261 | if (chain == 0) { | ||
3262 | tmpVal = REG_READ(ah, 0xa398); | ||
3263 | tmpVal = tmpVal & 0xff00ffff; | ||
3264 | a = (txPower)&0xff; | ||
3265 | tmpVal = tmpVal | (a << 16); | ||
3266 | REG_WRITE(ah, 0xa398, tmpVal); | ||
3267 | } | ||
3268 | |||
3269 | if (chain == 1) { | ||
3270 | tmpVal = REG_READ(ah, 0xb398); | ||
3271 | tmpVal = tmpVal & 0xff00ffff; | ||
3272 | a = (txPower)&0xff; | ||
3273 | tmpVal = tmpVal | (a << 16); | ||
3274 | REG_WRITE(ah, 0xb398, tmpVal); | ||
3275 | } | ||
3276 | } | ||
3277 | |||
3278 | |||
3279 | static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, | ||
3280 | struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset) | ||
3281 | { | ||
3282 | struct cal_data_per_freq_ar9287 *pRawDataset; | ||
3283 | struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; | ||
3284 | u8 *pCalBChans = NULL; | ||
3285 | u16 pdGainOverlap_t2; | ||
3286 | u8 pdadcValues[AR9287_NUM_PDADC_VALUES]; | ||
3287 | u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK]; | ||
3288 | u16 numPiers = 0, i, j; | ||
3289 | int16_t tMinCalPower; | ||
3290 | u16 numXpdGain, xpdMask; | ||
3291 | u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0}; | ||
3292 | u32 reg32, regOffset, regChainOffset; | ||
3293 | int16_t modalIdx, diff = 0; | ||
3294 | struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; | ||
3295 | modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; | ||
3296 | xpdMask = pEepData->modalHeader.xpdGain; | ||
3297 | if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= | ||
3298 | AR9287_EEP_MINOR_VER_2) | ||
3299 | pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; | ||
3300 | else | ||
3301 | pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), | ||
3302 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); | ||
3303 | |||
3304 | if (IS_CHAN_2GHZ(chan)) { | ||
3305 | pCalBChans = pEepData->calFreqPier2G; | ||
3306 | numPiers = AR9287_NUM_2G_CAL_PIERS; | ||
3307 | if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { | ||
3308 | pRawDatasetOpenLoop = | ||
3309 | (struct cal_data_op_loop_ar9287 *) | ||
3310 | pEepData->calPierData2G[0]; | ||
3311 | ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; | ||
3312 | } | ||
3313 | } | ||
3314 | |||
3315 | numXpdGain = 0; | ||
3316 | for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) { | ||
3317 | if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) { | ||
3318 | if (numXpdGain >= AR9287_NUM_PD_GAINS) | ||
3319 | break; | ||
3320 | xpdGainValues[numXpdGain] = | ||
3321 | (u16)(AR9287_PD_GAINS_IN_MASK-i); | ||
3322 | numXpdGain++; | ||
3323 | } | ||
3324 | } | ||
3325 | |||
3326 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, | ||
3327 | (numXpdGain - 1) & 0x3); | ||
3328 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, | ||
3329 | xpdGainValues[0]); | ||
3330 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, | ||
3331 | xpdGainValues[1]); | ||
3332 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, | ||
3333 | xpdGainValues[2]); | ||
3334 | |||
3335 | for (i = 0; i < AR9287_MAX_CHAINS; i++) { | ||
3336 | regChainOffset = i * 0x1000; | ||
3337 | if (pEepData->baseEepHeader.txMask & (1 << i)) { | ||
3338 | pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *) | ||
3339 | pEepData->calPierData2G[i]; | ||
3340 | if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { | ||
3341 | int8_t txPower; | ||
3342 | ar9287_eeprom_get_tx_gain_index(ah, chan, | ||
3343 | pRawDatasetOpenLoop, | ||
3344 | pCalBChans, numPiers, | ||
3345 | &txPower); | ||
3346 | ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i); | ||
3347 | } else { | ||
3348 | pRawDataset = | ||
3349 | (struct cal_data_per_freq_ar9287 *) | ||
3350 | pEepData->calPierData2G[i]; | ||
3351 | ath9k_hw_get_AR9287_gain_boundaries_pdadcs( | ||
3352 | ah, chan, pRawDataset, | ||
3353 | pCalBChans, numPiers, | ||
3354 | pdGainOverlap_t2, | ||
3355 | &tMinCalPower, gainBoundaries, | ||
3356 | pdadcValues, numXpdGain); | ||
3357 | } | ||
3358 | |||
3359 | if (i == 0) { | ||
3360 | if (!ath9k_hw_AR9287_get_eeprom( | ||
3361 | ah, EEP_OL_PWRCTRL)) { | ||
3362 | REG_WRITE(ah, AR_PHY_TPCRG5 + | ||
3363 | regChainOffset, | ||
3364 | SM(pdGainOverlap_t2, | ||
3365 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | | ||
3366 | SM(gainBoundaries[0], | ||
3367 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | ||
3368 | | SM(gainBoundaries[1], | ||
3369 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | ||
3370 | | SM(gainBoundaries[2], | ||
3371 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | ||
3372 | | SM(gainBoundaries[3], | ||
3373 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); | ||
3374 | } | ||
3375 | } | ||
3376 | |||
3377 | if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB != | ||
3378 | pEepData->baseEepHeader.pwrTableOffset) { | ||
3379 | diff = (u16) | ||
3380 | (pEepData->baseEepHeader.pwrTableOffset | ||
3381 | - (int32_t)AR9287_PWR_TABLE_OFFSET_DB); | ||
3382 | diff *= 2; | ||
3383 | |||
3384 | for (j = 0; | ||
3385 | j < ((u16)AR9287_NUM_PDADC_VALUES-diff); | ||
3386 | j++) | ||
3387 | pdadcValues[j] = pdadcValues[j+diff]; | ||
3388 | |||
3389 | for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff); | ||
3390 | j < AR9287_NUM_PDADC_VALUES; j++) | ||
3391 | pdadcValues[j] = | ||
3392 | pdadcValues[ | ||
3393 | AR9287_NUM_PDADC_VALUES-diff]; | ||
3394 | } | ||
3395 | if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { | ||
3396 | regOffset = AR_PHY_BASE + (672 << 2) + | ||
3397 | regChainOffset; | ||
3398 | for (j = 0; j < 32; j++) { | ||
3399 | reg32 = ((pdadcValues[4*j + 0] | ||
3400 | & 0xFF) << 0) | | ||
3401 | ((pdadcValues[4*j + 1] | ||
3402 | & 0xFF) << 8) | | ||
3403 | ((pdadcValues[4*j + 2] | ||
3404 | & 0xFF) << 16) | | ||
3405 | ((pdadcValues[4*j + 3] | ||
3406 | & 0xFF) << 24) ; | ||
3407 | REG_WRITE(ah, regOffset, reg32); | ||
3408 | |||
3409 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
3410 | "PDADC (%d,%4x): %4.4x %8.8x\n", | ||
3411 | i, regChainOffset, regOffset, | ||
3412 | reg32); | ||
3413 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
3414 | "PDADC: Chain %d | " | ||
3415 | "PDADC %3d Value %3d | " | ||
3416 | "PDADC %3d Value %3d | " | ||
3417 | "PDADC %3d Value %3d | " | ||
3418 | "PDADC %3d Value %3d |\n", | ||
3419 | i, 4 * j, pdadcValues[4 * j], | ||
3420 | 4 * j + 1, | ||
3421 | pdadcValues[4 * j + 1], | ||
3422 | 4 * j + 2, | ||
3423 | pdadcValues[4 * j + 2], | ||
3424 | 4 * j + 3, | ||
3425 | pdadcValues[4 * j + 3]); | ||
3426 | |||
3427 | regOffset += 4; | ||
3428 | } | ||
3429 | } | ||
3430 | } | ||
3431 | } | ||
3432 | |||
3433 | *pTxPowerIndexOffset = 0; | ||
3434 | } | ||
3435 | |||
3436 | |||
3437 | static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, | ||
3438 | struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, | ||
3439 | u16 AntennaReduction, u16 twiceMaxRegulatoryPower, | ||
3440 | u16 powerLimit) | ||
3441 | { | ||
3442 | #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 | ||
3443 | #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 | ||
3444 | |||
3445 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
3446 | static const u16 tpScaleReductionTable[5] = { 0, 3, 6, 9, | ||
3447 | AR5416_MAX_RATE_POWER }; | ||
3448 | int i; | ||
3449 | int16_t twiceLargestAntenna; | ||
3450 | struct cal_ctl_data_ar9287 *rep; | ||
3451 | struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, | ||
3452 | targetPowerCck = {0, {0, 0, 0, 0} }; | ||
3453 | struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} }, | ||
3454 | targetPowerCckExt = {0, {0, 0, 0, 0} }; | ||
3455 | struct cal_target_power_ht targetPowerHt20, | ||
3456 | targetPowerHt40 = {0, {0, 0, 0, 0} }; | ||
3457 | u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; | ||
3458 | u16 ctlModesFor11g[] = {CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, | ||
3459 | CTL_11G_EXT, CTL_2GHT40}; | ||
3460 | u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq; | ||
3461 | struct chan_centers centers; | ||
3462 | int tx_chainmask; | ||
3463 | u16 twiceMinEdgePower; | ||
3464 | struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; | ||
3465 | tx_chainmask = ah->txchainmask; | ||
3466 | |||
3467 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
3468 | |||
3469 | twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0], | ||
3470 | pEepData->modalHeader.antennaGainCh[1]); | ||
3471 | |||
3472 | twiceLargestAntenna = (int16_t)min((AntennaReduction) - | ||
3473 | twiceLargestAntenna, 0); | ||
3474 | |||
3475 | maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; | ||
3476 | if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) | ||
3477 | maxRegAllowedPower -= | ||
3478 | (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); | ||
3479 | |||
3480 | scaledPower = min(powerLimit, maxRegAllowedPower); | ||
3481 | |||
3482 | switch (ar5416_get_ntxchains(tx_chainmask)) { | ||
3483 | case 1: | ||
3484 | break; | ||
3485 | case 2: | ||
3486 | scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; | ||
3487 | break; | ||
3488 | case 3: | ||
3489 | scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; | ||
3490 | break; | ||
3491 | } | ||
3492 | scaledPower = max((u16)0, scaledPower); | ||
3493 | |||
3494 | if (IS_CHAN_2GHZ(chan)) { | ||
3495 | numCtlModes = ARRAY_SIZE(ctlModesFor11g) - | ||
3496 | SUB_NUM_CTL_MODES_AT_2G_40; | ||
3497 | pCtlMode = ctlModesFor11g; | ||
3498 | |||
3499 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
3500 | pEepData->calTargetPowerCck, | ||
3501 | AR9287_NUM_2G_CCK_TARGET_POWERS, | ||
3502 | &targetPowerCck, 4, false); | ||
3503 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
3504 | pEepData->calTargetPower2G, | ||
3505 | AR9287_NUM_2G_20_TARGET_POWERS, | ||
3506 | &targetPowerOfdm, 4, false); | ||
3507 | ath9k_hw_get_target_powers(ah, chan, | ||
3508 | pEepData->calTargetPower2GHT20, | ||
3509 | AR9287_NUM_2G_20_TARGET_POWERS, | ||
3510 | &targetPowerHt20, 8, false); | ||
3511 | |||
3512 | if (IS_CHAN_HT40(chan)) { | ||
3513 | numCtlModes = ARRAY_SIZE(ctlModesFor11g); | ||
3514 | ath9k_hw_get_target_powers(ah, chan, | ||
3515 | pEepData->calTargetPower2GHT40, | ||
3516 | AR9287_NUM_2G_40_TARGET_POWERS, | ||
3517 | &targetPowerHt40, 8, true); | ||
3518 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
3519 | pEepData->calTargetPowerCck, | ||
3520 | AR9287_NUM_2G_CCK_TARGET_POWERS, | ||
3521 | &targetPowerCckExt, 4, true); | ||
3522 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
3523 | pEepData->calTargetPower2G, | ||
3524 | AR9287_NUM_2G_20_TARGET_POWERS, | ||
3525 | &targetPowerOfdmExt, 4, true); | ||
3526 | } | ||
3527 | } | ||
3528 | |||
3529 | for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { | ||
3530 | |||
3531 | bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || | ||
3532 | (pCtlMode[ctlMode] == CTL_2GHT40); | ||
3533 | if (isHt40CtlMode) | ||
3534 | freq = centers.synth_center; | ||
3535 | else if (pCtlMode[ctlMode] & EXT_ADDITIVE) | ||
3536 | freq = centers.ext_center; | ||
3537 | else | ||
3538 | freq = centers.ctl_center; | ||
3539 | |||
3540 | |||
3541 | if (ah->eep_ops->get_eeprom_ver(ah) == 14 && | ||
3542 | ah->eep_ops->get_eeprom_rev(ah) <= 2) | ||
3543 | twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
3544 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
3545 | "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d," | ||
3546 | "EXT_ADDITIVE %d\n", ctlMode, numCtlModes, | ||
3547 | isHt40CtlMode, (pCtlMode[ctlMode] & EXT_ADDITIVE)); | ||
3548 | for (i = 0; (i < AR9287_NUM_CTLS) | ||
3549 | && pEepData->ctlIndex[i]; i++) { | ||
3550 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
3551 | "LOOP-Ctlidx %d: cfgCtl 0x%2.2x" | ||
3552 | "pCtlMode 0x%2.2x ctlIndex 0x%2.2x" | ||
3553 | "chan %d chanctl=xxxx\n", | ||
3554 | i, cfgCtl, pCtlMode[ctlMode], | ||
3555 | pEepData->ctlIndex[i], chan->channel); | ||
3556 | |||
3557 | if ((((cfgCtl & ~CTL_MODE_M) | | ||
3558 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
3559 | pEepData->ctlIndex[i]) || | ||
3560 | (((cfgCtl & ~CTL_MODE_M) | | ||
3561 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
3562 | ((pEepData->ctlIndex[i] & | ||
3563 | CTL_MODE_M) | SD_NO_CTL))) { | ||
3564 | |||
3565 | rep = &(pEepData->ctlData[i]); | ||
3566 | twiceMinEdgePower = ath9k_hw_get_max_edge_power( | ||
3567 | freq, | ||
3568 | rep->ctlEdges[ar5416_get_ntxchains( | ||
3569 | tx_chainmask) - 1], | ||
3570 | IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); | ||
3571 | |||
3572 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
3573 | "MATCH-EE_IDX %d: ch %d is2 %d" | ||
3574 | "2xMinEdge %d chainmask %d chains %d\n", | ||
3575 | i, freq, IS_CHAN_2GHZ(chan), | ||
3576 | twiceMinEdgePower, tx_chainmask, | ||
3577 | ar5416_get_ntxchains(tx_chainmask)); | ||
3578 | |||
3579 | if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) | ||
3580 | twiceMaxEdgePower = min( | ||
3581 | twiceMaxEdgePower, | ||
3582 | twiceMinEdgePower); | ||
3583 | else { | ||
3584 | twiceMaxEdgePower = twiceMinEdgePower; | ||
3585 | break; | ||
3586 | } | ||
3587 | } | ||
3588 | } | ||
3589 | |||
3590 | minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); | ||
3591 | |||
3592 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
3593 | "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d" | ||
3594 | "sP %d minCtlPwr %d\n", | ||
3595 | ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, | ||
3596 | scaledPower, minCtlPower); | ||
3597 | |||
3598 | |||
3599 | switch (pCtlMode[ctlMode]) { | ||
3600 | |||
3601 | case CTL_11B: | ||
3602 | for (i = 0; | ||
3603 | i < ARRAY_SIZE(targetPowerCck.tPow2x); | ||
3604 | i++) { | ||
3605 | targetPowerCck.tPow2x[i] = (u8)min( | ||
3606 | (u16)targetPowerCck.tPow2x[i], | ||
3607 | minCtlPower); | ||
3608 | } | ||
3609 | break; | ||
3610 | case CTL_11A: | ||
3611 | case CTL_11G: | ||
3612 | for (i = 0; | ||
3613 | i < ARRAY_SIZE(targetPowerOfdm.tPow2x); | ||
3614 | i++) { | ||
3615 | targetPowerOfdm.tPow2x[i] = (u8)min( | ||
3616 | (u16)targetPowerOfdm.tPow2x[i], | ||
3617 | minCtlPower); | ||
3618 | } | ||
3619 | break; | ||
3620 | case CTL_5GHT20: | ||
3621 | case CTL_2GHT20: | ||
3622 | for (i = 0; | ||
3623 | i < ARRAY_SIZE(targetPowerHt20.tPow2x); | ||
3624 | i++) { | ||
3625 | targetPowerHt20.tPow2x[i] = (u8)min( | ||
3626 | (u16)targetPowerHt20.tPow2x[i], | ||
3627 | minCtlPower); | ||
3628 | } | ||
3629 | break; | ||
3630 | case CTL_11B_EXT: | ||
3631 | targetPowerCckExt.tPow2x[0] = (u8)min( | ||
3632 | (u16)targetPowerCckExt.tPow2x[0], | ||
3633 | minCtlPower); | ||
3634 | break; | ||
3635 | case CTL_11A_EXT: | ||
3636 | case CTL_11G_EXT: | ||
3637 | targetPowerOfdmExt.tPow2x[0] = (u8)min( | ||
3638 | (u16)targetPowerOfdmExt.tPow2x[0], | ||
3639 | minCtlPower); | ||
3640 | break; | ||
3641 | case CTL_5GHT40: | ||
3642 | case CTL_2GHT40: | ||
3643 | for (i = 0; | ||
3644 | i < ARRAY_SIZE(targetPowerHt40.tPow2x); | ||
3645 | i++) { | ||
3646 | targetPowerHt40.tPow2x[i] = (u8)min( | ||
3647 | (u16)targetPowerHt40.tPow2x[i], | ||
3648 | minCtlPower); | ||
3649 | } | ||
3650 | break; | ||
3651 | default: | ||
3652 | break; | ||
3653 | } | ||
3654 | } | ||
3655 | |||
3656 | ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = | ||
3657 | ratesArray[rate18mb] = ratesArray[rate24mb] = | ||
3658 | targetPowerOfdm.tPow2x[0]; | ||
3659 | ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; | ||
3660 | ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; | ||
3661 | ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; | ||
3662 | ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; | ||
3663 | |||
3664 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) | ||
3665 | ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; | ||
3666 | |||
3667 | if (IS_CHAN_2GHZ(chan)) { | ||
3668 | ratesArray[rate1l] = targetPowerCck.tPow2x[0]; | ||
3669 | ratesArray[rate2s] = ratesArray[rate2l] = | ||
3670 | targetPowerCck.tPow2x[1]; | ||
3671 | ratesArray[rate5_5s] = ratesArray[rate5_5l] = | ||
3672 | targetPowerCck.tPow2x[2]; | ||
3673 | ratesArray[rate11s] = ratesArray[rate11l] = | ||
3674 | targetPowerCck.tPow2x[3]; | ||
3675 | } | ||
3676 | if (IS_CHAN_HT40(chan)) { | ||
3677 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) | ||
3678 | ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; | ||
3679 | |||
3680 | ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; | ||
3681 | ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; | ||
3682 | ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; | ||
3683 | if (IS_CHAN_2GHZ(chan)) | ||
3684 | ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; | ||
3685 | } | ||
3686 | #undef REDUCE_SCALED_POWER_BY_TWO_CHAIN | ||
3687 | #undef REDUCE_SCALED_POWER_BY_THREE_CHAIN | ||
3688 | } | ||
3689 | |||
3690 | static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, | ||
3691 | struct ath9k_channel *chan, u16 cfgCtl, | ||
3692 | u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, | ||
3693 | u8 powerLimit) | ||
3694 | { | ||
3695 | #define INCREASE_MAXPOW_BY_TWO_CHAIN 6 | ||
3696 | #define INCREASE_MAXPOW_BY_THREE_CHAIN 10 | ||
3697 | struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; | ||
3698 | struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; | ||
3699 | int16_t ratesArray[Ar5416RateSize]; | ||
3700 | int16_t txPowerIndexOffset = 0; | ||
3701 | u8 ht40PowerIncForPdadc = 2; | ||
3702 | int i; | ||
3703 | memset(ratesArray, 0, sizeof(ratesArray)); | ||
3704 | |||
3705 | if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= | ||
3706 | AR9287_EEP_MINOR_VER_2) | ||
3707 | ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; | ||
3708 | |||
3709 | ath9k_hw_set_AR9287_power_per_rate_table(ah, chan, | ||
3710 | &ratesArray[0], cfgCtl, | ||
3711 | twiceAntennaReduction, | ||
3712 | twiceMaxRegulatoryPower, | ||
3713 | powerLimit); | ||
3714 | |||
3715 | |||
3716 | ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset); | ||
3717 | |||
3718 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | ||
3719 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
3720 | if (ratesArray[i] > AR9287_MAX_RATE_POWER) | ||
3721 | ratesArray[i] = AR9287_MAX_RATE_POWER; | ||
3722 | } | ||
3723 | |||
3724 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
3725 | for (i = 0; i < Ar5416RateSize; i++) | ||
3726 | ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; | ||
3727 | } | ||
3728 | |||
3729 | |||
3730 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, | ||
3731 | ATH9K_POW_SM(ratesArray[rate18mb], 24) | ||
3732 | | ATH9K_POW_SM(ratesArray[rate12mb], 16) | ||
3733 | | ATH9K_POW_SM(ratesArray[rate9mb], 8) | ||
3734 | | ATH9K_POW_SM(ratesArray[rate6mb], 0) | ||
3735 | ); | ||
3736 | |||
3737 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, | ||
3738 | ATH9K_POW_SM(ratesArray[rate54mb], 24) | ||
3739 | | ATH9K_POW_SM(ratesArray[rate48mb], 16) | ||
3740 | | ATH9K_POW_SM(ratesArray[rate36mb], 8) | ||
3741 | | ATH9K_POW_SM(ratesArray[rate24mb], 0) | ||
3742 | ); | ||
3743 | |||
3744 | if (IS_CHAN_2GHZ(chan)) { | ||
3745 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
3746 | ATH9K_POW_SM(ratesArray[rate2s], 24) | ||
3747 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | ||
3748 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
3749 | | ATH9K_POW_SM(ratesArray[rate1l], 0) | ||
3750 | ); | ||
3751 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
3752 | ATH9K_POW_SM(ratesArray[rate11s], 24) | ||
3753 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | ||
3754 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | ||
3755 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0) | ||
3756 | ); | ||
3757 | } | ||
3758 | |||
3759 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, | ||
3760 | ATH9K_POW_SM(ratesArray[rateHt20_3], 24) | ||
3761 | | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) | ||
3762 | | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) | ||
3763 | | ATH9K_POW_SM(ratesArray[rateHt20_0], 0) | ||
3764 | ); | ||
3765 | |||
3766 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, | ||
3767 | ATH9K_POW_SM(ratesArray[rateHt20_7], 24) | ||
3768 | | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) | ||
3769 | | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) | ||
3770 | | ATH9K_POW_SM(ratesArray[rateHt20_4], 0) | ||
3771 | ); | ||
3772 | |||
3773 | if (IS_CHAN_HT40(chan)) { | ||
3774 | if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { | ||
3775 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
3776 | ATH9K_POW_SM(ratesArray[rateHt40_3], 24) | ||
3777 | | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) | ||
3778 | | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) | ||
3779 | | ATH9K_POW_SM(ratesArray[rateHt40_0], 0) | ||
3780 | ); | ||
3781 | |||
3782 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
3783 | ATH9K_POW_SM(ratesArray[rateHt40_7], 24) | ||
3784 | | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) | ||
3785 | | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) | ||
3786 | | ATH9K_POW_SM(ratesArray[rateHt40_4], 0) | ||
3787 | ); | ||
3788 | } else { | ||
3789 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
3790 | ATH9K_POW_SM(ratesArray[rateHt40_3] + | ||
3791 | ht40PowerIncForPdadc, 24) | ||
3792 | | ATH9K_POW_SM(ratesArray[rateHt40_2] + | ||
3793 | ht40PowerIncForPdadc, 16) | ||
3794 | | ATH9K_POW_SM(ratesArray[rateHt40_1] + | ||
3795 | ht40PowerIncForPdadc, 8) | ||
3796 | | ATH9K_POW_SM(ratesArray[rateHt40_0] + | ||
3797 | ht40PowerIncForPdadc, 0) | ||
3798 | ); | ||
3799 | |||
3800 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
3801 | ATH9K_POW_SM(ratesArray[rateHt40_7] + | ||
3802 | ht40PowerIncForPdadc, 24) | ||
3803 | | ATH9K_POW_SM(ratesArray[rateHt40_6] + | ||
3804 | ht40PowerIncForPdadc, 16) | ||
3805 | | ATH9K_POW_SM(ratesArray[rateHt40_5] + | ||
3806 | ht40PowerIncForPdadc, 8) | ||
3807 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + | ||
3808 | ht40PowerIncForPdadc, 0) | ||
3809 | ); | ||
3810 | |||
3811 | } | ||
3812 | |||
3813 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
3814 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
3815 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ||
3816 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
3817 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0) | ||
3818 | ); | ||
3819 | } | ||
3820 | |||
3821 | |||
3822 | if (IS_CHAN_2GHZ(chan)) | ||
3823 | i = rate1l; | ||
3824 | else | ||
3825 | i = rate6mb; | ||
3826 | |||
3827 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
3828 | ah->regulatory.max_power_level = | ||
3829 | ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; | ||
3830 | else | ||
3831 | ah->regulatory.max_power_level = ratesArray[i]; | ||
3832 | |||
3833 | switch (ar5416_get_ntxchains(ah->txchainmask)) { | ||
3834 | case 1: | ||
3835 | break; | ||
3836 | case 2: | ||
3837 | ah->regulatory.max_power_level += | ||
3838 | INCREASE_MAXPOW_BY_TWO_CHAIN; | ||
3839 | break; | ||
3840 | case 3: | ||
3841 | ah->regulatory.max_power_level += | ||
3842 | INCREASE_MAXPOW_BY_THREE_CHAIN; | ||
3843 | break; | ||
3844 | default: | ||
3845 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
3846 | "Invalid chainmask configuration\n"); | ||
3847 | break; | ||
3848 | } | ||
3849 | } | ||
3850 | |||
3851 | static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah, | ||
3852 | struct ath9k_channel *chan) | ||
3853 | { | ||
3854 | return; | ||
3855 | } | ||
3856 | |||
3857 | static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, | ||
3858 | struct ath9k_channel *chan) | ||
3859 | { | ||
3860 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
3861 | struct modal_eep_ar9287_header *pModal = &eep->modalHeader; | ||
3862 | |||
3863 | u16 antWrites[AR9287_ANT_16S]; | ||
3864 | u32 regChainOffset; | ||
3865 | u8 txRxAttenLocal; | ||
3866 | int i, j, offset_num; | ||
3867 | |||
3868 | pModal = &eep->modalHeader; | ||
3869 | |||
3870 | antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF); | ||
3871 | antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF); | ||
3872 | antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF); | ||
3873 | antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF); | ||
3874 | antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF); | ||
3875 | antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF); | ||
3876 | antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF); | ||
3877 | antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF); | ||
3878 | |||
3879 | offset_num = 8; | ||
3880 | |||
3881 | for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { | ||
3882 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf); | ||
3883 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3); | ||
3884 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3); | ||
3885 | antWrites[j++] = 0; | ||
3886 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3); | ||
3887 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3); | ||
3888 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3); | ||
3889 | antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); | ||
3890 | } | ||
3891 | |||
3892 | |||
3893 | REG_WRITE(ah, AR_PHY_SWITCH_COM, | ||
3894 | ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); | ||
3895 | |||
3896 | for (i = 0; i < AR9287_MAX_CHAINS; i++) { | ||
3897 | regChainOffset = i * 0x1000; | ||
3898 | |||
3899 | REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, | ||
3900 | pModal->antCtrlChain[i]); | ||
3901 | |||
3902 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, | ||
3903 | (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) | ||
3904 | & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | | ||
3905 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | | ||
3906 | SM(pModal->iqCalICh[i], | ||
3907 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | | ||
3908 | SM(pModal->iqCalQCh[i], | ||
3909 | AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); | ||
3910 | |||
3911 | txRxAttenLocal = pModal->txRxAttenCh[i]; | ||
3912 | |||
3913 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
3914 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, | ||
3915 | pModal->bswMargin[i]); | ||
3916 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
3917 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, | ||
3918 | pModal->bswAtten[i]); | ||
3919 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, | ||
3920 | AR9280_PHY_RXGAIN_TXRX_ATTEN, | ||
3921 | txRxAttenLocal); | ||
3922 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, | ||
3923 | AR9280_PHY_RXGAIN_TXRX_MARGIN, | ||
3924 | pModal->rxTxMarginCh[i]); | ||
3925 | } | ||
3926 | |||
3927 | |||
3928 | if (IS_CHAN_HT40(chan)) | ||
3929 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
3930 | AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); | ||
3931 | else | ||
3932 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
3933 | AR_PHY_SETTLING_SWITCH, pModal->switchSettling); | ||
3934 | |||
3935 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, | ||
3936 | AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); | ||
3937 | |||
3938 | REG_WRITE(ah, AR_PHY_RF_CTL4, | ||
3939 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | ||
3940 | | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | ||
3941 | | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | ||
3942 | | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); | ||
3943 | |||
3944 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, | ||
3945 | AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); | ||
3946 | |||
3947 | REG_RMW_FIELD(ah, AR_PHY_CCA, | ||
3948 | AR9280_PHY_CCA_THRESH62, pModal->thresh62); | ||
3949 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, | ||
3950 | AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); | ||
3951 | |||
3952 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1, | ||
3953 | AR9287_AN_RF2G3_DB1_S, pModal->db1); | ||
3954 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2, | ||
3955 | AR9287_AN_RF2G3_DB2_S, pModal->db2); | ||
3956 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, | ||
3957 | AR9287_AN_RF2G3_OB_CCK, | ||
3958 | AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); | ||
3959 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, | ||
3960 | AR9287_AN_RF2G3_OB_PSK, | ||
3961 | AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); | ||
3962 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, | ||
3963 | AR9287_AN_RF2G3_OB_QAM, | ||
3964 | AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); | ||
3965 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, | ||
3966 | AR9287_AN_RF2G3_OB_PAL_OFF, | ||
3967 | AR9287_AN_RF2G3_OB_PAL_OFF_S, | ||
3968 | pModal->ob_pal_off); | ||
3969 | |||
3970 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
3971 | AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S, | ||
3972 | pModal->db1); | ||
3973 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2, | ||
3974 | AR9287_AN_RF2G3_DB2_S, pModal->db2); | ||
3975 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
3976 | AR9287_AN_RF2G3_OB_CCK, | ||
3977 | AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); | ||
3978 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
3979 | AR9287_AN_RF2G3_OB_PSK, | ||
3980 | AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); | ||
3981 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
3982 | AR9287_AN_RF2G3_OB_QAM, | ||
3983 | AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); | ||
3984 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
3985 | AR9287_AN_RF2G3_OB_PAL_OFF, | ||
3986 | AR9287_AN_RF2G3_OB_PAL_OFF_S, | ||
3987 | pModal->ob_pal_off); | ||
3988 | |||
3989 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, | ||
3990 | AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart); | ||
3991 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, | ||
3992 | AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn); | ||
3993 | |||
3994 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2, | ||
3995 | AR9287_AN_TOP2_XPABIAS_LVL, | ||
3996 | AR9287_AN_TOP2_XPABIAS_LVL_S, | ||
3997 | pModal->xpaBiasLvl); | ||
3998 | } | ||
3999 | |||
4000 | static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah, | ||
4001 | enum ieee80211_band freq_band) | ||
4002 | { | ||
4003 | return 1; | ||
4004 | } | ||
4005 | |||
4006 | |||
4007 | |||
4008 | |||
4009 | static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah, | ||
4010 | struct ath9k_channel *chan) | ||
4011 | { | ||
4012 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
4013 | struct modal_eep_ar9287_header *pModal = &eep->modalHeader; | ||
4014 | return pModal->antCtrlCommon & 0xFFFF; | ||
4015 | } | ||
4016 | |||
4017 | |||
4018 | static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, | ||
4019 | u16 i, bool is2GHz) | ||
4020 | { | ||
4021 | #define EEP_MAP9287_SPURCHAN \ | ||
4022 | (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan) | ||
4023 | u16 spur_val = AR_NO_SPUR; | ||
4024 | |||
4025 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
4026 | "Getting spur idx %d is2Ghz. %d val %x\n", | ||
4027 | i, is2GHz, ah->config.spurchans[i][is2GHz]); | ||
4028 | |||
4029 | switch (ah->config.spurmode) { | ||
4030 | case SPUR_DISABLE: | ||
4031 | break; | ||
4032 | case SPUR_ENABLE_IOCTL: | ||
4033 | spur_val = ah->config.spurchans[i][is2GHz]; | ||
4034 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
4035 | "Getting spur val from new loc. %d\n", spur_val); | ||
4036 | break; | ||
4037 | case SPUR_ENABLE_EEPROM: | ||
4038 | spur_val = EEP_MAP9287_SPURCHAN; | ||
4039 | break; | ||
4040 | } | ||
4041 | |||
4042 | return spur_val; | ||
4043 | |||
4044 | #undef EEP_MAP9287_SPURCHAN | ||
4045 | } | ||
4046 | |||
4047 | static struct eeprom_ops eep_AR9287_ops = { | ||
4048 | .check_eeprom = ath9k_hw_AR9287_check_eeprom, | ||
4049 | .get_eeprom = ath9k_hw_AR9287_get_eeprom, | ||
4050 | .fill_eeprom = ath9k_hw_AR9287_fill_eeprom, | ||
4051 | .get_eeprom_ver = ath9k_hw_AR9287_get_eeprom_ver, | ||
4052 | .get_eeprom_rev = ath9k_hw_AR9287_get_eeprom_rev, | ||
4053 | .get_num_ant_config = ath9k_hw_AR9287_get_num_ant_config, | ||
4054 | .get_eeprom_antenna_cfg = ath9k_hw_AR9287_get_eeprom_antenna_cfg, | ||
4055 | .set_board_values = ath9k_hw_AR9287_set_board_values, | ||
4056 | .set_addac = ath9k_hw_AR9287_set_addac, | ||
4057 | .set_txpower = ath9k_hw_AR9287_set_txpower, | ||
4058 | .get_spur_channel = ath9k_hw_AR9287_get_spur_channel | ||
4059 | }; | ||
4060 | |||
4061 | |||
4062 | int ath9k_hw_eeprom_init(struct ath_hw *ah) | 257 | int ath9k_hw_eeprom_init(struct ath_hw *ah) |
4063 | { | 258 | { |
4064 | int status; | 259 | int status; |
260 | |||
4065 | if (AR_SREV_9287(ah)) { | 261 | if (AR_SREV_9287(ah)) { |
4066 | ah->eep_map = EEP_MAP_AR9287; | 262 | ah->eep_map = EEP_MAP_AR9287; |
4067 | ah->eep_ops = &eep_AR9287_ops; | 263 | ah->eep_ops = &eep_AR9287_ops; |
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index db77e90ed9ab..4fe33f7eee9d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h | |||
@@ -385,106 +385,124 @@ struct calDataPerFreqOpLoop { | |||
385 | } __packed; | 385 | } __packed; |
386 | 386 | ||
387 | struct modal_eep_4k_header { | 387 | struct modal_eep_4k_header { |
388 | u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; | 388 | u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; |
389 | u32 antCtrlCommon; | 389 | u32 antCtrlCommon; |
390 | u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; | 390 | u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; |
391 | u8 switchSettling; | 391 | u8 switchSettling; |
392 | u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; | 392 | u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; |
393 | u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS]; | 393 | u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS]; |
394 | u8 adcDesiredSize; | 394 | u8 adcDesiredSize; |
395 | u8 pgaDesiredSize; | 395 | u8 pgaDesiredSize; |
396 | u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS]; | 396 | u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS]; |
397 | u8 txEndToXpaOff; | 397 | u8 txEndToXpaOff; |
398 | u8 txEndToRxOn; | 398 | u8 txEndToRxOn; |
399 | u8 txFrameToXpaOn; | 399 | u8 txFrameToXpaOn; |
400 | u8 thresh62; | 400 | u8 thresh62; |
401 | u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS]; | 401 | u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS]; |
402 | u8 xpdGain; | 402 | u8 xpdGain; |
403 | u8 xpd; | 403 | u8 xpd; |
404 | u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; | 404 | u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; |
405 | u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; | 405 | u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; |
406 | u8 pdGainOverlap; | 406 | u8 pdGainOverlap; |
407 | u8 ob_01; | 407 | #ifdef __BIG_ENDIAN_BITFIELD |
408 | u8 db1_01; | 408 | u8 ob_1:4, ob_0:4; |
409 | u8 xpaBiasLvl; | 409 | u8 db1_1:4, db1_0:4; |
410 | u8 txFrameToDataStart; | 410 | #else |
411 | u8 txFrameToPaOn; | 411 | u8 ob_0:4, ob_1:4; |
412 | u8 ht40PowerIncForPdadc; | 412 | u8 db1_0:4, db1_1:4; |
413 | u8 bswAtten[AR5416_EEP4K_MAX_CHAINS]; | 413 | #endif |
414 | u8 bswMargin[AR5416_EEP4K_MAX_CHAINS]; | 414 | u8 xpaBiasLvl; |
415 | u8 swSettleHt40; | 415 | u8 txFrameToDataStart; |
416 | u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; | 416 | u8 txFrameToPaOn; |
417 | u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; | 417 | u8 ht40PowerIncForPdadc; |
418 | u8 db2_01; | 418 | u8 bswAtten[AR5416_EEP4K_MAX_CHAINS]; |
419 | u8 version; | 419 | u8 bswMargin[AR5416_EEP4K_MAX_CHAINS]; |
420 | u16 ob_234; | 420 | u8 swSettleHt40; |
421 | u16 db1_234; | 421 | u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; |
422 | u16 db2_234; | 422 | u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; |
423 | u8 futureModal[4]; | 423 | #ifdef __BIG_ENDIAN_BITFIELD |
424 | 424 | u8 db2_1:4, db2_0:4; | |
425 | #else | ||
426 | u8 db2_0:4, db2_1:4; | ||
427 | #endif | ||
428 | u8 version; | ||
429 | #ifdef __BIG_ENDIAN_BITFIELD | ||
430 | u8 ob_3:4, ob_2:4; | ||
431 | u8 antdiv_ctl1:4, ob_4:4; | ||
432 | u8 db1_3:4, db1_2:4; | ||
433 | u8 antdiv_ctl2:4, db1_4:4; | ||
434 | u8 db2_2:4, db2_3:4; | ||
435 | u8 reserved:4, db2_4:4; | ||
436 | #else | ||
437 | u8 ob_2:4, ob_3:4; | ||
438 | u8 ob_4:4, antdiv_ctl1:4; | ||
439 | u8 db1_2:4, db1_3:4; | ||
440 | u8 db1_4:4, antdiv_ctl2:4; | ||
441 | u8 db2_2:4, db2_3:4; | ||
442 | u8 db2_4:4, reserved:4; | ||
443 | #endif | ||
444 | u8 futureModal[4]; | ||
425 | struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; | 445 | struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; |
426 | } __packed; | 446 | } __packed; |
427 | 447 | ||
428 | struct base_eep_ar9287_header { | 448 | struct base_eep_ar9287_header { |
429 | u16 length; | 449 | u16 length; |
430 | u16 checksum; | 450 | u16 checksum; |
431 | u16 version; | 451 | u16 version; |
432 | u8 opCapFlags; | 452 | u8 opCapFlags; |
433 | u8 eepMisc; | 453 | u8 eepMisc; |
434 | u16 regDmn[2]; | 454 | u16 regDmn[2]; |
435 | u8 macAddr[6]; | 455 | u8 macAddr[6]; |
436 | u8 rxMask; | 456 | u8 rxMask; |
437 | u8 txMask; | 457 | u8 txMask; |
438 | u16 rfSilent; | 458 | u16 rfSilent; |
439 | u16 blueToothOptions; | 459 | u16 blueToothOptions; |
440 | u16 deviceCap; | 460 | u16 deviceCap; |
441 | u32 binBuildNumber; | 461 | u32 binBuildNumber; |
442 | u8 deviceType; | 462 | u8 deviceType; |
443 | u8 openLoopPwrCntl; | 463 | u8 openLoopPwrCntl; |
444 | int8_t pwrTableOffset; | 464 | int8_t pwrTableOffset; |
445 | int8_t tempSensSlope; | 465 | int8_t tempSensSlope; |
446 | int8_t tempSensSlopePalOn; | 466 | int8_t tempSensSlopePalOn; |
447 | u8 futureBase[29]; | 467 | u8 futureBase[29]; |
448 | } __packed; | 468 | } __packed; |
449 | 469 | ||
450 | struct modal_eep_ar9287_header { | 470 | struct modal_eep_ar9287_header { |
451 | u32 antCtrlChain[AR9287_MAX_CHAINS]; | 471 | u32 antCtrlChain[AR9287_MAX_CHAINS]; |
452 | u32 antCtrlCommon; | 472 | u32 antCtrlCommon; |
453 | int8_t antennaGainCh[AR9287_MAX_CHAINS]; | 473 | int8_t antennaGainCh[AR9287_MAX_CHAINS]; |
454 | u8 switchSettling; | 474 | u8 switchSettling; |
455 | u8 txRxAttenCh[AR9287_MAX_CHAINS]; | 475 | u8 txRxAttenCh[AR9287_MAX_CHAINS]; |
456 | u8 rxTxMarginCh[AR9287_MAX_CHAINS]; | 476 | u8 rxTxMarginCh[AR9287_MAX_CHAINS]; |
457 | int8_t adcDesiredSize; | 477 | int8_t adcDesiredSize; |
458 | u8 txEndToXpaOff; | 478 | u8 txEndToXpaOff; |
459 | u8 txEndToRxOn; | 479 | u8 txEndToRxOn; |
460 | u8 txFrameToXpaOn; | 480 | u8 txFrameToXpaOn; |
461 | u8 thresh62; | 481 | u8 thresh62; |
462 | int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS]; | 482 | int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS]; |
463 | u8 xpdGain; | 483 | u8 xpdGain; |
464 | u8 xpd; | 484 | u8 xpd; |
465 | int8_t iqCalICh[AR9287_MAX_CHAINS]; | 485 | int8_t iqCalICh[AR9287_MAX_CHAINS]; |
466 | int8_t iqCalQCh[AR9287_MAX_CHAINS]; | 486 | int8_t iqCalQCh[AR9287_MAX_CHAINS]; |
467 | u8 pdGainOverlap; | 487 | u8 pdGainOverlap; |
468 | u8 xpaBiasLvl; | 488 | u8 xpaBiasLvl; |
469 | u8 txFrameToDataStart; | 489 | u8 txFrameToDataStart; |
470 | u8 txFrameToPaOn; | 490 | u8 txFrameToPaOn; |
471 | u8 ht40PowerIncForPdadc; | 491 | u8 ht40PowerIncForPdadc; |
472 | u8 bswAtten[AR9287_MAX_CHAINS]; | 492 | u8 bswAtten[AR9287_MAX_CHAINS]; |
473 | u8 bswMargin[AR9287_MAX_CHAINS]; | 493 | u8 bswMargin[AR9287_MAX_CHAINS]; |
474 | u8 swSettleHt40; | 494 | u8 swSettleHt40; |
475 | u8 version; | 495 | u8 version; |
476 | u8 db1; | 496 | u8 db1; |
477 | u8 db2; | 497 | u8 db2; |
478 | u8 ob_cck; | 498 | u8 ob_cck; |
479 | u8 ob_psk; | 499 | u8 ob_psk; |
480 | u8 ob_qam; | 500 | u8 ob_qam; |
481 | u8 ob_pal_off; | 501 | u8 ob_pal_off; |
482 | u8 futureModal[30]; | 502 | u8 futureModal[30]; |
483 | struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS]; | 503 | struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS]; |
484 | } __packed; | 504 | } __packed; |
485 | 505 | ||
486 | |||
487 | |||
488 | struct cal_data_per_freq { | 506 | struct cal_data_per_freq { |
489 | u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; | 507 | u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; |
490 | u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; | 508 | u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; |
@@ -525,7 +543,6 @@ struct cal_data_op_loop_ar9287 { | |||
525 | u8 empty[2][5]; | 543 | u8 empty[2][5]; |
526 | } __packed; | 544 | } __packed; |
527 | 545 | ||
528 | |||
529 | struct cal_data_per_freq_ar9287 { | 546 | struct cal_data_per_freq_ar9287 { |
530 | u8 pwrPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS]; | 547 | u8 pwrPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS]; |
531 | u8 vpdPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS]; | 548 | u8 vpdPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS]; |
@@ -601,26 +618,25 @@ struct ar5416_eeprom_4k { | |||
601 | } __packed; | 618 | } __packed; |
602 | 619 | ||
603 | struct ar9287_eeprom { | 620 | struct ar9287_eeprom { |
604 | struct base_eep_ar9287_header baseEepHeader; | 621 | struct base_eep_ar9287_header baseEepHeader; |
605 | u8 custData[AR9287_DATA_SZ]; | 622 | u8 custData[AR9287_DATA_SZ]; |
606 | struct modal_eep_ar9287_header modalHeader; | 623 | struct modal_eep_ar9287_header modalHeader; |
607 | u8 calFreqPier2G[AR9287_NUM_2G_CAL_PIERS]; | 624 | u8 calFreqPier2G[AR9287_NUM_2G_CAL_PIERS]; |
608 | union cal_data_per_freq_ar9287_u | 625 | union cal_data_per_freq_ar9287_u |
609 | calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS]; | 626 | calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS]; |
610 | struct cal_target_power_leg | 627 | struct cal_target_power_leg |
611 | calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS]; | 628 | calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS]; |
612 | struct cal_target_power_leg | 629 | struct cal_target_power_leg |
613 | calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS]; | 630 | calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS]; |
614 | struct cal_target_power_ht | 631 | struct cal_target_power_ht |
615 | calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS]; | 632 | calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS]; |
616 | struct cal_target_power_ht | 633 | struct cal_target_power_ht |
617 | calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS]; | 634 | calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS]; |
618 | u8 ctlIndex[AR9287_NUM_CTLS]; | 635 | u8 ctlIndex[AR9287_NUM_CTLS]; |
619 | struct cal_ctl_data_ar9287 ctlData[AR9287_NUM_CTLS]; | 636 | struct cal_ctl_data_ar9287 ctlData[AR9287_NUM_CTLS]; |
620 | u8 padding; | 637 | u8 padding; |
621 | } __packed; | 638 | } __packed; |
622 | 639 | ||
623 | |||
624 | enum reg_ext_bitmap { | 640 | enum reg_ext_bitmap { |
625 | REG_EXT_JAPAN_MIDBAND = 1, | 641 | REG_EXT_JAPAN_MIDBAND = 1, |
626 | REG_EXT_FCC_DFS_HT40 = 2, | 642 | REG_EXT_FCC_DFS_HT40 = 2, |
@@ -661,10 +677,39 @@ struct eeprom_ops { | |||
661 | u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz); | 677 | u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz); |
662 | }; | 678 | }; |
663 | 679 | ||
680 | void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, | ||
681 | u32 shift, u32 val); | ||
682 | int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, | ||
683 | int16_t targetLeft, | ||
684 | int16_t targetRight); | ||
685 | bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, | ||
686 | u16 *indexL, u16 *indexR); | ||
687 | bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data); | ||
688 | void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, | ||
689 | u8 *pVpdList, u16 numIntercepts, | ||
690 | u8 *pRetVpdList); | ||
691 | void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, | ||
692 | struct ath9k_channel *chan, | ||
693 | struct cal_target_power_leg *powInfo, | ||
694 | u16 numChannels, | ||
695 | struct cal_target_power_leg *pNewPower, | ||
696 | u16 numRates, bool isExtTarget); | ||
697 | void ath9k_hw_get_target_powers(struct ath_hw *ah, | ||
698 | struct ath9k_channel *chan, | ||
699 | struct cal_target_power_ht *powInfo, | ||
700 | u16 numChannels, | ||
701 | struct cal_target_power_ht *pNewPower, | ||
702 | u16 numRates, bool isHt40Target); | ||
703 | u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, | ||
704 | bool is2GHz, int num_band_edges); | ||
705 | int ath9k_hw_eeprom_init(struct ath_hw *ah); | ||
706 | |||
664 | #define ar5416_get_ntxchains(_txchainmask) \ | 707 | #define ar5416_get_ntxchains(_txchainmask) \ |
665 | (((_txchainmask >> 2) & 1) + \ | 708 | (((_txchainmask >> 2) & 1) + \ |
666 | ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) | 709 | ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) |
667 | 710 | ||
668 | int ath9k_hw_eeprom_init(struct ath_hw *ah); | 711 | extern const struct eeprom_ops eep_def_ops; |
712 | extern const struct eeprom_ops eep_4k_ops; | ||
713 | extern const struct eeprom_ops eep_AR9287_ops; | ||
669 | 714 | ||
670 | #endif /* EEPROM_H */ | 715 | #endif /* EEPROM_H */ |
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c new file mode 100644 index 000000000000..d34dd23e806a --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c | |||
@@ -0,0 +1,1186 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008-2009 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "ath9k.h" | ||
18 | |||
19 | static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) | ||
20 | { | ||
21 | return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF); | ||
22 | } | ||
23 | |||
24 | static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) | ||
25 | { | ||
26 | return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); | ||
27 | } | ||
28 | |||
29 | static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) | ||
30 | { | ||
31 | #define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) | ||
32 | u16 *eep_data = (u16 *)&ah->eeprom.map4k; | ||
33 | int addr, eep_start_loc = 0; | ||
34 | |||
35 | eep_start_loc = 64; | ||
36 | |||
37 | if (!ath9k_hw_use_flash(ah)) { | ||
38 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
39 | "Reading from EEPROM, not flash\n"); | ||
40 | } | ||
41 | |||
42 | for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { | ||
43 | if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { | ||
44 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
45 | "Unable to read eeprom region \n"); | ||
46 | return false; | ||
47 | } | ||
48 | eep_data++; | ||
49 | } | ||
50 | |||
51 | return true; | ||
52 | #undef SIZE_EEPROM_4K | ||
53 | } | ||
54 | |||
55 | static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) | ||
56 | { | ||
57 | #define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) | ||
58 | struct ar5416_eeprom_4k *eep = | ||
59 | (struct ar5416_eeprom_4k *) &ah->eeprom.map4k; | ||
60 | u16 *eepdata, temp, magic, magic2; | ||
61 | u32 sum = 0, el; | ||
62 | bool need_swap = false; | ||
63 | int i, addr; | ||
64 | |||
65 | |||
66 | if (!ath9k_hw_use_flash(ah)) { | ||
67 | if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, | ||
68 | &magic)) { | ||
69 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
70 | "Reading Magic # failed\n"); | ||
71 | return false; | ||
72 | } | ||
73 | |||
74 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
75 | "Read Magic = 0x%04X\n", magic); | ||
76 | |||
77 | if (magic != AR5416_EEPROM_MAGIC) { | ||
78 | magic2 = swab16(magic); | ||
79 | |||
80 | if (magic2 == AR5416_EEPROM_MAGIC) { | ||
81 | need_swap = true; | ||
82 | eepdata = (u16 *) (&ah->eeprom); | ||
83 | |||
84 | for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { | ||
85 | temp = swab16(*eepdata); | ||
86 | *eepdata = temp; | ||
87 | eepdata++; | ||
88 | } | ||
89 | } else { | ||
90 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
91 | "Invalid EEPROM Magic. " | ||
92 | "endianness mismatch.\n"); | ||
93 | return -EINVAL; | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | |||
98 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", | ||
99 | need_swap ? "True" : "False"); | ||
100 | |||
101 | if (need_swap) | ||
102 | el = swab16(ah->eeprom.map4k.baseEepHeader.length); | ||
103 | else | ||
104 | el = ah->eeprom.map4k.baseEepHeader.length; | ||
105 | |||
106 | if (el > sizeof(struct ar5416_eeprom_4k)) | ||
107 | el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); | ||
108 | else | ||
109 | el = el / sizeof(u16); | ||
110 | |||
111 | eepdata = (u16 *)(&ah->eeprom); | ||
112 | |||
113 | for (i = 0; i < el; i++) | ||
114 | sum ^= *eepdata++; | ||
115 | |||
116 | if (need_swap) { | ||
117 | u32 integer; | ||
118 | u16 word; | ||
119 | |||
120 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
121 | "EEPROM Endianness is not native.. Changing\n"); | ||
122 | |||
123 | word = swab16(eep->baseEepHeader.length); | ||
124 | eep->baseEepHeader.length = word; | ||
125 | |||
126 | word = swab16(eep->baseEepHeader.checksum); | ||
127 | eep->baseEepHeader.checksum = word; | ||
128 | |||
129 | word = swab16(eep->baseEepHeader.version); | ||
130 | eep->baseEepHeader.version = word; | ||
131 | |||
132 | word = swab16(eep->baseEepHeader.regDmn[0]); | ||
133 | eep->baseEepHeader.regDmn[0] = word; | ||
134 | |||
135 | word = swab16(eep->baseEepHeader.regDmn[1]); | ||
136 | eep->baseEepHeader.regDmn[1] = word; | ||
137 | |||
138 | word = swab16(eep->baseEepHeader.rfSilent); | ||
139 | eep->baseEepHeader.rfSilent = word; | ||
140 | |||
141 | word = swab16(eep->baseEepHeader.blueToothOptions); | ||
142 | eep->baseEepHeader.blueToothOptions = word; | ||
143 | |||
144 | word = swab16(eep->baseEepHeader.deviceCap); | ||
145 | eep->baseEepHeader.deviceCap = word; | ||
146 | |||
147 | integer = swab32(eep->modalHeader.antCtrlCommon); | ||
148 | eep->modalHeader.antCtrlCommon = integer; | ||
149 | |||
150 | for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { | ||
151 | integer = swab32(eep->modalHeader.antCtrlChain[i]); | ||
152 | eep->modalHeader.antCtrlChain[i] = integer; | ||
153 | } | ||
154 | |||
155 | for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { | ||
156 | word = swab16(eep->modalHeader.spurChans[i].spurChan); | ||
157 | eep->modalHeader.spurChans[i].spurChan = word; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || | ||
162 | ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { | ||
163 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
164 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", | ||
165 | sum, ah->eep_ops->get_eeprom_ver(ah)); | ||
166 | return -EINVAL; | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | #undef EEPROM_4K_SIZE | ||
171 | } | ||
172 | |||
173 | static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, | ||
174 | enum eeprom_param param) | ||
175 | { | ||
176 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
177 | struct modal_eep_4k_header *pModal = &eep->modalHeader; | ||
178 | struct base_eep_header_4k *pBase = &eep->baseEepHeader; | ||
179 | |||
180 | switch (param) { | ||
181 | case EEP_NFTHRESH_2: | ||
182 | return pModal->noiseFloorThreshCh[0]; | ||
183 | case AR_EEPROM_MAC(0): | ||
184 | return pBase->macAddr[0] << 8 | pBase->macAddr[1]; | ||
185 | case AR_EEPROM_MAC(1): | ||
186 | return pBase->macAddr[2] << 8 | pBase->macAddr[3]; | ||
187 | case AR_EEPROM_MAC(2): | ||
188 | return pBase->macAddr[4] << 8 | pBase->macAddr[5]; | ||
189 | case EEP_REG_0: | ||
190 | return pBase->regDmn[0]; | ||
191 | case EEP_REG_1: | ||
192 | return pBase->regDmn[1]; | ||
193 | case EEP_OP_CAP: | ||
194 | return pBase->deviceCap; | ||
195 | case EEP_OP_MODE: | ||
196 | return pBase->opCapFlags; | ||
197 | case EEP_RF_SILENT: | ||
198 | return pBase->rfSilent; | ||
199 | case EEP_OB_2: | ||
200 | return pModal->ob_0; | ||
201 | case EEP_DB_2: | ||
202 | return pModal->db1_1; | ||
203 | case EEP_MINOR_REV: | ||
204 | return pBase->version & AR5416_EEP_VER_MINOR_MASK; | ||
205 | case EEP_TX_MASK: | ||
206 | return pBase->txMask; | ||
207 | case EEP_RX_MASK: | ||
208 | return pBase->rxMask; | ||
209 | case EEP_FRAC_N_5G: | ||
210 | return 0; | ||
211 | default: | ||
212 | return 0; | ||
213 | } | ||
214 | } | ||
215 | |||
216 | static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, | ||
217 | struct ath9k_channel *chan, | ||
218 | struct cal_data_per_freq_4k *pRawDataSet, | ||
219 | u8 *bChans, u16 availPiers, | ||
220 | u16 tPdGainOverlap, int16_t *pMinCalPower, | ||
221 | u16 *pPdGainBoundaries, u8 *pPDADCValues, | ||
222 | u16 numXpdGains) | ||
223 | { | ||
224 | #define TMP_VAL_VPD_TABLE \ | ||
225 | ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); | ||
226 | int i, j, k; | ||
227 | int16_t ss; | ||
228 | u16 idxL = 0, idxR = 0, numPiers; | ||
229 | static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] | ||
230 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
231 | static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] | ||
232 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
233 | static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] | ||
234 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
235 | |||
236 | u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; | ||
237 | u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; | ||
238 | u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; | ||
239 | int16_t vpdStep; | ||
240 | int16_t tmpVal; | ||
241 | u16 sizeCurrVpdTable, maxIndex, tgtIndex; | ||
242 | bool match; | ||
243 | int16_t minDelta = 0; | ||
244 | struct chan_centers centers; | ||
245 | #define PD_GAIN_BOUNDARY_DEFAULT 58; | ||
246 | |||
247 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
248 | |||
249 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
250 | if (bChans[numPiers] == AR5416_BCHAN_UNUSED) | ||
251 | break; | ||
252 | } | ||
253 | |||
254 | match = ath9k_hw_get_lower_upper_index( | ||
255 | (u8)FREQ2FBIN(centers.synth_center, | ||
256 | IS_CHAN_2GHZ(chan)), bChans, numPiers, | ||
257 | &idxL, &idxR); | ||
258 | |||
259 | if (match) { | ||
260 | for (i = 0; i < numXpdGains; i++) { | ||
261 | minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; | ||
262 | maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; | ||
263 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
264 | pRawDataSet[idxL].pwrPdg[i], | ||
265 | pRawDataSet[idxL].vpdPdg[i], | ||
266 | AR5416_EEP4K_PD_GAIN_ICEPTS, | ||
267 | vpdTableI[i]); | ||
268 | } | ||
269 | } else { | ||
270 | for (i = 0; i < numXpdGains; i++) { | ||
271 | pVpdL = pRawDataSet[idxL].vpdPdg[i]; | ||
272 | pPwrL = pRawDataSet[idxL].pwrPdg[i]; | ||
273 | pVpdR = pRawDataSet[idxR].vpdPdg[i]; | ||
274 | pPwrR = pRawDataSet[idxR].pwrPdg[i]; | ||
275 | |||
276 | minPwrT4[i] = max(pPwrL[0], pPwrR[0]); | ||
277 | |||
278 | maxPwrT4[i] = | ||
279 | min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1], | ||
280 | pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); | ||
281 | |||
282 | |||
283 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
284 | pPwrL, pVpdL, | ||
285 | AR5416_EEP4K_PD_GAIN_ICEPTS, | ||
286 | vpdTableL[i]); | ||
287 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
288 | pPwrR, pVpdR, | ||
289 | AR5416_EEP4K_PD_GAIN_ICEPTS, | ||
290 | vpdTableR[i]); | ||
291 | |||
292 | for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { | ||
293 | vpdTableI[i][j] = | ||
294 | (u8)(ath9k_hw_interpolate((u16) | ||
295 | FREQ2FBIN(centers. | ||
296 | synth_center, | ||
297 | IS_CHAN_2GHZ | ||
298 | (chan)), | ||
299 | bChans[idxL], bChans[idxR], | ||
300 | vpdTableL[i][j], vpdTableR[i][j])); | ||
301 | } | ||
302 | } | ||
303 | } | ||
304 | |||
305 | *pMinCalPower = (int16_t)(minPwrT4[0] / 2); | ||
306 | |||
307 | k = 0; | ||
308 | |||
309 | for (i = 0; i < numXpdGains; i++) { | ||
310 | if (i == (numXpdGains - 1)) | ||
311 | pPdGainBoundaries[i] = | ||
312 | (u16)(maxPwrT4[i] / 2); | ||
313 | else | ||
314 | pPdGainBoundaries[i] = | ||
315 | (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); | ||
316 | |||
317 | pPdGainBoundaries[i] = | ||
318 | min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); | ||
319 | |||
320 | if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { | ||
321 | minDelta = pPdGainBoundaries[0] - 23; | ||
322 | pPdGainBoundaries[0] = 23; | ||
323 | } else { | ||
324 | minDelta = 0; | ||
325 | } | ||
326 | |||
327 | if (i == 0) { | ||
328 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
329 | ss = (int16_t)(0 - (minPwrT4[i] / 2)); | ||
330 | else | ||
331 | ss = 0; | ||
332 | } else { | ||
333 | ss = (int16_t)((pPdGainBoundaries[i - 1] - | ||
334 | (minPwrT4[i] / 2)) - | ||
335 | tPdGainOverlap + 1 + minDelta); | ||
336 | } | ||
337 | vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); | ||
338 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
339 | |||
340 | while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
341 | tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); | ||
342 | pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); | ||
343 | ss++; | ||
344 | } | ||
345 | |||
346 | sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); | ||
347 | tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - | ||
348 | (minPwrT4[i] / 2)); | ||
349 | maxIndex = (tgtIndex < sizeCurrVpdTable) ? | ||
350 | tgtIndex : sizeCurrVpdTable; | ||
351 | |||
352 | while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) | ||
353 | pPDADCValues[k++] = vpdTableI[i][ss++]; | ||
354 | |||
355 | vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - | ||
356 | vpdTableI[i][sizeCurrVpdTable - 2]); | ||
357 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
358 | |||
359 | if (tgtIndex >= maxIndex) { | ||
360 | while ((ss <= tgtIndex) && | ||
361 | (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
362 | tmpVal = (int16_t) TMP_VAL_VPD_TABLE; | ||
363 | pPDADCValues[k++] = (u8)((tmpVal > 255) ? | ||
364 | 255 : tmpVal); | ||
365 | ss++; | ||
366 | } | ||
367 | } | ||
368 | } | ||
369 | |||
370 | while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { | ||
371 | pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; | ||
372 | i++; | ||
373 | } | ||
374 | |||
375 | while (k < AR5416_NUM_PDADC_VALUES) { | ||
376 | pPDADCValues[k] = pPDADCValues[k - 1]; | ||
377 | k++; | ||
378 | } | ||
379 | |||
380 | return; | ||
381 | #undef TMP_VAL_VPD_TABLE | ||
382 | } | ||
383 | |||
384 | static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, | ||
385 | struct ath9k_channel *chan, | ||
386 | int16_t *pTxPowerIndexOffset) | ||
387 | { | ||
388 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | ||
389 | struct cal_data_per_freq_4k *pRawDataset; | ||
390 | u8 *pCalBChans = NULL; | ||
391 | u16 pdGainOverlap_t2; | ||
392 | static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; | ||
393 | u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK]; | ||
394 | u16 numPiers, i, j; | ||
395 | int16_t tMinCalPower; | ||
396 | u16 numXpdGain, xpdMask; | ||
397 | u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 }; | ||
398 | u32 reg32, regOffset, regChainOffset; | ||
399 | |||
400 | xpdMask = pEepData->modalHeader.xpdGain; | ||
401 | |||
402 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
403 | AR5416_EEP_MINOR_VER_2) { | ||
404 | pdGainOverlap_t2 = | ||
405 | pEepData->modalHeader.pdGainOverlap; | ||
406 | } else { | ||
407 | pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), | ||
408 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); | ||
409 | } | ||
410 | |||
411 | pCalBChans = pEepData->calFreqPier2G; | ||
412 | numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS; | ||
413 | |||
414 | numXpdGain = 0; | ||
415 | |||
416 | for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) { | ||
417 | if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) { | ||
418 | if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS) | ||
419 | break; | ||
420 | xpdGainValues[numXpdGain] = | ||
421 | (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i); | ||
422 | numXpdGain++; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, | ||
427 | (numXpdGain - 1) & 0x3); | ||
428 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, | ||
429 | xpdGainValues[0]); | ||
430 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, | ||
431 | xpdGainValues[1]); | ||
432 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0); | ||
433 | |||
434 | for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { | ||
435 | if (AR_SREV_5416_20_OR_LATER(ah) && | ||
436 | (ah->rxchainmask == 5 || ah->txchainmask == 5) && | ||
437 | (i != 0)) { | ||
438 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; | ||
439 | } else | ||
440 | regChainOffset = i * 0x1000; | ||
441 | |||
442 | if (pEepData->baseEepHeader.txMask & (1 << i)) { | ||
443 | pRawDataset = pEepData->calPierData2G[i]; | ||
444 | |||
445 | ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan, | ||
446 | pRawDataset, pCalBChans, | ||
447 | numPiers, pdGainOverlap_t2, | ||
448 | &tMinCalPower, gainBoundaries, | ||
449 | pdadcValues, numXpdGain); | ||
450 | |||
451 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { | ||
452 | REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, | ||
453 | SM(pdGainOverlap_t2, | ||
454 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | ||
455 | | SM(gainBoundaries[0], | ||
456 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | ||
457 | | SM(gainBoundaries[1], | ||
458 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | ||
459 | | SM(gainBoundaries[2], | ||
460 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | ||
461 | | SM(gainBoundaries[3], | ||
462 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); | ||
463 | } | ||
464 | |||
465 | regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; | ||
466 | for (j = 0; j < 32; j++) { | ||
467 | reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | | ||
468 | ((pdadcValues[4 * j + 1] & 0xFF) << 8) | | ||
469 | ((pdadcValues[4 * j + 2] & 0xFF) << 16)| | ||
470 | ((pdadcValues[4 * j + 3] & 0xFF) << 24); | ||
471 | REG_WRITE(ah, regOffset, reg32); | ||
472 | |||
473 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
474 | "PDADC (%d,%4x): %4.4x %8.8x\n", | ||
475 | i, regChainOffset, regOffset, | ||
476 | reg32); | ||
477 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
478 | "PDADC: Chain %d | " | ||
479 | "PDADC %3d Value %3d | " | ||
480 | "PDADC %3d Value %3d | " | ||
481 | "PDADC %3d Value %3d | " | ||
482 | "PDADC %3d Value %3d |\n", | ||
483 | i, 4 * j, pdadcValues[4 * j], | ||
484 | 4 * j + 1, pdadcValues[4 * j + 1], | ||
485 | 4 * j + 2, pdadcValues[4 * j + 2], | ||
486 | 4 * j + 3, | ||
487 | pdadcValues[4 * j + 3]); | ||
488 | |||
489 | regOffset += 4; | ||
490 | } | ||
491 | } | ||
492 | } | ||
493 | |||
494 | *pTxPowerIndexOffset = 0; | ||
495 | } | ||
496 | |||
497 | static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, | ||
498 | struct ath9k_channel *chan, | ||
499 | int16_t *ratesArray, | ||
500 | u16 cfgCtl, | ||
501 | u16 AntennaReduction, | ||
502 | u16 twiceMaxRegulatoryPower, | ||
503 | u16 powerLimit) | ||
504 | { | ||
505 | #define CMP_TEST_GRP \ | ||
506 | (((cfgCtl & ~CTL_MODE_M)| (pCtlMode[ctlMode] & CTL_MODE_M)) == \ | ||
507 | pEepData->ctlIndex[i]) \ | ||
508 | || (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \ | ||
509 | ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL)) | ||
510 | |||
511 | int i; | ||
512 | int16_t twiceLargestAntenna; | ||
513 | u16 twiceMinEdgePower; | ||
514 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
515 | u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; | ||
516 | u16 numCtlModes, *pCtlMode, ctlMode, freq; | ||
517 | struct chan_centers centers; | ||
518 | struct cal_ctl_data_4k *rep; | ||
519 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | ||
520 | static const u16 tpScaleReductionTable[5] = | ||
521 | { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; | ||
522 | struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { | ||
523 | 0, { 0, 0, 0, 0} | ||
524 | }; | ||
525 | struct cal_target_power_leg targetPowerOfdmExt = { | ||
526 | 0, { 0, 0, 0, 0} }, targetPowerCckExt = { | ||
527 | 0, { 0, 0, 0, 0 } | ||
528 | }; | ||
529 | struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { | ||
530 | 0, {0, 0, 0, 0} | ||
531 | }; | ||
532 | u16 ctlModesFor11g[] = | ||
533 | { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, | ||
534 | CTL_2GHT40 | ||
535 | }; | ||
536 | |||
537 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
538 | |||
539 | twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; | ||
540 | twiceLargestAntenna = (int16_t)min(AntennaReduction - | ||
541 | twiceLargestAntenna, 0); | ||
542 | |||
543 | maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; | ||
544 | if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { | ||
545 | maxRegAllowedPower -= | ||
546 | (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); | ||
547 | } | ||
548 | |||
549 | scaledPower = min(powerLimit, maxRegAllowedPower); | ||
550 | scaledPower = max((u16)0, scaledPower); | ||
551 | |||
552 | numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; | ||
553 | pCtlMode = ctlModesFor11g; | ||
554 | |||
555 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
556 | pEepData->calTargetPowerCck, | ||
557 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
558 | &targetPowerCck, 4, false); | ||
559 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
560 | pEepData->calTargetPower2G, | ||
561 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
562 | &targetPowerOfdm, 4, false); | ||
563 | ath9k_hw_get_target_powers(ah, chan, | ||
564 | pEepData->calTargetPower2GHT20, | ||
565 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
566 | &targetPowerHt20, 8, false); | ||
567 | |||
568 | if (IS_CHAN_HT40(chan)) { | ||
569 | numCtlModes = ARRAY_SIZE(ctlModesFor11g); | ||
570 | ath9k_hw_get_target_powers(ah, chan, | ||
571 | pEepData->calTargetPower2GHT40, | ||
572 | AR5416_NUM_2G_40_TARGET_POWERS, | ||
573 | &targetPowerHt40, 8, true); | ||
574 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
575 | pEepData->calTargetPowerCck, | ||
576 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
577 | &targetPowerCckExt, 4, true); | ||
578 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
579 | pEepData->calTargetPower2G, | ||
580 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
581 | &targetPowerOfdmExt, 4, true); | ||
582 | } | ||
583 | |||
584 | for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { | ||
585 | bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || | ||
586 | (pCtlMode[ctlMode] == CTL_2GHT40); | ||
587 | |||
588 | if (isHt40CtlMode) | ||
589 | freq = centers.synth_center; | ||
590 | else if (pCtlMode[ctlMode] & EXT_ADDITIVE) | ||
591 | freq = centers.ext_center; | ||
592 | else | ||
593 | freq = centers.ctl_center; | ||
594 | |||
595 | if (ah->eep_ops->get_eeprom_ver(ah) == 14 && | ||
596 | ah->eep_ops->get_eeprom_rev(ah) <= 2) | ||
597 | twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
598 | |||
599 | for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && | ||
600 | pEepData->ctlIndex[i]; i++) { | ||
601 | |||
602 | if (CMP_TEST_GRP) { | ||
603 | rep = &(pEepData->ctlData[i]); | ||
604 | |||
605 | twiceMinEdgePower = ath9k_hw_get_max_edge_power( | ||
606 | freq, | ||
607 | rep->ctlEdges[ | ||
608 | ar5416_get_ntxchains(ah->txchainmask) - 1], | ||
609 | IS_CHAN_2GHZ(chan), | ||
610 | AR5416_EEP4K_NUM_BAND_EDGES); | ||
611 | |||
612 | if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { | ||
613 | twiceMaxEdgePower = | ||
614 | min(twiceMaxEdgePower, | ||
615 | twiceMinEdgePower); | ||
616 | } else { | ||
617 | twiceMaxEdgePower = twiceMinEdgePower; | ||
618 | break; | ||
619 | } | ||
620 | } | ||
621 | } | ||
622 | |||
623 | minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); | ||
624 | |||
625 | switch (pCtlMode[ctlMode]) { | ||
626 | case CTL_11B: | ||
627 | for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { | ||
628 | targetPowerCck.tPow2x[i] = | ||
629 | min((u16)targetPowerCck.tPow2x[i], | ||
630 | minCtlPower); | ||
631 | } | ||
632 | break; | ||
633 | case CTL_11G: | ||
634 | for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { | ||
635 | targetPowerOfdm.tPow2x[i] = | ||
636 | min((u16)targetPowerOfdm.tPow2x[i], | ||
637 | minCtlPower); | ||
638 | } | ||
639 | break; | ||
640 | case CTL_2GHT20: | ||
641 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { | ||
642 | targetPowerHt20.tPow2x[i] = | ||
643 | min((u16)targetPowerHt20.tPow2x[i], | ||
644 | minCtlPower); | ||
645 | } | ||
646 | break; | ||
647 | case CTL_11B_EXT: | ||
648 | targetPowerCckExt.tPow2x[0] = | ||
649 | min((u16)targetPowerCckExt.tPow2x[0], | ||
650 | minCtlPower); | ||
651 | break; | ||
652 | case CTL_11G_EXT: | ||
653 | targetPowerOfdmExt.tPow2x[0] = | ||
654 | min((u16)targetPowerOfdmExt.tPow2x[0], | ||
655 | minCtlPower); | ||
656 | break; | ||
657 | case CTL_2GHT40: | ||
658 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
659 | targetPowerHt40.tPow2x[i] = | ||
660 | min((u16)targetPowerHt40.tPow2x[i], | ||
661 | minCtlPower); | ||
662 | } | ||
663 | break; | ||
664 | default: | ||
665 | break; | ||
666 | } | ||
667 | } | ||
668 | |||
669 | ratesArray[rate6mb] = | ||
670 | ratesArray[rate9mb] = | ||
671 | ratesArray[rate12mb] = | ||
672 | ratesArray[rate18mb] = | ||
673 | ratesArray[rate24mb] = | ||
674 | targetPowerOfdm.tPow2x[0]; | ||
675 | |||
676 | ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; | ||
677 | ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; | ||
678 | ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; | ||
679 | ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; | ||
680 | |||
681 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) | ||
682 | ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; | ||
683 | |||
684 | ratesArray[rate1l] = targetPowerCck.tPow2x[0]; | ||
685 | ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; | ||
686 | ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; | ||
687 | ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; | ||
688 | |||
689 | if (IS_CHAN_HT40(chan)) { | ||
690 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
691 | ratesArray[rateHt40_0 + i] = | ||
692 | targetPowerHt40.tPow2x[i]; | ||
693 | } | ||
694 | ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; | ||
695 | ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; | ||
696 | ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; | ||
697 | ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; | ||
698 | } | ||
699 | |||
700 | #undef CMP_TEST_GRP | ||
701 | } | ||
702 | |||
703 | static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | ||
704 | struct ath9k_channel *chan, | ||
705 | u16 cfgCtl, | ||
706 | u8 twiceAntennaReduction, | ||
707 | u8 twiceMaxRegulatoryPower, | ||
708 | u8 powerLimit) | ||
709 | { | ||
710 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | ||
711 | struct modal_eep_4k_header *pModal = &pEepData->modalHeader; | ||
712 | int16_t ratesArray[Ar5416RateSize]; | ||
713 | int16_t txPowerIndexOffset = 0; | ||
714 | u8 ht40PowerIncForPdadc = 2; | ||
715 | int i; | ||
716 | |||
717 | memset(ratesArray, 0, sizeof(ratesArray)); | ||
718 | |||
719 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
720 | AR5416_EEP_MINOR_VER_2) { | ||
721 | ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; | ||
722 | } | ||
723 | |||
724 | ath9k_hw_set_4k_power_per_rate_table(ah, chan, | ||
725 | &ratesArray[0], cfgCtl, | ||
726 | twiceAntennaReduction, | ||
727 | twiceMaxRegulatoryPower, | ||
728 | powerLimit); | ||
729 | |||
730 | ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); | ||
731 | |||
732 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | ||
733 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
734 | if (ratesArray[i] > AR5416_MAX_RATE_POWER) | ||
735 | ratesArray[i] = AR5416_MAX_RATE_POWER; | ||
736 | } | ||
737 | |||
738 | |||
739 | /* Update regulatory */ | ||
740 | |||
741 | i = rate6mb; | ||
742 | if (IS_CHAN_HT40(chan)) | ||
743 | i = rateHt40_0; | ||
744 | else if (IS_CHAN_HT20(chan)) | ||
745 | i = rateHt20_0; | ||
746 | |||
747 | ah->regulatory.max_power_level = ratesArray[i]; | ||
748 | |||
749 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
750 | for (i = 0; i < Ar5416RateSize; i++) | ||
751 | ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; | ||
752 | } | ||
753 | |||
754 | /* OFDM power per rate */ | ||
755 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, | ||
756 | ATH9K_POW_SM(ratesArray[rate18mb], 24) | ||
757 | | ATH9K_POW_SM(ratesArray[rate12mb], 16) | ||
758 | | ATH9K_POW_SM(ratesArray[rate9mb], 8) | ||
759 | | ATH9K_POW_SM(ratesArray[rate6mb], 0)); | ||
760 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, | ||
761 | ATH9K_POW_SM(ratesArray[rate54mb], 24) | ||
762 | | ATH9K_POW_SM(ratesArray[rate48mb], 16) | ||
763 | | ATH9K_POW_SM(ratesArray[rate36mb], 8) | ||
764 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); | ||
765 | |||
766 | /* CCK power per rate */ | ||
767 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
768 | ATH9K_POW_SM(ratesArray[rate2s], 24) | ||
769 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | ||
770 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
771 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | ||
772 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
773 | ATH9K_POW_SM(ratesArray[rate11s], 24) | ||
774 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | ||
775 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | ||
776 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | ||
777 | |||
778 | /* HT20 power per rate */ | ||
779 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, | ||
780 | ATH9K_POW_SM(ratesArray[rateHt20_3], 24) | ||
781 | | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) | ||
782 | | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) | ||
783 | | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); | ||
784 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, | ||
785 | ATH9K_POW_SM(ratesArray[rateHt20_7], 24) | ||
786 | | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) | ||
787 | | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) | ||
788 | | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); | ||
789 | |||
790 | /* HT40 power per rate */ | ||
791 | if (IS_CHAN_HT40(chan)) { | ||
792 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
793 | ATH9K_POW_SM(ratesArray[rateHt40_3] + | ||
794 | ht40PowerIncForPdadc, 24) | ||
795 | | ATH9K_POW_SM(ratesArray[rateHt40_2] + | ||
796 | ht40PowerIncForPdadc, 16) | ||
797 | | ATH9K_POW_SM(ratesArray[rateHt40_1] + | ||
798 | ht40PowerIncForPdadc, 8) | ||
799 | | ATH9K_POW_SM(ratesArray[rateHt40_0] + | ||
800 | ht40PowerIncForPdadc, 0)); | ||
801 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
802 | ATH9K_POW_SM(ratesArray[rateHt40_7] + | ||
803 | ht40PowerIncForPdadc, 24) | ||
804 | | ATH9K_POW_SM(ratesArray[rateHt40_6] + | ||
805 | ht40PowerIncForPdadc, 16) | ||
806 | | ATH9K_POW_SM(ratesArray[rateHt40_5] + | ||
807 | ht40PowerIncForPdadc, 8) | ||
808 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + | ||
809 | ht40PowerIncForPdadc, 0)); | ||
810 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
811 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
812 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ||
813 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
814 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | ||
815 | } | ||
816 | } | ||
817 | |||
818 | static void ath9k_hw_4k_set_addac(struct ath_hw *ah, | ||
819 | struct ath9k_channel *chan) | ||
820 | { | ||
821 | struct modal_eep_4k_header *pModal; | ||
822 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
823 | u8 biaslevel; | ||
824 | |||
825 | if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) | ||
826 | return; | ||
827 | |||
828 | if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) | ||
829 | return; | ||
830 | |||
831 | pModal = &eep->modalHeader; | ||
832 | |||
833 | if (pModal->xpaBiasLvl != 0xff) { | ||
834 | biaslevel = pModal->xpaBiasLvl; | ||
835 | INI_RA(&ah->iniAddac, 7, 1) = | ||
836 | (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; | ||
837 | } | ||
838 | } | ||
839 | |||
840 | static void ath9k_hw_4k_set_gain(struct ath_hw *ah, | ||
841 | struct modal_eep_4k_header *pModal, | ||
842 | struct ar5416_eeprom_4k *eep, | ||
843 | u8 txRxAttenLocal) | ||
844 | { | ||
845 | REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0, | ||
846 | pModal->antCtrlChain[0]); | ||
847 | |||
848 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), | ||
849 | (REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & | ||
850 | ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | | ||
851 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | | ||
852 | SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | | ||
853 | SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); | ||
854 | |||
855 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
856 | AR5416_EEP_MINOR_VER_3) { | ||
857 | txRxAttenLocal = pModal->txRxAttenCh[0]; | ||
858 | |||
859 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, | ||
860 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); | ||
861 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, | ||
862 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); | ||
863 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, | ||
864 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | ||
865 | pModal->xatten2Margin[0]); | ||
866 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, | ||
867 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); | ||
868 | |||
869 | /* Set the block 1 value to block 0 value */ | ||
870 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, | ||
871 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, | ||
872 | pModal->bswMargin[0]); | ||
873 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, | ||
874 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); | ||
875 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, | ||
876 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | ||
877 | pModal->xatten2Margin[0]); | ||
878 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, | ||
879 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, | ||
880 | pModal->xatten2Db[0]); | ||
881 | } | ||
882 | |||
883 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN, | ||
884 | AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); | ||
885 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN, | ||
886 | AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); | ||
887 | |||
888 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, | ||
889 | AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); | ||
890 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, | ||
891 | AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); | ||
892 | |||
893 | if (AR_SREV_9285_11(ah)) | ||
894 | REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); | ||
895 | } | ||
896 | |||
897 | /* | ||
898 | * Read EEPROM header info and program the device for correct operation | ||
899 | * given the channel value. | ||
900 | */ | ||
901 | static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, | ||
902 | struct ath9k_channel *chan) | ||
903 | { | ||
904 | struct modal_eep_4k_header *pModal; | ||
905 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
906 | u8 txRxAttenLocal; | ||
907 | u8 ob[5], db1[5], db2[5]; | ||
908 | u8 ant_div_control1, ant_div_control2; | ||
909 | u32 regVal; | ||
910 | |||
911 | pModal = &eep->modalHeader; | ||
912 | txRxAttenLocal = 23; | ||
913 | |||
914 | REG_WRITE(ah, AR_PHY_SWITCH_COM, | ||
915 | ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); | ||
916 | |||
917 | /* Single chain for 4K EEPROM*/ | ||
918 | ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal); | ||
919 | |||
920 | /* Initialize Ant Diversity settings from EEPROM */ | ||
921 | if (pModal->version >= 3) { | ||
922 | ant_div_control1 = pModal->antdiv_ctl1; | ||
923 | ant_div_control2 = pModal->antdiv_ctl2; | ||
924 | |||
925 | regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); | ||
926 | regVal &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL)); | ||
927 | |||
928 | regVal |= SM(ant_div_control1, | ||
929 | AR_PHY_9285_ANT_DIV_CTL); | ||
930 | regVal |= SM(ant_div_control2, | ||
931 | AR_PHY_9285_ANT_DIV_ALT_LNACONF); | ||
932 | regVal |= SM((ant_div_control2 >> 2), | ||
933 | AR_PHY_9285_ANT_DIV_MAIN_LNACONF); | ||
934 | regVal |= SM((ant_div_control1 >> 1), | ||
935 | AR_PHY_9285_ANT_DIV_ALT_GAINTB); | ||
936 | regVal |= SM((ant_div_control1 >> 2), | ||
937 | AR_PHY_9285_ANT_DIV_MAIN_GAINTB); | ||
938 | |||
939 | |||
940 | REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal); | ||
941 | regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); | ||
942 | regVal = REG_READ(ah, AR_PHY_CCK_DETECT); | ||
943 | regVal &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); | ||
944 | regVal |= SM((ant_div_control1 >> 3), | ||
945 | AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); | ||
946 | |||
947 | REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal); | ||
948 | regVal = REG_READ(ah, AR_PHY_CCK_DETECT); | ||
949 | } | ||
950 | |||
951 | if (pModal->version >= 2) { | ||
952 | ob[0] = pModal->ob_0; | ||
953 | ob[1] = pModal->ob_1; | ||
954 | ob[2] = pModal->ob_2; | ||
955 | ob[3] = pModal->ob_3; | ||
956 | ob[4] = pModal->ob_4; | ||
957 | |||
958 | db1[0] = pModal->db1_0; | ||
959 | db1[1] = pModal->db1_1; | ||
960 | db1[2] = pModal->db1_2; | ||
961 | db1[3] = pModal->db1_3; | ||
962 | db1[4] = pModal->db1_4; | ||
963 | |||
964 | db2[0] = pModal->db2_0; | ||
965 | db2[1] = pModal->db2_1; | ||
966 | db2[2] = pModal->db2_2; | ||
967 | db2[3] = pModal->db2_3; | ||
968 | db2[4] = pModal->db2_4; | ||
969 | } else if (pModal->version == 1) { | ||
970 | ob[0] = pModal->ob_0; | ||
971 | ob[1] = ob[2] = ob[3] = ob[4] = pModal->ob_1; | ||
972 | db1[0] = pModal->db1_0; | ||
973 | db1[1] = db1[2] = db1[3] = db1[4] = pModal->db1_1; | ||
974 | db2[0] = pModal->db2_0; | ||
975 | db2[1] = db2[2] = db2[3] = db2[4] = pModal->db2_1; | ||
976 | } else { | ||
977 | int i; | ||
978 | |||
979 | for (i = 0; i < 5; i++) { | ||
980 | ob[i] = pModal->ob_0; | ||
981 | db1[i] = pModal->db1_0; | ||
982 | db2[i] = pModal->db1_0; | ||
983 | } | ||
984 | } | ||
985 | |||
986 | if (AR_SREV_9271(ah)) { | ||
987 | ath9k_hw_analog_shift_rmw(ah, | ||
988 | AR9285_AN_RF2G3, | ||
989 | AR9271_AN_RF2G3_OB_cck, | ||
990 | AR9271_AN_RF2G3_OB_cck_S, | ||
991 | ob[0]); | ||
992 | ath9k_hw_analog_shift_rmw(ah, | ||
993 | AR9285_AN_RF2G3, | ||
994 | AR9271_AN_RF2G3_OB_psk, | ||
995 | AR9271_AN_RF2G3_OB_psk_S, | ||
996 | ob[1]); | ||
997 | ath9k_hw_analog_shift_rmw(ah, | ||
998 | AR9285_AN_RF2G3, | ||
999 | AR9271_AN_RF2G3_OB_qam, | ||
1000 | AR9271_AN_RF2G3_OB_qam_S, | ||
1001 | ob[2]); | ||
1002 | ath9k_hw_analog_shift_rmw(ah, | ||
1003 | AR9285_AN_RF2G3, | ||
1004 | AR9271_AN_RF2G3_DB_1, | ||
1005 | AR9271_AN_RF2G3_DB_1_S, | ||
1006 | db1[0]); | ||
1007 | ath9k_hw_analog_shift_rmw(ah, | ||
1008 | AR9285_AN_RF2G4, | ||
1009 | AR9271_AN_RF2G4_DB_2, | ||
1010 | AR9271_AN_RF2G4_DB_2_S, | ||
1011 | db2[0]); | ||
1012 | } else { | ||
1013 | ath9k_hw_analog_shift_rmw(ah, | ||
1014 | AR9285_AN_RF2G3, | ||
1015 | AR9285_AN_RF2G3_OB_0, | ||
1016 | AR9285_AN_RF2G3_OB_0_S, | ||
1017 | ob[0]); | ||
1018 | ath9k_hw_analog_shift_rmw(ah, | ||
1019 | AR9285_AN_RF2G3, | ||
1020 | AR9285_AN_RF2G3_OB_1, | ||
1021 | AR9285_AN_RF2G3_OB_1_S, | ||
1022 | ob[1]); | ||
1023 | ath9k_hw_analog_shift_rmw(ah, | ||
1024 | AR9285_AN_RF2G3, | ||
1025 | AR9285_AN_RF2G3_OB_2, | ||
1026 | AR9285_AN_RF2G3_OB_2_S, | ||
1027 | ob[2]); | ||
1028 | ath9k_hw_analog_shift_rmw(ah, | ||
1029 | AR9285_AN_RF2G3, | ||
1030 | AR9285_AN_RF2G3_OB_3, | ||
1031 | AR9285_AN_RF2G3_OB_3_S, | ||
1032 | ob[3]); | ||
1033 | ath9k_hw_analog_shift_rmw(ah, | ||
1034 | AR9285_AN_RF2G3, | ||
1035 | AR9285_AN_RF2G3_OB_4, | ||
1036 | AR9285_AN_RF2G3_OB_4_S, | ||
1037 | ob[4]); | ||
1038 | |||
1039 | ath9k_hw_analog_shift_rmw(ah, | ||
1040 | AR9285_AN_RF2G3, | ||
1041 | AR9285_AN_RF2G3_DB1_0, | ||
1042 | AR9285_AN_RF2G3_DB1_0_S, | ||
1043 | db1[0]); | ||
1044 | ath9k_hw_analog_shift_rmw(ah, | ||
1045 | AR9285_AN_RF2G3, | ||
1046 | AR9285_AN_RF2G3_DB1_1, | ||
1047 | AR9285_AN_RF2G3_DB1_1_S, | ||
1048 | db1[1]); | ||
1049 | ath9k_hw_analog_shift_rmw(ah, | ||
1050 | AR9285_AN_RF2G3, | ||
1051 | AR9285_AN_RF2G3_DB1_2, | ||
1052 | AR9285_AN_RF2G3_DB1_2_S, | ||
1053 | db1[2]); | ||
1054 | ath9k_hw_analog_shift_rmw(ah, | ||
1055 | AR9285_AN_RF2G4, | ||
1056 | AR9285_AN_RF2G4_DB1_3, | ||
1057 | AR9285_AN_RF2G4_DB1_3_S, | ||
1058 | db1[3]); | ||
1059 | ath9k_hw_analog_shift_rmw(ah, | ||
1060 | AR9285_AN_RF2G4, | ||
1061 | AR9285_AN_RF2G4_DB1_4, | ||
1062 | AR9285_AN_RF2G4_DB1_4_S, db1[4]); | ||
1063 | |||
1064 | ath9k_hw_analog_shift_rmw(ah, | ||
1065 | AR9285_AN_RF2G4, | ||
1066 | AR9285_AN_RF2G4_DB2_0, | ||
1067 | AR9285_AN_RF2G4_DB2_0_S, | ||
1068 | db2[0]); | ||
1069 | ath9k_hw_analog_shift_rmw(ah, | ||
1070 | AR9285_AN_RF2G4, | ||
1071 | AR9285_AN_RF2G4_DB2_1, | ||
1072 | AR9285_AN_RF2G4_DB2_1_S, | ||
1073 | db2[1]); | ||
1074 | ath9k_hw_analog_shift_rmw(ah, | ||
1075 | AR9285_AN_RF2G4, | ||
1076 | AR9285_AN_RF2G4_DB2_2, | ||
1077 | AR9285_AN_RF2G4_DB2_2_S, | ||
1078 | db2[2]); | ||
1079 | ath9k_hw_analog_shift_rmw(ah, | ||
1080 | AR9285_AN_RF2G4, | ||
1081 | AR9285_AN_RF2G4_DB2_3, | ||
1082 | AR9285_AN_RF2G4_DB2_3_S, | ||
1083 | db2[3]); | ||
1084 | ath9k_hw_analog_shift_rmw(ah, | ||
1085 | AR9285_AN_RF2G4, | ||
1086 | AR9285_AN_RF2G4_DB2_4, | ||
1087 | AR9285_AN_RF2G4_DB2_4_S, | ||
1088 | db2[4]); | ||
1089 | } | ||
1090 | |||
1091 | |||
1092 | if (AR_SREV_9285_11(ah)) | ||
1093 | REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); | ||
1094 | |||
1095 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, | ||
1096 | pModal->switchSettling); | ||
1097 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, | ||
1098 | pModal->adcDesiredSize); | ||
1099 | |||
1100 | REG_WRITE(ah, AR_PHY_RF_CTL4, | ||
1101 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | | ||
1102 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | | ||
1103 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | | ||
1104 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); | ||
1105 | |||
1106 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, | ||
1107 | pModal->txEndToRxOn); | ||
1108 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, | ||
1109 | pModal->thresh62); | ||
1110 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, | ||
1111 | pModal->thresh62); | ||
1112 | |||
1113 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1114 | AR5416_EEP_MINOR_VER_2) { | ||
1115 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, | ||
1116 | pModal->txFrameToDataStart); | ||
1117 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, | ||
1118 | pModal->txFrameToPaOn); | ||
1119 | } | ||
1120 | |||
1121 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1122 | AR5416_EEP_MINOR_VER_3) { | ||
1123 | if (IS_CHAN_HT40(chan)) | ||
1124 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
1125 | AR_PHY_SETTLING_SWITCH, | ||
1126 | pModal->swSettleHt40); | ||
1127 | } | ||
1128 | } | ||
1129 | |||
1130 | static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah, | ||
1131 | struct ath9k_channel *chan) | ||
1132 | { | ||
1133 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
1134 | struct modal_eep_4k_header *pModal = &eep->modalHeader; | ||
1135 | |||
1136 | return pModal->antCtrlCommon & 0xFFFF; | ||
1137 | } | ||
1138 | |||
1139 | static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah, | ||
1140 | enum ieee80211_band freq_band) | ||
1141 | { | ||
1142 | return 1; | ||
1143 | } | ||
1144 | |||
1145 | static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) | ||
1146 | { | ||
1147 | #define EEP_MAP4K_SPURCHAN \ | ||
1148 | (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) | ||
1149 | |||
1150 | u16 spur_val = AR_NO_SPUR; | ||
1151 | |||
1152 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1153 | "Getting spur idx %d is2Ghz. %d val %x\n", | ||
1154 | i, is2GHz, ah->config.spurchans[i][is2GHz]); | ||
1155 | |||
1156 | switch (ah->config.spurmode) { | ||
1157 | case SPUR_DISABLE: | ||
1158 | break; | ||
1159 | case SPUR_ENABLE_IOCTL: | ||
1160 | spur_val = ah->config.spurchans[i][is2GHz]; | ||
1161 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1162 | "Getting spur val from new loc. %d\n", spur_val); | ||
1163 | break; | ||
1164 | case SPUR_ENABLE_EEPROM: | ||
1165 | spur_val = EEP_MAP4K_SPURCHAN; | ||
1166 | break; | ||
1167 | } | ||
1168 | |||
1169 | return spur_val; | ||
1170 | |||
1171 | #undef EEP_MAP4K_SPURCHAN | ||
1172 | } | ||
1173 | |||
1174 | const struct eeprom_ops eep_4k_ops = { | ||
1175 | .check_eeprom = ath9k_hw_4k_check_eeprom, | ||
1176 | .get_eeprom = ath9k_hw_4k_get_eeprom, | ||
1177 | .fill_eeprom = ath9k_hw_4k_fill_eeprom, | ||
1178 | .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, | ||
1179 | .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, | ||
1180 | .get_num_ant_config = ath9k_hw_4k_get_num_ant_config, | ||
1181 | .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg, | ||
1182 | .set_board_values = ath9k_hw_4k_set_board_values, | ||
1183 | .set_addac = ath9k_hw_4k_set_addac, | ||
1184 | .set_txpower = ath9k_hw_4k_set_txpower, | ||
1185 | .get_spur_channel = ath9k_hw_4k_get_spur_channel | ||
1186 | }; | ||
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c new file mode 100644 index 000000000000..aeb7f484b6e1 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c | |||
@@ -0,0 +1,1183 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008-2009 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "ath9k.h" | ||
18 | |||
19 | static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) | ||
20 | { | ||
21 | return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF; | ||
22 | } | ||
23 | |||
24 | static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah) | ||
25 | { | ||
26 | return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF; | ||
27 | } | ||
28 | |||
29 | static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) | ||
30 | { | ||
31 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
32 | u16 *eep_data; | ||
33 | int addr, eep_start_loc = AR9287_EEP_START_LOC; | ||
34 | eep_data = (u16 *)eep; | ||
35 | |||
36 | if (!ath9k_hw_use_flash(ah)) { | ||
37 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
38 | "Reading from EEPROM, not flash\n"); | ||
39 | } | ||
40 | |||
41 | for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); | ||
42 | addr++) { | ||
43 | if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { | ||
44 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
45 | "Unable to read eeprom region \n"); | ||
46 | return false; | ||
47 | } | ||
48 | eep_data++; | ||
49 | } | ||
50 | return true; | ||
51 | } | ||
52 | |||
53 | static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) | ||
54 | { | ||
55 | u32 sum = 0, el, integer; | ||
56 | u16 temp, word, magic, magic2, *eepdata; | ||
57 | int i, addr; | ||
58 | bool need_swap = false; | ||
59 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
60 | |||
61 | if (!ath9k_hw_use_flash(ah)) { | ||
62 | if (!ath9k_hw_nvram_read | ||
63 | (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { | ||
64 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
65 | "Reading Magic # failed\n"); | ||
66 | return false; | ||
67 | } | ||
68 | |||
69 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
70 | "Read Magic = 0x%04X\n", magic); | ||
71 | if (magic != AR5416_EEPROM_MAGIC) { | ||
72 | magic2 = swab16(magic); | ||
73 | |||
74 | if (magic2 == AR5416_EEPROM_MAGIC) { | ||
75 | need_swap = true; | ||
76 | eepdata = (u16 *)(&ah->eeprom); | ||
77 | |||
78 | for (addr = 0; | ||
79 | addr < sizeof(struct ar9287_eeprom) / sizeof(u16); | ||
80 | addr++) { | ||
81 | temp = swab16(*eepdata); | ||
82 | *eepdata = temp; | ||
83 | eepdata++; | ||
84 | } | ||
85 | } else { | ||
86 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
87 | "Invalid EEPROM Magic. " | ||
88 | "endianness mismatch.\n"); | ||
89 | return -EINVAL; | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? | ||
94 | "True" : "False"); | ||
95 | |||
96 | if (need_swap) | ||
97 | el = swab16(ah->eeprom.map9287.baseEepHeader.length); | ||
98 | else | ||
99 | el = ah->eeprom.map9287.baseEepHeader.length; | ||
100 | |||
101 | if (el > sizeof(struct ar9287_eeprom)) | ||
102 | el = sizeof(struct ar9287_eeprom) / sizeof(u16); | ||
103 | else | ||
104 | el = el / sizeof(u16); | ||
105 | |||
106 | eepdata = (u16 *)(&ah->eeprom); | ||
107 | for (i = 0; i < el; i++) | ||
108 | sum ^= *eepdata++; | ||
109 | |||
110 | if (need_swap) { | ||
111 | word = swab16(eep->baseEepHeader.length); | ||
112 | eep->baseEepHeader.length = word; | ||
113 | |||
114 | word = swab16(eep->baseEepHeader.checksum); | ||
115 | eep->baseEepHeader.checksum = word; | ||
116 | |||
117 | word = swab16(eep->baseEepHeader.version); | ||
118 | eep->baseEepHeader.version = word; | ||
119 | |||
120 | word = swab16(eep->baseEepHeader.regDmn[0]); | ||
121 | eep->baseEepHeader.regDmn[0] = word; | ||
122 | |||
123 | word = swab16(eep->baseEepHeader.regDmn[1]); | ||
124 | eep->baseEepHeader.regDmn[1] = word; | ||
125 | |||
126 | word = swab16(eep->baseEepHeader.rfSilent); | ||
127 | eep->baseEepHeader.rfSilent = word; | ||
128 | |||
129 | word = swab16(eep->baseEepHeader.blueToothOptions); | ||
130 | eep->baseEepHeader.blueToothOptions = word; | ||
131 | |||
132 | word = swab16(eep->baseEepHeader.deviceCap); | ||
133 | eep->baseEepHeader.deviceCap = word; | ||
134 | |||
135 | integer = swab32(eep->modalHeader.antCtrlCommon); | ||
136 | eep->modalHeader.antCtrlCommon = integer; | ||
137 | |||
138 | for (i = 0; i < AR9287_MAX_CHAINS; i++) { | ||
139 | integer = swab32(eep->modalHeader.antCtrlChain[i]); | ||
140 | eep->modalHeader.antCtrlChain[i] = integer; | ||
141 | } | ||
142 | |||
143 | for (i = 0; i < AR9287_EEPROM_MODAL_SPURS; i++) { | ||
144 | word = swab16(eep->modalHeader.spurChans[i].spurChan); | ||
145 | eep->modalHeader.spurChans[i].spurChan = word; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER | ||
150 | || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { | ||
151 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
152 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", | ||
153 | sum, ah->eep_ops->get_eeprom_ver(ah)); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, | ||
161 | enum eeprom_param param) | ||
162 | { | ||
163 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
164 | struct modal_eep_ar9287_header *pModal = &eep->modalHeader; | ||
165 | struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; | ||
166 | u16 ver_minor; | ||
167 | |||
168 | ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK; | ||
169 | switch (param) { | ||
170 | case EEP_NFTHRESH_2: | ||
171 | return pModal->noiseFloorThreshCh[0]; | ||
172 | case AR_EEPROM_MAC(0): | ||
173 | return pBase->macAddr[0] << 8 | pBase->macAddr[1]; | ||
174 | case AR_EEPROM_MAC(1): | ||
175 | return pBase->macAddr[2] << 8 | pBase->macAddr[3]; | ||
176 | case AR_EEPROM_MAC(2): | ||
177 | return pBase->macAddr[4] << 8 | pBase->macAddr[5]; | ||
178 | case EEP_REG_0: | ||
179 | return pBase->regDmn[0]; | ||
180 | case EEP_REG_1: | ||
181 | return pBase->regDmn[1]; | ||
182 | case EEP_OP_CAP: | ||
183 | return pBase->deviceCap; | ||
184 | case EEP_OP_MODE: | ||
185 | return pBase->opCapFlags; | ||
186 | case EEP_RF_SILENT: | ||
187 | return pBase->rfSilent; | ||
188 | case EEP_MINOR_REV: | ||
189 | return ver_minor; | ||
190 | case EEP_TX_MASK: | ||
191 | return pBase->txMask; | ||
192 | case EEP_RX_MASK: | ||
193 | return pBase->rxMask; | ||
194 | case EEP_DEV_TYPE: | ||
195 | return pBase->deviceType; | ||
196 | case EEP_OL_PWRCTRL: | ||
197 | return pBase->openLoopPwrCntl; | ||
198 | case EEP_TEMPSENSE_SLOPE: | ||
199 | if (ver_minor >= AR9287_EEP_MINOR_VER_2) | ||
200 | return pBase->tempSensSlope; | ||
201 | else | ||
202 | return 0; | ||
203 | case EEP_TEMPSENSE_SLOPE_PAL_ON: | ||
204 | if (ver_minor >= AR9287_EEP_MINOR_VER_3) | ||
205 | return pBase->tempSensSlopePalOn; | ||
206 | else | ||
207 | return 0; | ||
208 | default: | ||
209 | return 0; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | |||
214 | static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, | ||
215 | struct ath9k_channel *chan, | ||
216 | struct cal_data_per_freq_ar9287 *pRawDataSet, | ||
217 | u8 *bChans, u16 availPiers, | ||
218 | u16 tPdGainOverlap, int16_t *pMinCalPower, | ||
219 | u16 *pPdGainBoundaries, u8 *pPDADCValues, | ||
220 | u16 numXpdGains) | ||
221 | { | ||
222 | #define TMP_VAL_VPD_TABLE \ | ||
223 | ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); | ||
224 | |||
225 | int i, j, k; | ||
226 | int16_t ss; | ||
227 | u16 idxL = 0, idxR = 0, numPiers; | ||
228 | u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; | ||
229 | u8 minPwrT4[AR9287_NUM_PD_GAINS]; | ||
230 | u8 maxPwrT4[AR9287_NUM_PD_GAINS]; | ||
231 | int16_t vpdStep; | ||
232 | int16_t tmpVal; | ||
233 | u16 sizeCurrVpdTable, maxIndex, tgtIndex; | ||
234 | bool match; | ||
235 | int16_t minDelta = 0; | ||
236 | struct chan_centers centers; | ||
237 | static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] | ||
238 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
239 | static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] | ||
240 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
241 | static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] | ||
242 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
243 | |||
244 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
245 | |||
246 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
247 | if (bChans[numPiers] == AR9287_BCHAN_UNUSED) | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | match = ath9k_hw_get_lower_upper_index( | ||
252 | (u8)FREQ2FBIN(centers.synth_center, | ||
253 | IS_CHAN_2GHZ(chan)), bChans, numPiers, | ||
254 | &idxL, &idxR); | ||
255 | |||
256 | if (match) { | ||
257 | for (i = 0; i < numXpdGains; i++) { | ||
258 | minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; | ||
259 | maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; | ||
260 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
261 | pRawDataSet[idxL].pwrPdg[i], | ||
262 | pRawDataSet[idxL].vpdPdg[i], | ||
263 | AR9287_PD_GAIN_ICEPTS, vpdTableI[i]); | ||
264 | } | ||
265 | } else { | ||
266 | for (i = 0; i < numXpdGains; i++) { | ||
267 | pVpdL = pRawDataSet[idxL].vpdPdg[i]; | ||
268 | pPwrL = pRawDataSet[idxL].pwrPdg[i]; | ||
269 | pVpdR = pRawDataSet[idxR].vpdPdg[i]; | ||
270 | pPwrR = pRawDataSet[idxR].pwrPdg[i]; | ||
271 | |||
272 | minPwrT4[i] = max(pPwrL[0], pPwrR[0]); | ||
273 | |||
274 | maxPwrT4[i] = | ||
275 | min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1], | ||
276 | pPwrR[AR9287_PD_GAIN_ICEPTS - 1]); | ||
277 | |||
278 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
279 | pPwrL, pVpdL, | ||
280 | AR9287_PD_GAIN_ICEPTS, | ||
281 | vpdTableL[i]); | ||
282 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
283 | pPwrR, pVpdR, | ||
284 | AR9287_PD_GAIN_ICEPTS, | ||
285 | vpdTableR[i]); | ||
286 | |||
287 | for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { | ||
288 | vpdTableI[i][j] = | ||
289 | (u8)(ath9k_hw_interpolate((u16) | ||
290 | FREQ2FBIN(centers. synth_center, | ||
291 | IS_CHAN_2GHZ(chan)), | ||
292 | bChans[idxL], bChans[idxR], | ||
293 | vpdTableL[i][j], vpdTableR[i][j])); | ||
294 | } | ||
295 | } | ||
296 | } | ||
297 | *pMinCalPower = (int16_t)(minPwrT4[0] / 2); | ||
298 | |||
299 | k = 0; | ||
300 | for (i = 0; i < numXpdGains; i++) { | ||
301 | if (i == (numXpdGains - 1)) | ||
302 | pPdGainBoundaries[i] = (u16)(maxPwrT4[i] / 2); | ||
303 | else | ||
304 | pPdGainBoundaries[i] = (u16)((maxPwrT4[i] + | ||
305 | minPwrT4[i+1]) / 4); | ||
306 | |||
307 | pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER, | ||
308 | pPdGainBoundaries[i]); | ||
309 | |||
310 | |||
311 | if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { | ||
312 | minDelta = pPdGainBoundaries[0] - 23; | ||
313 | pPdGainBoundaries[0] = 23; | ||
314 | } else | ||
315 | minDelta = 0; | ||
316 | |||
317 | if (i == 0) { | ||
318 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
319 | ss = (int16_t)(0 - (minPwrT4[i] / 2)); | ||
320 | else | ||
321 | ss = 0; | ||
322 | } else | ||
323 | ss = (int16_t)((pPdGainBoundaries[i-1] - | ||
324 | (minPwrT4[i] / 2)) - | ||
325 | tPdGainOverlap + 1 + minDelta); | ||
326 | |||
327 | vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); | ||
328 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
329 | while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) { | ||
330 | tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); | ||
331 | pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); | ||
332 | ss++; | ||
333 | } | ||
334 | |||
335 | sizeCurrVpdTable = (u8)((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); | ||
336 | tgtIndex = (u8)(pPdGainBoundaries[i] + | ||
337 | tPdGainOverlap - (minPwrT4[i] / 2)); | ||
338 | maxIndex = (tgtIndex < sizeCurrVpdTable) ? | ||
339 | tgtIndex : sizeCurrVpdTable; | ||
340 | |||
341 | while ((ss < maxIndex) && (k < (AR9287_NUM_PDADC_VALUES - 1))) | ||
342 | pPDADCValues[k++] = vpdTableI[i][ss++]; | ||
343 | |||
344 | vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - | ||
345 | vpdTableI[i][sizeCurrVpdTable - 2]); | ||
346 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
347 | if (tgtIndex > maxIndex) { | ||
348 | while ((ss <= tgtIndex) && | ||
349 | (k < (AR9287_NUM_PDADC_VALUES - 1))) { | ||
350 | tmpVal = (int16_t) TMP_VAL_VPD_TABLE; | ||
351 | pPDADCValues[k++] = (u8)((tmpVal > 255) ? | ||
352 | 255 : tmpVal); | ||
353 | ss++; | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | |||
358 | while (i < AR9287_PD_GAINS_IN_MASK) { | ||
359 | pPdGainBoundaries[i] = pPdGainBoundaries[i-1]; | ||
360 | i++; | ||
361 | } | ||
362 | |||
363 | while (k < AR9287_NUM_PDADC_VALUES) { | ||
364 | pPDADCValues[k] = pPDADCValues[k-1]; | ||
365 | k++; | ||
366 | } | ||
367 | |||
368 | #undef TMP_VAL_VPD_TABLE | ||
369 | } | ||
370 | |||
371 | static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, | ||
372 | struct ath9k_channel *chan, | ||
373 | struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, | ||
374 | u8 *pCalChans, u16 availPiers, | ||
375 | int8_t *pPwr) | ||
376 | { | ||
377 | u8 pcdac, i = 0; | ||
378 | u16 idxL = 0, idxR = 0, numPiers; | ||
379 | bool match; | ||
380 | struct chan_centers centers; | ||
381 | |||
382 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
383 | |||
384 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
385 | if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED) | ||
386 | break; | ||
387 | } | ||
388 | |||
389 | match = ath9k_hw_get_lower_upper_index( | ||
390 | (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), | ||
391 | pCalChans, numPiers, | ||
392 | &idxL, &idxR); | ||
393 | |||
394 | if (match) { | ||
395 | pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0]; | ||
396 | *pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0]; | ||
397 | } else { | ||
398 | pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0]; | ||
399 | *pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] + | ||
400 | pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; | ||
401 | } | ||
402 | |||
403 | while ((pcdac > ah->originalGain[i]) && | ||
404 | (i < (AR9280_TX_GAIN_TABLE_SIZE - 1))) | ||
405 | i++; | ||
406 | } | ||
407 | |||
408 | static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, | ||
409 | int32_t txPower, u16 chain) | ||
410 | { | ||
411 | u32 tmpVal; | ||
412 | u32 a; | ||
413 | |||
414 | tmpVal = REG_READ(ah, 0xa270); | ||
415 | tmpVal = tmpVal & 0xFCFFFFFF; | ||
416 | tmpVal = tmpVal | (0x3 << 24); | ||
417 | REG_WRITE(ah, 0xa270, tmpVal); | ||
418 | |||
419 | tmpVal = REG_READ(ah, 0xb270); | ||
420 | tmpVal = tmpVal & 0xFCFFFFFF; | ||
421 | tmpVal = tmpVal | (0x3 << 24); | ||
422 | REG_WRITE(ah, 0xb270, tmpVal); | ||
423 | |||
424 | if (chain == 0) { | ||
425 | tmpVal = REG_READ(ah, 0xa398); | ||
426 | tmpVal = tmpVal & 0xff00ffff; | ||
427 | a = (txPower)&0xff; | ||
428 | tmpVal = tmpVal | (a << 16); | ||
429 | REG_WRITE(ah, 0xa398, tmpVal); | ||
430 | } | ||
431 | |||
432 | if (chain == 1) { | ||
433 | tmpVal = REG_READ(ah, 0xb398); | ||
434 | tmpVal = tmpVal & 0xff00ffff; | ||
435 | a = (txPower)&0xff; | ||
436 | tmpVal = tmpVal | (a << 16); | ||
437 | REG_WRITE(ah, 0xb398, tmpVal); | ||
438 | } | ||
439 | } | ||
440 | |||
441 | static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, | ||
442 | struct ath9k_channel *chan, | ||
443 | int16_t *pTxPowerIndexOffset) | ||
444 | { | ||
445 | struct cal_data_per_freq_ar9287 *pRawDataset; | ||
446 | struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; | ||
447 | u8 *pCalBChans = NULL; | ||
448 | u16 pdGainOverlap_t2; | ||
449 | u8 pdadcValues[AR9287_NUM_PDADC_VALUES]; | ||
450 | u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK]; | ||
451 | u16 numPiers = 0, i, j; | ||
452 | int16_t tMinCalPower; | ||
453 | u16 numXpdGain, xpdMask; | ||
454 | u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0}; | ||
455 | u32 reg32, regOffset, regChainOffset; | ||
456 | int16_t modalIdx, diff = 0; | ||
457 | struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; | ||
458 | modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; | ||
459 | xpdMask = pEepData->modalHeader.xpdGain; | ||
460 | if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= | ||
461 | AR9287_EEP_MINOR_VER_2) | ||
462 | pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; | ||
463 | else | ||
464 | pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), | ||
465 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); | ||
466 | |||
467 | if (IS_CHAN_2GHZ(chan)) { | ||
468 | pCalBChans = pEepData->calFreqPier2G; | ||
469 | numPiers = AR9287_NUM_2G_CAL_PIERS; | ||
470 | if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { | ||
471 | pRawDatasetOpenLoop = | ||
472 | (struct cal_data_op_loop_ar9287 *) | ||
473 | pEepData->calPierData2G[0]; | ||
474 | ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; | ||
475 | } | ||
476 | } | ||
477 | |||
478 | numXpdGain = 0; | ||
479 | for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) { | ||
480 | if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) { | ||
481 | if (numXpdGain >= AR9287_NUM_PD_GAINS) | ||
482 | break; | ||
483 | xpdGainValues[numXpdGain] = | ||
484 | (u16)(AR9287_PD_GAINS_IN_MASK-i); | ||
485 | numXpdGain++; | ||
486 | } | ||
487 | } | ||
488 | |||
489 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, | ||
490 | (numXpdGain - 1) & 0x3); | ||
491 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, | ||
492 | xpdGainValues[0]); | ||
493 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, | ||
494 | xpdGainValues[1]); | ||
495 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, | ||
496 | xpdGainValues[2]); | ||
497 | |||
498 | for (i = 0; i < AR9287_MAX_CHAINS; i++) { | ||
499 | regChainOffset = i * 0x1000; | ||
500 | if (pEepData->baseEepHeader.txMask & (1 << i)) { | ||
501 | pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *) | ||
502 | pEepData->calPierData2G[i]; | ||
503 | if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { | ||
504 | int8_t txPower; | ||
505 | ar9287_eeprom_get_tx_gain_index(ah, chan, | ||
506 | pRawDatasetOpenLoop, | ||
507 | pCalBChans, numPiers, | ||
508 | &txPower); | ||
509 | ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i); | ||
510 | } else { | ||
511 | pRawDataset = | ||
512 | (struct cal_data_per_freq_ar9287 *) | ||
513 | pEepData->calPierData2G[i]; | ||
514 | ath9k_hw_get_AR9287_gain_boundaries_pdadcs( | ||
515 | ah, chan, pRawDataset, | ||
516 | pCalBChans, numPiers, | ||
517 | pdGainOverlap_t2, | ||
518 | &tMinCalPower, gainBoundaries, | ||
519 | pdadcValues, numXpdGain); | ||
520 | } | ||
521 | |||
522 | if (i == 0) { | ||
523 | if (!ath9k_hw_AR9287_get_eeprom( | ||
524 | ah, EEP_OL_PWRCTRL)) { | ||
525 | REG_WRITE(ah, AR_PHY_TPCRG5 + | ||
526 | regChainOffset, | ||
527 | SM(pdGainOverlap_t2, | ||
528 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | | ||
529 | SM(gainBoundaries[0], | ||
530 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | ||
531 | | SM(gainBoundaries[1], | ||
532 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | ||
533 | | SM(gainBoundaries[2], | ||
534 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | ||
535 | | SM(gainBoundaries[3], | ||
536 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); | ||
537 | } | ||
538 | } | ||
539 | |||
540 | if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB != | ||
541 | pEepData->baseEepHeader.pwrTableOffset) { | ||
542 | diff = (u16) | ||
543 | (pEepData->baseEepHeader.pwrTableOffset | ||
544 | - (int32_t)AR9287_PWR_TABLE_OFFSET_DB); | ||
545 | diff *= 2; | ||
546 | |||
547 | for (j = 0; | ||
548 | j < ((u16)AR9287_NUM_PDADC_VALUES-diff); | ||
549 | j++) | ||
550 | pdadcValues[j] = pdadcValues[j+diff]; | ||
551 | |||
552 | for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff); | ||
553 | j < AR9287_NUM_PDADC_VALUES; j++) | ||
554 | pdadcValues[j] = | ||
555 | pdadcValues[ | ||
556 | AR9287_NUM_PDADC_VALUES-diff]; | ||
557 | } | ||
558 | |||
559 | if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { | ||
560 | regOffset = AR_PHY_BASE + (672 << 2) + | ||
561 | regChainOffset; | ||
562 | for (j = 0; j < 32; j++) { | ||
563 | reg32 = ((pdadcValues[4*j + 0] | ||
564 | & 0xFF) << 0) | | ||
565 | ((pdadcValues[4*j + 1] | ||
566 | & 0xFF) << 8) | | ||
567 | ((pdadcValues[4*j + 2] | ||
568 | & 0xFF) << 16) | | ||
569 | ((pdadcValues[4*j + 3] | ||
570 | & 0xFF) << 24) ; | ||
571 | REG_WRITE(ah, regOffset, reg32); | ||
572 | |||
573 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
574 | "PDADC (%d,%4x): %4.4x %8.8x\n", | ||
575 | i, regChainOffset, regOffset, | ||
576 | reg32); | ||
577 | |||
578 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
579 | "PDADC: Chain %d | " | ||
580 | "PDADC %3d Value %3d | " | ||
581 | "PDADC %3d Value %3d | " | ||
582 | "PDADC %3d Value %3d | " | ||
583 | "PDADC %3d Value %3d |\n", | ||
584 | i, 4 * j, pdadcValues[4 * j], | ||
585 | 4 * j + 1, | ||
586 | pdadcValues[4 * j + 1], | ||
587 | 4 * j + 2, | ||
588 | pdadcValues[4 * j + 2], | ||
589 | 4 * j + 3, | ||
590 | pdadcValues[4 * j + 3]); | ||
591 | |||
592 | regOffset += 4; | ||
593 | } | ||
594 | } | ||
595 | } | ||
596 | } | ||
597 | |||
598 | *pTxPowerIndexOffset = 0; | ||
599 | } | ||
600 | |||
601 | static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, | ||
602 | struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, | ||
603 | u16 AntennaReduction, u16 twiceMaxRegulatoryPower, | ||
604 | u16 powerLimit) | ||
605 | { | ||
606 | #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 | ||
607 | #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 | ||
608 | |||
609 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
610 | static const u16 tpScaleReductionTable[5] = | ||
611 | { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; | ||
612 | int i; | ||
613 | int16_t twiceLargestAntenna; | ||
614 | struct cal_ctl_data_ar9287 *rep; | ||
615 | struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, | ||
616 | targetPowerCck = {0, {0, 0, 0, 0} }; | ||
617 | struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} }, | ||
618 | targetPowerCckExt = {0, {0, 0, 0, 0} }; | ||
619 | struct cal_target_power_ht targetPowerHt20, | ||
620 | targetPowerHt40 = {0, {0, 0, 0, 0} }; | ||
621 | u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; | ||
622 | u16 ctlModesFor11g[] = | ||
623 | {CTL_11B, CTL_11G, CTL_2GHT20, | ||
624 | CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40}; | ||
625 | u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq; | ||
626 | struct chan_centers centers; | ||
627 | int tx_chainmask; | ||
628 | u16 twiceMinEdgePower; | ||
629 | struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; | ||
630 | tx_chainmask = ah->txchainmask; | ||
631 | |||
632 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
633 | |||
634 | twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0], | ||
635 | pEepData->modalHeader.antennaGainCh[1]); | ||
636 | |||
637 | twiceLargestAntenna = (int16_t)min((AntennaReduction) - | ||
638 | twiceLargestAntenna, 0); | ||
639 | |||
640 | maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; | ||
641 | if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) | ||
642 | maxRegAllowedPower -= | ||
643 | (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); | ||
644 | |||
645 | scaledPower = min(powerLimit, maxRegAllowedPower); | ||
646 | |||
647 | switch (ar5416_get_ntxchains(tx_chainmask)) { | ||
648 | case 1: | ||
649 | break; | ||
650 | case 2: | ||
651 | scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; | ||
652 | break; | ||
653 | case 3: | ||
654 | scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; | ||
655 | break; | ||
656 | } | ||
657 | scaledPower = max((u16)0, scaledPower); | ||
658 | |||
659 | if (IS_CHAN_2GHZ(chan)) { | ||
660 | numCtlModes = | ||
661 | ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; | ||
662 | pCtlMode = ctlModesFor11g; | ||
663 | |||
664 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
665 | pEepData->calTargetPowerCck, | ||
666 | AR9287_NUM_2G_CCK_TARGET_POWERS, | ||
667 | &targetPowerCck, 4, false); | ||
668 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
669 | pEepData->calTargetPower2G, | ||
670 | AR9287_NUM_2G_20_TARGET_POWERS, | ||
671 | &targetPowerOfdm, 4, false); | ||
672 | ath9k_hw_get_target_powers(ah, chan, | ||
673 | pEepData->calTargetPower2GHT20, | ||
674 | AR9287_NUM_2G_20_TARGET_POWERS, | ||
675 | &targetPowerHt20, 8, false); | ||
676 | |||
677 | if (IS_CHAN_HT40(chan)) { | ||
678 | numCtlModes = ARRAY_SIZE(ctlModesFor11g); | ||
679 | ath9k_hw_get_target_powers(ah, chan, | ||
680 | pEepData->calTargetPower2GHT40, | ||
681 | AR9287_NUM_2G_40_TARGET_POWERS, | ||
682 | &targetPowerHt40, 8, true); | ||
683 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
684 | pEepData->calTargetPowerCck, | ||
685 | AR9287_NUM_2G_CCK_TARGET_POWERS, | ||
686 | &targetPowerCckExt, 4, true); | ||
687 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
688 | pEepData->calTargetPower2G, | ||
689 | AR9287_NUM_2G_20_TARGET_POWERS, | ||
690 | &targetPowerOfdmExt, 4, true); | ||
691 | } | ||
692 | } | ||
693 | |||
694 | for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { | ||
695 | bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || | ||
696 | (pCtlMode[ctlMode] == CTL_2GHT40); | ||
697 | if (isHt40CtlMode) | ||
698 | freq = centers.synth_center; | ||
699 | else if (pCtlMode[ctlMode] & EXT_ADDITIVE) | ||
700 | freq = centers.ext_center; | ||
701 | else | ||
702 | freq = centers.ctl_center; | ||
703 | |||
704 | if (ah->eep_ops->get_eeprom_ver(ah) == 14 && | ||
705 | ah->eep_ops->get_eeprom_rev(ah) <= 2) | ||
706 | twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
707 | |||
708 | for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { | ||
709 | if ((((cfgCtl & ~CTL_MODE_M) | | ||
710 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
711 | pEepData->ctlIndex[i]) || | ||
712 | (((cfgCtl & ~CTL_MODE_M) | | ||
713 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
714 | ((pEepData->ctlIndex[i] & | ||
715 | CTL_MODE_M) | SD_NO_CTL))) { | ||
716 | |||
717 | rep = &(pEepData->ctlData[i]); | ||
718 | twiceMinEdgePower = ath9k_hw_get_max_edge_power( | ||
719 | freq, | ||
720 | rep->ctlEdges[ar5416_get_ntxchains( | ||
721 | tx_chainmask) - 1], | ||
722 | IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); | ||
723 | |||
724 | if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) | ||
725 | twiceMaxEdgePower = min( | ||
726 | twiceMaxEdgePower, | ||
727 | twiceMinEdgePower); | ||
728 | else { | ||
729 | twiceMaxEdgePower = twiceMinEdgePower; | ||
730 | break; | ||
731 | } | ||
732 | } | ||
733 | } | ||
734 | |||
735 | minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); | ||
736 | |||
737 | switch (pCtlMode[ctlMode]) { | ||
738 | case CTL_11B: | ||
739 | for (i = 0; | ||
740 | i < ARRAY_SIZE(targetPowerCck.tPow2x); | ||
741 | i++) { | ||
742 | targetPowerCck.tPow2x[i] = (u8)min( | ||
743 | (u16)targetPowerCck.tPow2x[i], | ||
744 | minCtlPower); | ||
745 | } | ||
746 | break; | ||
747 | case CTL_11A: | ||
748 | case CTL_11G: | ||
749 | for (i = 0; | ||
750 | i < ARRAY_SIZE(targetPowerOfdm.tPow2x); | ||
751 | i++) { | ||
752 | targetPowerOfdm.tPow2x[i] = (u8)min( | ||
753 | (u16)targetPowerOfdm.tPow2x[i], | ||
754 | minCtlPower); | ||
755 | } | ||
756 | break; | ||
757 | case CTL_5GHT20: | ||
758 | case CTL_2GHT20: | ||
759 | for (i = 0; | ||
760 | i < ARRAY_SIZE(targetPowerHt20.tPow2x); | ||
761 | i++) { | ||
762 | targetPowerHt20.tPow2x[i] = (u8)min( | ||
763 | (u16)targetPowerHt20.tPow2x[i], | ||
764 | minCtlPower); | ||
765 | } | ||
766 | break; | ||
767 | case CTL_11B_EXT: | ||
768 | targetPowerCckExt.tPow2x[0] = (u8)min( | ||
769 | (u16)targetPowerCckExt.tPow2x[0], | ||
770 | minCtlPower); | ||
771 | break; | ||
772 | case CTL_11A_EXT: | ||
773 | case CTL_11G_EXT: | ||
774 | targetPowerOfdmExt.tPow2x[0] = (u8)min( | ||
775 | (u16)targetPowerOfdmExt.tPow2x[0], | ||
776 | minCtlPower); | ||
777 | break; | ||
778 | case CTL_5GHT40: | ||
779 | case CTL_2GHT40: | ||
780 | for (i = 0; | ||
781 | i < ARRAY_SIZE(targetPowerHt40.tPow2x); | ||
782 | i++) { | ||
783 | targetPowerHt40.tPow2x[i] = (u8)min( | ||
784 | (u16)targetPowerHt40.tPow2x[i], | ||
785 | minCtlPower); | ||
786 | } | ||
787 | break; | ||
788 | default: | ||
789 | break; | ||
790 | } | ||
791 | } | ||
792 | |||
793 | ratesArray[rate6mb] = | ||
794 | ratesArray[rate9mb] = | ||
795 | ratesArray[rate12mb] = | ||
796 | ratesArray[rate18mb] = | ||
797 | ratesArray[rate24mb] = | ||
798 | targetPowerOfdm.tPow2x[0]; | ||
799 | |||
800 | ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; | ||
801 | ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; | ||
802 | ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; | ||
803 | ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; | ||
804 | |||
805 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) | ||
806 | ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; | ||
807 | |||
808 | if (IS_CHAN_2GHZ(chan)) { | ||
809 | ratesArray[rate1l] = targetPowerCck.tPow2x[0]; | ||
810 | ratesArray[rate2s] = ratesArray[rate2l] = | ||
811 | targetPowerCck.tPow2x[1]; | ||
812 | ratesArray[rate5_5s] = ratesArray[rate5_5l] = | ||
813 | targetPowerCck.tPow2x[2]; | ||
814 | ratesArray[rate11s] = ratesArray[rate11l] = | ||
815 | targetPowerCck.tPow2x[3]; | ||
816 | } | ||
817 | if (IS_CHAN_HT40(chan)) { | ||
818 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) | ||
819 | ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; | ||
820 | |||
821 | ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; | ||
822 | ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; | ||
823 | ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; | ||
824 | if (IS_CHAN_2GHZ(chan)) | ||
825 | ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; | ||
826 | } | ||
827 | |||
828 | #undef REDUCE_SCALED_POWER_BY_TWO_CHAIN | ||
829 | #undef REDUCE_SCALED_POWER_BY_THREE_CHAIN | ||
830 | } | ||
831 | |||
832 | static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, | ||
833 | struct ath9k_channel *chan, u16 cfgCtl, | ||
834 | u8 twiceAntennaReduction, | ||
835 | u8 twiceMaxRegulatoryPower, | ||
836 | u8 powerLimit) | ||
837 | { | ||
838 | #define INCREASE_MAXPOW_BY_TWO_CHAIN 6 | ||
839 | #define INCREASE_MAXPOW_BY_THREE_CHAIN 10 | ||
840 | |||
841 | struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; | ||
842 | struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; | ||
843 | int16_t ratesArray[Ar5416RateSize]; | ||
844 | int16_t txPowerIndexOffset = 0; | ||
845 | u8 ht40PowerIncForPdadc = 2; | ||
846 | int i; | ||
847 | |||
848 | memset(ratesArray, 0, sizeof(ratesArray)); | ||
849 | |||
850 | if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= | ||
851 | AR9287_EEP_MINOR_VER_2) | ||
852 | ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; | ||
853 | |||
854 | ath9k_hw_set_AR9287_power_per_rate_table(ah, chan, | ||
855 | &ratesArray[0], cfgCtl, | ||
856 | twiceAntennaReduction, | ||
857 | twiceMaxRegulatoryPower, | ||
858 | powerLimit); | ||
859 | |||
860 | ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset); | ||
861 | |||
862 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | ||
863 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
864 | if (ratesArray[i] > AR9287_MAX_RATE_POWER) | ||
865 | ratesArray[i] = AR9287_MAX_RATE_POWER; | ||
866 | } | ||
867 | |||
868 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
869 | for (i = 0; i < Ar5416RateSize; i++) | ||
870 | ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; | ||
871 | } | ||
872 | |||
873 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, | ||
874 | ATH9K_POW_SM(ratesArray[rate18mb], 24) | ||
875 | | ATH9K_POW_SM(ratesArray[rate12mb], 16) | ||
876 | | ATH9K_POW_SM(ratesArray[rate9mb], 8) | ||
877 | | ATH9K_POW_SM(ratesArray[rate6mb], 0)); | ||
878 | |||
879 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, | ||
880 | ATH9K_POW_SM(ratesArray[rate54mb], 24) | ||
881 | | ATH9K_POW_SM(ratesArray[rate48mb], 16) | ||
882 | | ATH9K_POW_SM(ratesArray[rate36mb], 8) | ||
883 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); | ||
884 | |||
885 | if (IS_CHAN_2GHZ(chan)) { | ||
886 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
887 | ATH9K_POW_SM(ratesArray[rate2s], 24) | ||
888 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | ||
889 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
890 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | ||
891 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
892 | ATH9K_POW_SM(ratesArray[rate11s], 24) | ||
893 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | ||
894 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | ||
895 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | ||
896 | } | ||
897 | |||
898 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, | ||
899 | ATH9K_POW_SM(ratesArray[rateHt20_3], 24) | ||
900 | | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) | ||
901 | | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) | ||
902 | | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); | ||
903 | |||
904 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, | ||
905 | ATH9K_POW_SM(ratesArray[rateHt20_7], 24) | ||
906 | | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) | ||
907 | | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) | ||
908 | | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); | ||
909 | |||
910 | if (IS_CHAN_HT40(chan)) { | ||
911 | if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { | ||
912 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
913 | ATH9K_POW_SM(ratesArray[rateHt40_3], 24) | ||
914 | | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) | ||
915 | | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) | ||
916 | | ATH9K_POW_SM(ratesArray[rateHt40_0], 0)); | ||
917 | |||
918 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
919 | ATH9K_POW_SM(ratesArray[rateHt40_7], 24) | ||
920 | | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) | ||
921 | | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) | ||
922 | | ATH9K_POW_SM(ratesArray[rateHt40_4], 0)); | ||
923 | } else { | ||
924 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
925 | ATH9K_POW_SM(ratesArray[rateHt40_3] + | ||
926 | ht40PowerIncForPdadc, 24) | ||
927 | | ATH9K_POW_SM(ratesArray[rateHt40_2] + | ||
928 | ht40PowerIncForPdadc, 16) | ||
929 | | ATH9K_POW_SM(ratesArray[rateHt40_1] + | ||
930 | ht40PowerIncForPdadc, 8) | ||
931 | | ATH9K_POW_SM(ratesArray[rateHt40_0] + | ||
932 | ht40PowerIncForPdadc, 0)); | ||
933 | |||
934 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
935 | ATH9K_POW_SM(ratesArray[rateHt40_7] + | ||
936 | ht40PowerIncForPdadc, 24) | ||
937 | | ATH9K_POW_SM(ratesArray[rateHt40_6] + | ||
938 | ht40PowerIncForPdadc, 16) | ||
939 | | ATH9K_POW_SM(ratesArray[rateHt40_5] + | ||
940 | ht40PowerIncForPdadc, 8) | ||
941 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + | ||
942 | ht40PowerIncForPdadc, 0)); | ||
943 | } | ||
944 | |||
945 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
946 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
947 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ||
948 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
949 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | ||
950 | } | ||
951 | |||
952 | if (IS_CHAN_2GHZ(chan)) | ||
953 | i = rate1l; | ||
954 | else | ||
955 | i = rate6mb; | ||
956 | |||
957 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
958 | ah->regulatory.max_power_level = | ||
959 | ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; | ||
960 | else | ||
961 | ah->regulatory.max_power_level = ratesArray[i]; | ||
962 | |||
963 | switch (ar5416_get_ntxchains(ah->txchainmask)) { | ||
964 | case 1: | ||
965 | break; | ||
966 | case 2: | ||
967 | ah->regulatory.max_power_level += | ||
968 | INCREASE_MAXPOW_BY_TWO_CHAIN; | ||
969 | break; | ||
970 | case 3: | ||
971 | ah->regulatory.max_power_level += | ||
972 | INCREASE_MAXPOW_BY_THREE_CHAIN; | ||
973 | break; | ||
974 | default: | ||
975 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
976 | "Invalid chainmask configuration\n"); | ||
977 | break; | ||
978 | } | ||
979 | } | ||
980 | |||
981 | static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah, | ||
982 | struct ath9k_channel *chan) | ||
983 | { | ||
984 | } | ||
985 | |||
986 | static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, | ||
987 | struct ath9k_channel *chan) | ||
988 | { | ||
989 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
990 | struct modal_eep_ar9287_header *pModal = &eep->modalHeader; | ||
991 | u16 antWrites[AR9287_ANT_16S]; | ||
992 | u32 regChainOffset; | ||
993 | u8 txRxAttenLocal; | ||
994 | int i, j, offset_num; | ||
995 | |||
996 | pModal = &eep->modalHeader; | ||
997 | |||
998 | antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF); | ||
999 | antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF); | ||
1000 | antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF); | ||
1001 | antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF); | ||
1002 | antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF); | ||
1003 | antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF); | ||
1004 | antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF); | ||
1005 | antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF); | ||
1006 | |||
1007 | offset_num = 8; | ||
1008 | |||
1009 | for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { | ||
1010 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf); | ||
1011 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3); | ||
1012 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3); | ||
1013 | antWrites[j++] = 0; | ||
1014 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3); | ||
1015 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3); | ||
1016 | antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3); | ||
1017 | antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); | ||
1018 | } | ||
1019 | |||
1020 | REG_WRITE(ah, AR_PHY_SWITCH_COM, | ||
1021 | ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); | ||
1022 | |||
1023 | for (i = 0; i < AR9287_MAX_CHAINS; i++) { | ||
1024 | regChainOffset = i * 0x1000; | ||
1025 | |||
1026 | REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, | ||
1027 | pModal->antCtrlChain[i]); | ||
1028 | |||
1029 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, | ||
1030 | (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) | ||
1031 | & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | | ||
1032 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | | ||
1033 | SM(pModal->iqCalICh[i], | ||
1034 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | | ||
1035 | SM(pModal->iqCalQCh[i], | ||
1036 | AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); | ||
1037 | |||
1038 | txRxAttenLocal = pModal->txRxAttenCh[i]; | ||
1039 | |||
1040 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1041 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, | ||
1042 | pModal->bswMargin[i]); | ||
1043 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
1044 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, | ||
1045 | pModal->bswAtten[i]); | ||
1046 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, | ||
1047 | AR9280_PHY_RXGAIN_TXRX_ATTEN, | ||
1048 | txRxAttenLocal); | ||
1049 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, | ||
1050 | AR9280_PHY_RXGAIN_TXRX_MARGIN, | ||
1051 | pModal->rxTxMarginCh[i]); | ||
1052 | } | ||
1053 | |||
1054 | |||
1055 | if (IS_CHAN_HT40(chan)) | ||
1056 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
1057 | AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); | ||
1058 | else | ||
1059 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
1060 | AR_PHY_SETTLING_SWITCH, pModal->switchSettling); | ||
1061 | |||
1062 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, | ||
1063 | AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); | ||
1064 | |||
1065 | REG_WRITE(ah, AR_PHY_RF_CTL4, | ||
1066 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | ||
1067 | | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | ||
1068 | | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | ||
1069 | | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); | ||
1070 | |||
1071 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, | ||
1072 | AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); | ||
1073 | |||
1074 | REG_RMW_FIELD(ah, AR_PHY_CCA, | ||
1075 | AR9280_PHY_CCA_THRESH62, pModal->thresh62); | ||
1076 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, | ||
1077 | AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); | ||
1078 | |||
1079 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1, | ||
1080 | AR9287_AN_RF2G3_DB1_S, pModal->db1); | ||
1081 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2, | ||
1082 | AR9287_AN_RF2G3_DB2_S, pModal->db2); | ||
1083 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, | ||
1084 | AR9287_AN_RF2G3_OB_CCK, | ||
1085 | AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); | ||
1086 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, | ||
1087 | AR9287_AN_RF2G3_OB_PSK, | ||
1088 | AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); | ||
1089 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, | ||
1090 | AR9287_AN_RF2G3_OB_QAM, | ||
1091 | AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); | ||
1092 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, | ||
1093 | AR9287_AN_RF2G3_OB_PAL_OFF, | ||
1094 | AR9287_AN_RF2G3_OB_PAL_OFF_S, | ||
1095 | pModal->ob_pal_off); | ||
1096 | |||
1097 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
1098 | AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S, | ||
1099 | pModal->db1); | ||
1100 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2, | ||
1101 | AR9287_AN_RF2G3_DB2_S, pModal->db2); | ||
1102 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
1103 | AR9287_AN_RF2G3_OB_CCK, | ||
1104 | AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); | ||
1105 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
1106 | AR9287_AN_RF2G3_OB_PSK, | ||
1107 | AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); | ||
1108 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
1109 | AR9287_AN_RF2G3_OB_QAM, | ||
1110 | AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); | ||
1111 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, | ||
1112 | AR9287_AN_RF2G3_OB_PAL_OFF, | ||
1113 | AR9287_AN_RF2G3_OB_PAL_OFF_S, | ||
1114 | pModal->ob_pal_off); | ||
1115 | |||
1116 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, | ||
1117 | AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart); | ||
1118 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, | ||
1119 | AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn); | ||
1120 | |||
1121 | ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2, | ||
1122 | AR9287_AN_TOP2_XPABIAS_LVL, | ||
1123 | AR9287_AN_TOP2_XPABIAS_LVL_S, | ||
1124 | pModal->xpaBiasLvl); | ||
1125 | } | ||
1126 | |||
1127 | static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah, | ||
1128 | enum ieee80211_band freq_band) | ||
1129 | { | ||
1130 | return 1; | ||
1131 | } | ||
1132 | |||
1133 | static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah, | ||
1134 | struct ath9k_channel *chan) | ||
1135 | { | ||
1136 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
1137 | struct modal_eep_ar9287_header *pModal = &eep->modalHeader; | ||
1138 | |||
1139 | return pModal->antCtrlCommon & 0xFFFF; | ||
1140 | } | ||
1141 | |||
1142 | static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, | ||
1143 | u16 i, bool is2GHz) | ||
1144 | { | ||
1145 | #define EEP_MAP9287_SPURCHAN \ | ||
1146 | (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan) | ||
1147 | u16 spur_val = AR_NO_SPUR; | ||
1148 | |||
1149 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1150 | "Getting spur idx %d is2Ghz. %d val %x\n", | ||
1151 | i, is2GHz, ah->config.spurchans[i][is2GHz]); | ||
1152 | |||
1153 | switch (ah->config.spurmode) { | ||
1154 | case SPUR_DISABLE: | ||
1155 | break; | ||
1156 | case SPUR_ENABLE_IOCTL: | ||
1157 | spur_val = ah->config.spurchans[i][is2GHz]; | ||
1158 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1159 | "Getting spur val from new loc. %d\n", spur_val); | ||
1160 | break; | ||
1161 | case SPUR_ENABLE_EEPROM: | ||
1162 | spur_val = EEP_MAP9287_SPURCHAN; | ||
1163 | break; | ||
1164 | } | ||
1165 | |||
1166 | return spur_val; | ||
1167 | |||
1168 | #undef EEP_MAP9287_SPURCHAN | ||
1169 | } | ||
1170 | |||
1171 | const struct eeprom_ops eep_AR9287_ops = { | ||
1172 | .check_eeprom = ath9k_hw_AR9287_check_eeprom, | ||
1173 | .get_eeprom = ath9k_hw_AR9287_get_eeprom, | ||
1174 | .fill_eeprom = ath9k_hw_AR9287_fill_eeprom, | ||
1175 | .get_eeprom_ver = ath9k_hw_AR9287_get_eeprom_ver, | ||
1176 | .get_eeprom_rev = ath9k_hw_AR9287_get_eeprom_rev, | ||
1177 | .get_num_ant_config = ath9k_hw_AR9287_get_num_ant_config, | ||
1178 | .get_eeprom_antenna_cfg = ath9k_hw_AR9287_get_eeprom_antenna_cfg, | ||
1179 | .set_board_values = ath9k_hw_AR9287_set_board_values, | ||
1180 | .set_addac = ath9k_hw_AR9287_set_addac, | ||
1181 | .set_txpower = ath9k_hw_AR9287_set_txpower, | ||
1182 | .get_spur_channel = ath9k_hw_AR9287_get_spur_channel | ||
1183 | }; | ||
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c new file mode 100644 index 000000000000..5211ad94c8fb --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c | |||
@@ -0,0 +1,1385 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008-2009 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "ath9k.h" | ||
18 | |||
19 | static void ath9k_get_txgain_index(struct ath_hw *ah, | ||
20 | struct ath9k_channel *chan, | ||
21 | struct calDataPerFreqOpLoop *rawDatasetOpLoop, | ||
22 | u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx) | ||
23 | { | ||
24 | u8 pcdac, i = 0; | ||
25 | u16 idxL = 0, idxR = 0, numPiers; | ||
26 | bool match; | ||
27 | struct chan_centers centers; | ||
28 | |||
29 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
30 | |||
31 | for (numPiers = 0; numPiers < availPiers; numPiers++) | ||
32 | if (calChans[numPiers] == AR5416_BCHAN_UNUSED) | ||
33 | break; | ||
34 | |||
35 | match = ath9k_hw_get_lower_upper_index( | ||
36 | (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), | ||
37 | calChans, numPiers, &idxL, &idxR); | ||
38 | if (match) { | ||
39 | pcdac = rawDatasetOpLoop[idxL].pcdac[0][0]; | ||
40 | *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0]; | ||
41 | } else { | ||
42 | pcdac = rawDatasetOpLoop[idxR].pcdac[0][0]; | ||
43 | *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] + | ||
44 | rawDatasetOpLoop[idxR].pwrPdg[0][0])/2; | ||
45 | } | ||
46 | |||
47 | while (pcdac > ah->originalGain[i] && | ||
48 | i < (AR9280_TX_GAIN_TABLE_SIZE - 1)) | ||
49 | i++; | ||
50 | |||
51 | *pcdacIdx = i; | ||
52 | return; | ||
53 | } | ||
54 | |||
55 | static void ath9k_olc_get_pdadcs(struct ath_hw *ah, | ||
56 | u32 initTxGain, | ||
57 | int txPower, | ||
58 | u8 *pPDADCValues) | ||
59 | { | ||
60 | u32 i; | ||
61 | u32 offset; | ||
62 | |||
63 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, | ||
64 | AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); | ||
65 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, | ||
66 | AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); | ||
67 | |||
68 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, | ||
69 | AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain); | ||
70 | |||
71 | offset = txPower; | ||
72 | for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++) | ||
73 | if (i < offset) | ||
74 | pPDADCValues[i] = 0x0; | ||
75 | else | ||
76 | pPDADCValues[i] = 0xFF; | ||
77 | } | ||
78 | |||
79 | static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah) | ||
80 | { | ||
81 | return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF); | ||
82 | } | ||
83 | |||
84 | static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) | ||
85 | { | ||
86 | return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF); | ||
87 | } | ||
88 | |||
89 | static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) | ||
90 | { | ||
91 | #define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) | ||
92 | u16 *eep_data = (u16 *)&ah->eeprom.def; | ||
93 | int addr, ar5416_eep_start_loc = 0x100; | ||
94 | |||
95 | for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { | ||
96 | if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, | ||
97 | eep_data)) { | ||
98 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
99 | "Unable to read eeprom region\n"); | ||
100 | return false; | ||
101 | } | ||
102 | eep_data++; | ||
103 | } | ||
104 | return true; | ||
105 | #undef SIZE_EEPROM_DEF | ||
106 | } | ||
107 | |||
108 | static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) | ||
109 | { | ||
110 | struct ar5416_eeprom_def *eep = | ||
111 | (struct ar5416_eeprom_def *) &ah->eeprom.def; | ||
112 | u16 *eepdata, temp, magic, magic2; | ||
113 | u32 sum = 0, el; | ||
114 | bool need_swap = false; | ||
115 | int i, addr, size; | ||
116 | |||
117 | if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { | ||
118 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n"); | ||
119 | return false; | ||
120 | } | ||
121 | |||
122 | if (!ath9k_hw_use_flash(ah)) { | ||
123 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
124 | "Read Magic = 0x%04X\n", magic); | ||
125 | |||
126 | if (magic != AR5416_EEPROM_MAGIC) { | ||
127 | magic2 = swab16(magic); | ||
128 | |||
129 | if (magic2 == AR5416_EEPROM_MAGIC) { | ||
130 | size = sizeof(struct ar5416_eeprom_def); | ||
131 | need_swap = true; | ||
132 | eepdata = (u16 *) (&ah->eeprom); | ||
133 | |||
134 | for (addr = 0; addr < size / sizeof(u16); addr++) { | ||
135 | temp = swab16(*eepdata); | ||
136 | *eepdata = temp; | ||
137 | eepdata++; | ||
138 | } | ||
139 | } else { | ||
140 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
141 | "Invalid EEPROM Magic. " | ||
142 | "Endianness mismatch.\n"); | ||
143 | return -EINVAL; | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | |||
148 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", | ||
149 | need_swap ? "True" : "False"); | ||
150 | |||
151 | if (need_swap) | ||
152 | el = swab16(ah->eeprom.def.baseEepHeader.length); | ||
153 | else | ||
154 | el = ah->eeprom.def.baseEepHeader.length; | ||
155 | |||
156 | if (el > sizeof(struct ar5416_eeprom_def)) | ||
157 | el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); | ||
158 | else | ||
159 | el = el / sizeof(u16); | ||
160 | |||
161 | eepdata = (u16 *)(&ah->eeprom); | ||
162 | |||
163 | for (i = 0; i < el; i++) | ||
164 | sum ^= *eepdata++; | ||
165 | |||
166 | if (need_swap) { | ||
167 | u32 integer, j; | ||
168 | u16 word; | ||
169 | |||
170 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
171 | "EEPROM Endianness is not native.. Changing.\n"); | ||
172 | |||
173 | word = swab16(eep->baseEepHeader.length); | ||
174 | eep->baseEepHeader.length = word; | ||
175 | |||
176 | word = swab16(eep->baseEepHeader.checksum); | ||
177 | eep->baseEepHeader.checksum = word; | ||
178 | |||
179 | word = swab16(eep->baseEepHeader.version); | ||
180 | eep->baseEepHeader.version = word; | ||
181 | |||
182 | word = swab16(eep->baseEepHeader.regDmn[0]); | ||
183 | eep->baseEepHeader.regDmn[0] = word; | ||
184 | |||
185 | word = swab16(eep->baseEepHeader.regDmn[1]); | ||
186 | eep->baseEepHeader.regDmn[1] = word; | ||
187 | |||
188 | word = swab16(eep->baseEepHeader.rfSilent); | ||
189 | eep->baseEepHeader.rfSilent = word; | ||
190 | |||
191 | word = swab16(eep->baseEepHeader.blueToothOptions); | ||
192 | eep->baseEepHeader.blueToothOptions = word; | ||
193 | |||
194 | word = swab16(eep->baseEepHeader.deviceCap); | ||
195 | eep->baseEepHeader.deviceCap = word; | ||
196 | |||
197 | for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { | ||
198 | struct modal_eep_header *pModal = | ||
199 | &eep->modalHeader[j]; | ||
200 | integer = swab32(pModal->antCtrlCommon); | ||
201 | pModal->antCtrlCommon = integer; | ||
202 | |||
203 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
204 | integer = swab32(pModal->antCtrlChain[i]); | ||
205 | pModal->antCtrlChain[i] = integer; | ||
206 | } | ||
207 | |||
208 | for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { | ||
209 | word = swab16(pModal->spurChans[i].spurChan); | ||
210 | pModal->spurChans[i].spurChan = word; | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | |||
215 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || | ||
216 | ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { | ||
217 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, | ||
218 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", | ||
219 | sum, ah->eep_ops->get_eeprom_ver(ah)); | ||
220 | return -EINVAL; | ||
221 | } | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, | ||
227 | enum eeprom_param param) | ||
228 | { | ||
229 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
230 | struct modal_eep_header *pModal = eep->modalHeader; | ||
231 | struct base_eep_header *pBase = &eep->baseEepHeader; | ||
232 | |||
233 | switch (param) { | ||
234 | case EEP_NFTHRESH_5: | ||
235 | return pModal[0].noiseFloorThreshCh[0]; | ||
236 | case EEP_NFTHRESH_2: | ||
237 | return pModal[1].noiseFloorThreshCh[0]; | ||
238 | case AR_EEPROM_MAC(0): | ||
239 | return pBase->macAddr[0] << 8 | pBase->macAddr[1]; | ||
240 | case AR_EEPROM_MAC(1): | ||
241 | return pBase->macAddr[2] << 8 | pBase->macAddr[3]; | ||
242 | case AR_EEPROM_MAC(2): | ||
243 | return pBase->macAddr[4] << 8 | pBase->macAddr[5]; | ||
244 | case EEP_REG_0: | ||
245 | return pBase->regDmn[0]; | ||
246 | case EEP_REG_1: | ||
247 | return pBase->regDmn[1]; | ||
248 | case EEP_OP_CAP: | ||
249 | return pBase->deviceCap; | ||
250 | case EEP_OP_MODE: | ||
251 | return pBase->opCapFlags; | ||
252 | case EEP_RF_SILENT: | ||
253 | return pBase->rfSilent; | ||
254 | case EEP_OB_5: | ||
255 | return pModal[0].ob; | ||
256 | case EEP_DB_5: | ||
257 | return pModal[0].db; | ||
258 | case EEP_OB_2: | ||
259 | return pModal[1].ob; | ||
260 | case EEP_DB_2: | ||
261 | return pModal[1].db; | ||
262 | case EEP_MINOR_REV: | ||
263 | return AR5416_VER_MASK; | ||
264 | case EEP_TX_MASK: | ||
265 | return pBase->txMask; | ||
266 | case EEP_RX_MASK: | ||
267 | return pBase->rxMask; | ||
268 | case EEP_RXGAIN_TYPE: | ||
269 | return pBase->rxGainType; | ||
270 | case EEP_TXGAIN_TYPE: | ||
271 | return pBase->txGainType; | ||
272 | case EEP_OL_PWRCTRL: | ||
273 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
274 | return pBase->openLoopPwrCntl ? true : false; | ||
275 | else | ||
276 | return false; | ||
277 | case EEP_RC_CHAIN_MASK: | ||
278 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
279 | return pBase->rcChainMask; | ||
280 | else | ||
281 | return 0; | ||
282 | case EEP_DAC_HPWR_5G: | ||
283 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) | ||
284 | return pBase->dacHiPwrMode_5G; | ||
285 | else | ||
286 | return 0; | ||
287 | case EEP_FRAC_N_5G: | ||
288 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22) | ||
289 | return pBase->frac_n_5g; | ||
290 | else | ||
291 | return 0; | ||
292 | default: | ||
293 | return 0; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | static void ath9k_hw_def_set_gain(struct ath_hw *ah, | ||
298 | struct modal_eep_header *pModal, | ||
299 | struct ar5416_eeprom_def *eep, | ||
300 | u8 txRxAttenLocal, int regChainOffset, int i) | ||
301 | { | ||
302 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { | ||
303 | txRxAttenLocal = pModal->txRxAttenCh[i]; | ||
304 | |||
305 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
306 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
307 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, | ||
308 | pModal->bswMargin[i]); | ||
309 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
310 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, | ||
311 | pModal->bswAtten[i]); | ||
312 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
313 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | ||
314 | pModal->xatten2Margin[i]); | ||
315 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
316 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, | ||
317 | pModal->xatten2Db[i]); | ||
318 | } else { | ||
319 | REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
320 | (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & | ||
321 | ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | ||
322 | | SM(pModal-> bswMargin[i], | ||
323 | AR_PHY_GAIN_2GHZ_BSW_MARGIN)); | ||
324 | REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
325 | (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & | ||
326 | ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | ||
327 | | SM(pModal->bswAtten[i], | ||
328 | AR_PHY_GAIN_2GHZ_BSW_ATTEN)); | ||
329 | } | ||
330 | } | ||
331 | |||
332 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
333 | REG_RMW_FIELD(ah, | ||
334 | AR_PHY_RXGAIN + regChainOffset, | ||
335 | AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); | ||
336 | REG_RMW_FIELD(ah, | ||
337 | AR_PHY_RXGAIN + regChainOffset, | ||
338 | AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]); | ||
339 | } else { | ||
340 | REG_WRITE(ah, | ||
341 | AR_PHY_RXGAIN + regChainOffset, | ||
342 | (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & | ||
343 | ~AR_PHY_RXGAIN_TXRX_ATTEN) | ||
344 | | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN)); | ||
345 | REG_WRITE(ah, | ||
346 | AR_PHY_GAIN_2GHZ + regChainOffset, | ||
347 | (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & | ||
348 | ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | | ||
349 | SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | static void ath9k_hw_def_set_board_values(struct ath_hw *ah, | ||
354 | struct ath9k_channel *chan) | ||
355 | { | ||
356 | struct modal_eep_header *pModal; | ||
357 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
358 | int i, regChainOffset; | ||
359 | u8 txRxAttenLocal; | ||
360 | |||
361 | pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
362 | txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; | ||
363 | |||
364 | REG_WRITE(ah, AR_PHY_SWITCH_COM, | ||
365 | ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); | ||
366 | |||
367 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
368 | if (AR_SREV_9280(ah)) { | ||
369 | if (i >= 2) | ||
370 | break; | ||
371 | } | ||
372 | |||
373 | if (AR_SREV_5416_20_OR_LATER(ah) && | ||
374 | (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) | ||
375 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; | ||
376 | else | ||
377 | regChainOffset = i * 0x1000; | ||
378 | |||
379 | REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, | ||
380 | pModal->antCtrlChain[i]); | ||
381 | |||
382 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, | ||
383 | (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & | ||
384 | ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | | ||
385 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | | ||
386 | SM(pModal->iqCalICh[i], | ||
387 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | | ||
388 | SM(pModal->iqCalQCh[i], | ||
389 | AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); | ||
390 | |||
391 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) | ||
392 | ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal, | ||
393 | regChainOffset, i); | ||
394 | } | ||
395 | |||
396 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
397 | if (IS_CHAN_2GHZ(chan)) { | ||
398 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, | ||
399 | AR_AN_RF2G1_CH0_OB, | ||
400 | AR_AN_RF2G1_CH0_OB_S, | ||
401 | pModal->ob); | ||
402 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, | ||
403 | AR_AN_RF2G1_CH0_DB, | ||
404 | AR_AN_RF2G1_CH0_DB_S, | ||
405 | pModal->db); | ||
406 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, | ||
407 | AR_AN_RF2G1_CH1_OB, | ||
408 | AR_AN_RF2G1_CH1_OB_S, | ||
409 | pModal->ob_ch1); | ||
410 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, | ||
411 | AR_AN_RF2G1_CH1_DB, | ||
412 | AR_AN_RF2G1_CH1_DB_S, | ||
413 | pModal->db_ch1); | ||
414 | } else { | ||
415 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, | ||
416 | AR_AN_RF5G1_CH0_OB5, | ||
417 | AR_AN_RF5G1_CH0_OB5_S, | ||
418 | pModal->ob); | ||
419 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, | ||
420 | AR_AN_RF5G1_CH0_DB5, | ||
421 | AR_AN_RF5G1_CH0_DB5_S, | ||
422 | pModal->db); | ||
423 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, | ||
424 | AR_AN_RF5G1_CH1_OB5, | ||
425 | AR_AN_RF5G1_CH1_OB5_S, | ||
426 | pModal->ob_ch1); | ||
427 | ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, | ||
428 | AR_AN_RF5G1_CH1_DB5, | ||
429 | AR_AN_RF5G1_CH1_DB5_S, | ||
430 | pModal->db_ch1); | ||
431 | } | ||
432 | ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, | ||
433 | AR_AN_TOP2_XPABIAS_LVL, | ||
434 | AR_AN_TOP2_XPABIAS_LVL_S, | ||
435 | pModal->xpaBiasLvl); | ||
436 | ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, | ||
437 | AR_AN_TOP2_LOCALBIAS, | ||
438 | AR_AN_TOP2_LOCALBIAS_S, | ||
439 | pModal->local_bias); | ||
440 | REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, | ||
441 | pModal->force_xpaon); | ||
442 | } | ||
443 | |||
444 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, | ||
445 | pModal->switchSettling); | ||
446 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, | ||
447 | pModal->adcDesiredSize); | ||
448 | |||
449 | if (!AR_SREV_9280_10_OR_LATER(ah)) | ||
450 | REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, | ||
451 | AR_PHY_DESIRED_SZ_PGA, | ||
452 | pModal->pgaDesiredSize); | ||
453 | |||
454 | REG_WRITE(ah, AR_PHY_RF_CTL4, | ||
455 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | ||
456 | | SM(pModal->txEndToXpaOff, | ||
457 | AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | ||
458 | | SM(pModal->txFrameToXpaOn, | ||
459 | AR_PHY_RF_CTL4_FRAME_XPAA_ON) | ||
460 | | SM(pModal->txFrameToXpaOn, | ||
461 | AR_PHY_RF_CTL4_FRAME_XPAB_ON)); | ||
462 | |||
463 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, | ||
464 | pModal->txEndToRxOn); | ||
465 | |||
466 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
467 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, | ||
468 | pModal->thresh62); | ||
469 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, | ||
470 | AR_PHY_EXT_CCA0_THRESH62, | ||
471 | pModal->thresh62); | ||
472 | } else { | ||
473 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, | ||
474 | pModal->thresh62); | ||
475 | REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, | ||
476 | AR_PHY_EXT_CCA_THRESH62, | ||
477 | pModal->thresh62); | ||
478 | } | ||
479 | |||
480 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) { | ||
481 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, | ||
482 | AR_PHY_TX_END_DATA_START, | ||
483 | pModal->txFrameToDataStart); | ||
484 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, | ||
485 | pModal->txFrameToPaOn); | ||
486 | } | ||
487 | |||
488 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { | ||
489 | if (IS_CHAN_HT40(chan)) | ||
490 | REG_RMW_FIELD(ah, AR_PHY_SETTLING, | ||
491 | AR_PHY_SETTLING_SWITCH, | ||
492 | pModal->swSettleHt40); | ||
493 | } | ||
494 | |||
495 | if (AR_SREV_9280_20_OR_LATER(ah) && | ||
496 | AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
497 | REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, | ||
498 | AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, | ||
499 | pModal->miscBits); | ||
500 | |||
501 | |||
502 | if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { | ||
503 | if (IS_CHAN_2GHZ(chan)) | ||
504 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, | ||
505 | eep->baseEepHeader.dacLpMode); | ||
506 | else if (eep->baseEepHeader.dacHiPwrMode_5G) | ||
507 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0); | ||
508 | else | ||
509 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, | ||
510 | eep->baseEepHeader.dacLpMode); | ||
511 | |||
512 | REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, | ||
513 | pModal->miscBits >> 2); | ||
514 | |||
515 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, | ||
516 | AR_PHY_TX_DESIRED_SCALE_CCK, | ||
517 | eep->baseEepHeader.desiredScaleCCK); | ||
518 | } | ||
519 | } | ||
520 | |||
521 | static void ath9k_hw_def_set_addac(struct ath_hw *ah, | ||
522 | struct ath9k_channel *chan) | ||
523 | { | ||
524 | #define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) | ||
525 | struct modal_eep_header *pModal; | ||
526 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
527 | u8 biaslevel; | ||
528 | |||
529 | if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) | ||
530 | return; | ||
531 | |||
532 | if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) | ||
533 | return; | ||
534 | |||
535 | pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
536 | |||
537 | if (pModal->xpaBiasLvl != 0xff) { | ||
538 | biaslevel = pModal->xpaBiasLvl; | ||
539 | } else { | ||
540 | u16 resetFreqBin, freqBin, freqCount = 0; | ||
541 | struct chan_centers centers; | ||
542 | |||
543 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
544 | |||
545 | resetFreqBin = FREQ2FBIN(centers.synth_center, | ||
546 | IS_CHAN_2GHZ(chan)); | ||
547 | freqBin = XPA_LVL_FREQ(0) & 0xff; | ||
548 | biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); | ||
549 | |||
550 | freqCount++; | ||
551 | |||
552 | while (freqCount < 3) { | ||
553 | if (XPA_LVL_FREQ(freqCount) == 0x0) | ||
554 | break; | ||
555 | |||
556 | freqBin = XPA_LVL_FREQ(freqCount) & 0xff; | ||
557 | if (resetFreqBin >= freqBin) | ||
558 | biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); | ||
559 | else | ||
560 | break; | ||
561 | freqCount++; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | if (IS_CHAN_2GHZ(chan)) { | ||
566 | INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac, | ||
567 | 7, 1) & (~0x18)) | biaslevel << 3; | ||
568 | } else { | ||
569 | INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac, | ||
570 | 6, 1) & (~0xc0)) | biaslevel << 6; | ||
571 | } | ||
572 | #undef XPA_LVL_FREQ | ||
573 | } | ||
574 | |||
575 | static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, | ||
576 | struct ath9k_channel *chan, | ||
577 | struct cal_data_per_freq *pRawDataSet, | ||
578 | u8 *bChans, u16 availPiers, | ||
579 | u16 tPdGainOverlap, int16_t *pMinCalPower, | ||
580 | u16 *pPdGainBoundaries, u8 *pPDADCValues, | ||
581 | u16 numXpdGains) | ||
582 | { | ||
583 | int i, j, k; | ||
584 | int16_t ss; | ||
585 | u16 idxL = 0, idxR = 0, numPiers; | ||
586 | static u8 vpdTableL[AR5416_NUM_PD_GAINS] | ||
587 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
588 | static u8 vpdTableR[AR5416_NUM_PD_GAINS] | ||
589 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
590 | static u8 vpdTableI[AR5416_NUM_PD_GAINS] | ||
591 | [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; | ||
592 | |||
593 | u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; | ||
594 | u8 minPwrT4[AR5416_NUM_PD_GAINS]; | ||
595 | u8 maxPwrT4[AR5416_NUM_PD_GAINS]; | ||
596 | int16_t vpdStep; | ||
597 | int16_t tmpVal; | ||
598 | u16 sizeCurrVpdTable, maxIndex, tgtIndex; | ||
599 | bool match; | ||
600 | int16_t minDelta = 0; | ||
601 | struct chan_centers centers; | ||
602 | |||
603 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
604 | |||
605 | for (numPiers = 0; numPiers < availPiers; numPiers++) { | ||
606 | if (bChans[numPiers] == AR5416_BCHAN_UNUSED) | ||
607 | break; | ||
608 | } | ||
609 | |||
610 | match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, | ||
611 | IS_CHAN_2GHZ(chan)), | ||
612 | bChans, numPiers, &idxL, &idxR); | ||
613 | |||
614 | if (match) { | ||
615 | for (i = 0; i < numXpdGains; i++) { | ||
616 | minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; | ||
617 | maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; | ||
618 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
619 | pRawDataSet[idxL].pwrPdg[i], | ||
620 | pRawDataSet[idxL].vpdPdg[i], | ||
621 | AR5416_PD_GAIN_ICEPTS, | ||
622 | vpdTableI[i]); | ||
623 | } | ||
624 | } else { | ||
625 | for (i = 0; i < numXpdGains; i++) { | ||
626 | pVpdL = pRawDataSet[idxL].vpdPdg[i]; | ||
627 | pPwrL = pRawDataSet[idxL].pwrPdg[i]; | ||
628 | pVpdR = pRawDataSet[idxR].vpdPdg[i]; | ||
629 | pPwrR = pRawDataSet[idxR].pwrPdg[i]; | ||
630 | |||
631 | minPwrT4[i] = max(pPwrL[0], pPwrR[0]); | ||
632 | |||
633 | maxPwrT4[i] = | ||
634 | min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], | ||
635 | pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); | ||
636 | |||
637 | |||
638 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
639 | pPwrL, pVpdL, | ||
640 | AR5416_PD_GAIN_ICEPTS, | ||
641 | vpdTableL[i]); | ||
642 | ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], | ||
643 | pPwrR, pVpdR, | ||
644 | AR5416_PD_GAIN_ICEPTS, | ||
645 | vpdTableR[i]); | ||
646 | |||
647 | for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { | ||
648 | vpdTableI[i][j] = | ||
649 | (u8)(ath9k_hw_interpolate((u16) | ||
650 | FREQ2FBIN(centers. | ||
651 | synth_center, | ||
652 | IS_CHAN_2GHZ | ||
653 | (chan)), | ||
654 | bChans[idxL], bChans[idxR], | ||
655 | vpdTableL[i][j], vpdTableR[i][j])); | ||
656 | } | ||
657 | } | ||
658 | } | ||
659 | |||
660 | *pMinCalPower = (int16_t)(minPwrT4[0] / 2); | ||
661 | |||
662 | k = 0; | ||
663 | |||
664 | for (i = 0; i < numXpdGains; i++) { | ||
665 | if (i == (numXpdGains - 1)) | ||
666 | pPdGainBoundaries[i] = | ||
667 | (u16)(maxPwrT4[i] / 2); | ||
668 | else | ||
669 | pPdGainBoundaries[i] = | ||
670 | (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); | ||
671 | |||
672 | pPdGainBoundaries[i] = | ||
673 | min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); | ||
674 | |||
675 | if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { | ||
676 | minDelta = pPdGainBoundaries[0] - 23; | ||
677 | pPdGainBoundaries[0] = 23; | ||
678 | } else { | ||
679 | minDelta = 0; | ||
680 | } | ||
681 | |||
682 | if (i == 0) { | ||
683 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
684 | ss = (int16_t)(0 - (minPwrT4[i] / 2)); | ||
685 | else | ||
686 | ss = 0; | ||
687 | } else { | ||
688 | ss = (int16_t)((pPdGainBoundaries[i - 1] - | ||
689 | (minPwrT4[i] / 2)) - | ||
690 | tPdGainOverlap + 1 + minDelta); | ||
691 | } | ||
692 | vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); | ||
693 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
694 | |||
695 | while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
696 | tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); | ||
697 | pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); | ||
698 | ss++; | ||
699 | } | ||
700 | |||
701 | sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); | ||
702 | tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - | ||
703 | (minPwrT4[i] / 2)); | ||
704 | maxIndex = (tgtIndex < sizeCurrVpdTable) ? | ||
705 | tgtIndex : sizeCurrVpdTable; | ||
706 | |||
707 | while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
708 | pPDADCValues[k++] = vpdTableI[i][ss++]; | ||
709 | } | ||
710 | |||
711 | vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - | ||
712 | vpdTableI[i][sizeCurrVpdTable - 2]); | ||
713 | vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); | ||
714 | |||
715 | if (tgtIndex > maxIndex) { | ||
716 | while ((ss <= tgtIndex) && | ||
717 | (k < (AR5416_NUM_PDADC_VALUES - 1))) { | ||
718 | tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + | ||
719 | (ss - maxIndex + 1) * vpdStep)); | ||
720 | pPDADCValues[k++] = (u8)((tmpVal > 255) ? | ||
721 | 255 : tmpVal); | ||
722 | ss++; | ||
723 | } | ||
724 | } | ||
725 | } | ||
726 | |||
727 | while (i < AR5416_PD_GAINS_IN_MASK) { | ||
728 | pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; | ||
729 | i++; | ||
730 | } | ||
731 | |||
732 | while (k < AR5416_NUM_PDADC_VALUES) { | ||
733 | pPDADCValues[k] = pPDADCValues[k - 1]; | ||
734 | k++; | ||
735 | } | ||
736 | |||
737 | return; | ||
738 | } | ||
739 | |||
740 | static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | ||
741 | struct ath9k_channel *chan, | ||
742 | int16_t *pTxPowerIndexOffset) | ||
743 | { | ||
744 | #define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) | ||
745 | #define SM_PDGAIN_B(x, y) \ | ||
746 | SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y) | ||
747 | |||
748 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; | ||
749 | struct cal_data_per_freq *pRawDataset; | ||
750 | u8 *pCalBChans = NULL; | ||
751 | u16 pdGainOverlap_t2; | ||
752 | static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; | ||
753 | u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; | ||
754 | u16 numPiers, i, j; | ||
755 | int16_t tMinCalPower; | ||
756 | u16 numXpdGain, xpdMask; | ||
757 | u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; | ||
758 | u32 reg32, regOffset, regChainOffset; | ||
759 | int16_t modalIdx; | ||
760 | |||
761 | modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; | ||
762 | xpdMask = pEepData->modalHeader[modalIdx].xpdGain; | ||
763 | |||
764 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
765 | AR5416_EEP_MINOR_VER_2) { | ||
766 | pdGainOverlap_t2 = | ||
767 | pEepData->modalHeader[modalIdx].pdGainOverlap; | ||
768 | } else { | ||
769 | pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), | ||
770 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); | ||
771 | } | ||
772 | |||
773 | if (IS_CHAN_2GHZ(chan)) { | ||
774 | pCalBChans = pEepData->calFreqPier2G; | ||
775 | numPiers = AR5416_NUM_2G_CAL_PIERS; | ||
776 | } else { | ||
777 | pCalBChans = pEepData->calFreqPier5G; | ||
778 | numPiers = AR5416_NUM_5G_CAL_PIERS; | ||
779 | } | ||
780 | |||
781 | if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) { | ||
782 | pRawDataset = pEepData->calPierData2G[0]; | ||
783 | ah->initPDADC = ((struct calDataPerFreqOpLoop *) | ||
784 | pRawDataset)->vpdPdg[0][0]; | ||
785 | } | ||
786 | |||
787 | numXpdGain = 0; | ||
788 | |||
789 | for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { | ||
790 | if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { | ||
791 | if (numXpdGain >= AR5416_NUM_PD_GAINS) | ||
792 | break; | ||
793 | xpdGainValues[numXpdGain] = | ||
794 | (u16)(AR5416_PD_GAINS_IN_MASK - i); | ||
795 | numXpdGain++; | ||
796 | } | ||
797 | } | ||
798 | |||
799 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, | ||
800 | (numXpdGain - 1) & 0x3); | ||
801 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, | ||
802 | xpdGainValues[0]); | ||
803 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, | ||
804 | xpdGainValues[1]); | ||
805 | REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, | ||
806 | xpdGainValues[2]); | ||
807 | |||
808 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
809 | if (AR_SREV_5416_20_OR_LATER(ah) && | ||
810 | (ah->rxchainmask == 5 || ah->txchainmask == 5) && | ||
811 | (i != 0)) { | ||
812 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; | ||
813 | } else | ||
814 | regChainOffset = i * 0x1000; | ||
815 | |||
816 | if (pEepData->baseEepHeader.txMask & (1 << i)) { | ||
817 | if (IS_CHAN_2GHZ(chan)) | ||
818 | pRawDataset = pEepData->calPierData2G[i]; | ||
819 | else | ||
820 | pRawDataset = pEepData->calPierData5G[i]; | ||
821 | |||
822 | |||
823 | if (OLC_FOR_AR9280_20_LATER) { | ||
824 | u8 pcdacIdx; | ||
825 | u8 txPower; | ||
826 | |||
827 | ath9k_get_txgain_index(ah, chan, | ||
828 | (struct calDataPerFreqOpLoop *)pRawDataset, | ||
829 | pCalBChans, numPiers, &txPower, &pcdacIdx); | ||
830 | ath9k_olc_get_pdadcs(ah, pcdacIdx, | ||
831 | txPower/2, pdadcValues); | ||
832 | } else { | ||
833 | ath9k_hw_get_def_gain_boundaries_pdadcs(ah, | ||
834 | chan, pRawDataset, | ||
835 | pCalBChans, numPiers, | ||
836 | pdGainOverlap_t2, | ||
837 | &tMinCalPower, | ||
838 | gainBoundaries, | ||
839 | pdadcValues, | ||
840 | numXpdGain); | ||
841 | } | ||
842 | |||
843 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { | ||
844 | if (OLC_FOR_AR9280_20_LATER) { | ||
845 | REG_WRITE(ah, | ||
846 | AR_PHY_TPCRG5 + regChainOffset, | ||
847 | SM(0x6, | ||
848 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | | ||
849 | SM_PD_GAIN(1) | SM_PD_GAIN(2) | | ||
850 | SM_PD_GAIN(3) | SM_PD_GAIN(4)); | ||
851 | } else { | ||
852 | REG_WRITE(ah, | ||
853 | AR_PHY_TPCRG5 + regChainOffset, | ||
854 | SM(pdGainOverlap_t2, | ||
855 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| | ||
856 | SM_PDGAIN_B(0, 1) | | ||
857 | SM_PDGAIN_B(1, 2) | | ||
858 | SM_PDGAIN_B(2, 3) | | ||
859 | SM_PDGAIN_B(3, 4)); | ||
860 | } | ||
861 | } | ||
862 | |||
863 | regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; | ||
864 | for (j = 0; j < 32; j++) { | ||
865 | reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | | ||
866 | ((pdadcValues[4 * j + 1] & 0xFF) << 8) | | ||
867 | ((pdadcValues[4 * j + 2] & 0xFF) << 16)| | ||
868 | ((pdadcValues[4 * j + 3] & 0xFF) << 24); | ||
869 | REG_WRITE(ah, regOffset, reg32); | ||
870 | |||
871 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
872 | "PDADC (%d,%4x): %4.4x %8.8x\n", | ||
873 | i, regChainOffset, regOffset, | ||
874 | reg32); | ||
875 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
876 | "PDADC: Chain %d | PDADC %3d " | ||
877 | "Value %3d | PDADC %3d Value %3d | " | ||
878 | "PDADC %3d Value %3d | PDADC %3d " | ||
879 | "Value %3d |\n", | ||
880 | i, 4 * j, pdadcValues[4 * j], | ||
881 | 4 * j + 1, pdadcValues[4 * j + 1], | ||
882 | 4 * j + 2, pdadcValues[4 * j + 2], | ||
883 | 4 * j + 3, | ||
884 | pdadcValues[4 * j + 3]); | ||
885 | |||
886 | regOffset += 4; | ||
887 | } | ||
888 | } | ||
889 | } | ||
890 | |||
891 | *pTxPowerIndexOffset = 0; | ||
892 | #undef SM_PD_GAIN | ||
893 | #undef SM_PDGAIN_B | ||
894 | } | ||
895 | |||
896 | static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, | ||
897 | struct ath9k_channel *chan, | ||
898 | int16_t *ratesArray, | ||
899 | u16 cfgCtl, | ||
900 | u16 AntennaReduction, | ||
901 | u16 twiceMaxRegulatoryPower, | ||
902 | u16 powerLimit) | ||
903 | { | ||
904 | #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ | ||
905 | #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ | ||
906 | |||
907 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; | ||
908 | u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
909 | static const u16 tpScaleReductionTable[5] = | ||
910 | { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; | ||
911 | |||
912 | int i; | ||
913 | int16_t twiceLargestAntenna; | ||
914 | struct cal_ctl_data *rep; | ||
915 | struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { | ||
916 | 0, { 0, 0, 0, 0} | ||
917 | }; | ||
918 | struct cal_target_power_leg targetPowerOfdmExt = { | ||
919 | 0, { 0, 0, 0, 0} }, targetPowerCckExt = { | ||
920 | 0, { 0, 0, 0, 0 } | ||
921 | }; | ||
922 | struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { | ||
923 | 0, {0, 0, 0, 0} | ||
924 | }; | ||
925 | u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; | ||
926 | u16 ctlModesFor11a[] = | ||
927 | { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; | ||
928 | u16 ctlModesFor11g[] = | ||
929 | { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, | ||
930 | CTL_2GHT40 | ||
931 | }; | ||
932 | u16 numCtlModes, *pCtlMode, ctlMode, freq; | ||
933 | struct chan_centers centers; | ||
934 | int tx_chainmask; | ||
935 | u16 twiceMinEdgePower; | ||
936 | |||
937 | tx_chainmask = ah->txchainmask; | ||
938 | |||
939 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
940 | |||
941 | twiceLargestAntenna = max( | ||
942 | pEepData->modalHeader | ||
943 | [IS_CHAN_2GHZ(chan)].antennaGainCh[0], | ||
944 | pEepData->modalHeader | ||
945 | [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); | ||
946 | |||
947 | twiceLargestAntenna = max((u8)twiceLargestAntenna, | ||
948 | pEepData->modalHeader | ||
949 | [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); | ||
950 | |||
951 | twiceLargestAntenna = (int16_t)min(AntennaReduction - | ||
952 | twiceLargestAntenna, 0); | ||
953 | |||
954 | maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; | ||
955 | |||
956 | if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { | ||
957 | maxRegAllowedPower -= | ||
958 | (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); | ||
959 | } | ||
960 | |||
961 | scaledPower = min(powerLimit, maxRegAllowedPower); | ||
962 | |||
963 | switch (ar5416_get_ntxchains(tx_chainmask)) { | ||
964 | case 1: | ||
965 | break; | ||
966 | case 2: | ||
967 | scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; | ||
968 | break; | ||
969 | case 3: | ||
970 | scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; | ||
971 | break; | ||
972 | } | ||
973 | |||
974 | scaledPower = max((u16)0, scaledPower); | ||
975 | |||
976 | if (IS_CHAN_2GHZ(chan)) { | ||
977 | numCtlModes = ARRAY_SIZE(ctlModesFor11g) - | ||
978 | SUB_NUM_CTL_MODES_AT_2G_40; | ||
979 | pCtlMode = ctlModesFor11g; | ||
980 | |||
981 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
982 | pEepData->calTargetPowerCck, | ||
983 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
984 | &targetPowerCck, 4, false); | ||
985 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
986 | pEepData->calTargetPower2G, | ||
987 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
988 | &targetPowerOfdm, 4, false); | ||
989 | ath9k_hw_get_target_powers(ah, chan, | ||
990 | pEepData->calTargetPower2GHT20, | ||
991 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
992 | &targetPowerHt20, 8, false); | ||
993 | |||
994 | if (IS_CHAN_HT40(chan)) { | ||
995 | numCtlModes = ARRAY_SIZE(ctlModesFor11g); | ||
996 | ath9k_hw_get_target_powers(ah, chan, | ||
997 | pEepData->calTargetPower2GHT40, | ||
998 | AR5416_NUM_2G_40_TARGET_POWERS, | ||
999 | &targetPowerHt40, 8, true); | ||
1000 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
1001 | pEepData->calTargetPowerCck, | ||
1002 | AR5416_NUM_2G_CCK_TARGET_POWERS, | ||
1003 | &targetPowerCckExt, 4, true); | ||
1004 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
1005 | pEepData->calTargetPower2G, | ||
1006 | AR5416_NUM_2G_20_TARGET_POWERS, | ||
1007 | &targetPowerOfdmExt, 4, true); | ||
1008 | } | ||
1009 | } else { | ||
1010 | numCtlModes = ARRAY_SIZE(ctlModesFor11a) - | ||
1011 | SUB_NUM_CTL_MODES_AT_5G_40; | ||
1012 | pCtlMode = ctlModesFor11a; | ||
1013 | |||
1014 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
1015 | pEepData->calTargetPower5G, | ||
1016 | AR5416_NUM_5G_20_TARGET_POWERS, | ||
1017 | &targetPowerOfdm, 4, false); | ||
1018 | ath9k_hw_get_target_powers(ah, chan, | ||
1019 | pEepData->calTargetPower5GHT20, | ||
1020 | AR5416_NUM_5G_20_TARGET_POWERS, | ||
1021 | &targetPowerHt20, 8, false); | ||
1022 | |||
1023 | if (IS_CHAN_HT40(chan)) { | ||
1024 | numCtlModes = ARRAY_SIZE(ctlModesFor11a); | ||
1025 | ath9k_hw_get_target_powers(ah, chan, | ||
1026 | pEepData->calTargetPower5GHT40, | ||
1027 | AR5416_NUM_5G_40_TARGET_POWERS, | ||
1028 | &targetPowerHt40, 8, true); | ||
1029 | ath9k_hw_get_legacy_target_powers(ah, chan, | ||
1030 | pEepData->calTargetPower5G, | ||
1031 | AR5416_NUM_5G_20_TARGET_POWERS, | ||
1032 | &targetPowerOfdmExt, 4, true); | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { | ||
1037 | bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || | ||
1038 | (pCtlMode[ctlMode] == CTL_2GHT40); | ||
1039 | if (isHt40CtlMode) | ||
1040 | freq = centers.synth_center; | ||
1041 | else if (pCtlMode[ctlMode] & EXT_ADDITIVE) | ||
1042 | freq = centers.ext_center; | ||
1043 | else | ||
1044 | freq = centers.ctl_center; | ||
1045 | |||
1046 | if (ah->eep_ops->get_eeprom_ver(ah) == 14 && | ||
1047 | ah->eep_ops->get_eeprom_rev(ah) <= 2) | ||
1048 | twiceMaxEdgePower = AR5416_MAX_RATE_POWER; | ||
1049 | |||
1050 | for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { | ||
1051 | if ((((cfgCtl & ~CTL_MODE_M) | | ||
1052 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
1053 | pEepData->ctlIndex[i]) || | ||
1054 | (((cfgCtl & ~CTL_MODE_M) | | ||
1055 | (pCtlMode[ctlMode] & CTL_MODE_M)) == | ||
1056 | ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { | ||
1057 | rep = &(pEepData->ctlData[i]); | ||
1058 | |||
1059 | twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, | ||
1060 | rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], | ||
1061 | IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); | ||
1062 | |||
1063 | if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { | ||
1064 | twiceMaxEdgePower = min(twiceMaxEdgePower, | ||
1065 | twiceMinEdgePower); | ||
1066 | } else { | ||
1067 | twiceMaxEdgePower = twiceMinEdgePower; | ||
1068 | break; | ||
1069 | } | ||
1070 | } | ||
1071 | } | ||
1072 | |||
1073 | minCtlPower = min(twiceMaxEdgePower, scaledPower); | ||
1074 | |||
1075 | switch (pCtlMode[ctlMode]) { | ||
1076 | case CTL_11B: | ||
1077 | for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { | ||
1078 | targetPowerCck.tPow2x[i] = | ||
1079 | min((u16)targetPowerCck.tPow2x[i], | ||
1080 | minCtlPower); | ||
1081 | } | ||
1082 | break; | ||
1083 | case CTL_11A: | ||
1084 | case CTL_11G: | ||
1085 | for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { | ||
1086 | targetPowerOfdm.tPow2x[i] = | ||
1087 | min((u16)targetPowerOfdm.tPow2x[i], | ||
1088 | minCtlPower); | ||
1089 | } | ||
1090 | break; | ||
1091 | case CTL_5GHT20: | ||
1092 | case CTL_2GHT20: | ||
1093 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { | ||
1094 | targetPowerHt20.tPow2x[i] = | ||
1095 | min((u16)targetPowerHt20.tPow2x[i], | ||
1096 | minCtlPower); | ||
1097 | } | ||
1098 | break; | ||
1099 | case CTL_11B_EXT: | ||
1100 | targetPowerCckExt.tPow2x[0] = min((u16) | ||
1101 | targetPowerCckExt.tPow2x[0], | ||
1102 | minCtlPower); | ||
1103 | break; | ||
1104 | case CTL_11A_EXT: | ||
1105 | case CTL_11G_EXT: | ||
1106 | targetPowerOfdmExt.tPow2x[0] = min((u16) | ||
1107 | targetPowerOfdmExt.tPow2x[0], | ||
1108 | minCtlPower); | ||
1109 | break; | ||
1110 | case CTL_5GHT40: | ||
1111 | case CTL_2GHT40: | ||
1112 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
1113 | targetPowerHt40.tPow2x[i] = | ||
1114 | min((u16)targetPowerHt40.tPow2x[i], | ||
1115 | minCtlPower); | ||
1116 | } | ||
1117 | break; | ||
1118 | default: | ||
1119 | break; | ||
1120 | } | ||
1121 | } | ||
1122 | |||
1123 | ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = | ||
1124 | ratesArray[rate18mb] = ratesArray[rate24mb] = | ||
1125 | targetPowerOfdm.tPow2x[0]; | ||
1126 | ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; | ||
1127 | ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; | ||
1128 | ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; | ||
1129 | ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; | ||
1130 | |||
1131 | for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) | ||
1132 | ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; | ||
1133 | |||
1134 | if (IS_CHAN_2GHZ(chan)) { | ||
1135 | ratesArray[rate1l] = targetPowerCck.tPow2x[0]; | ||
1136 | ratesArray[rate2s] = ratesArray[rate2l] = | ||
1137 | targetPowerCck.tPow2x[1]; | ||
1138 | ratesArray[rate5_5s] = ratesArray[rate5_5l] = | ||
1139 | targetPowerCck.tPow2x[2]; | ||
1140 | ratesArray[rate11s] = ratesArray[rate11l] = | ||
1141 | targetPowerCck.tPow2x[3]; | ||
1142 | } | ||
1143 | if (IS_CHAN_HT40(chan)) { | ||
1144 | for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { | ||
1145 | ratesArray[rateHt40_0 + i] = | ||
1146 | targetPowerHt40.tPow2x[i]; | ||
1147 | } | ||
1148 | ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; | ||
1149 | ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; | ||
1150 | ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; | ||
1151 | if (IS_CHAN_2GHZ(chan)) { | ||
1152 | ratesArray[rateExtCck] = | ||
1153 | targetPowerCckExt.tPow2x[0]; | ||
1154 | } | ||
1155 | } | ||
1156 | } | ||
1157 | |||
1158 | static void ath9k_hw_def_set_txpower(struct ath_hw *ah, | ||
1159 | struct ath9k_channel *chan, | ||
1160 | u16 cfgCtl, | ||
1161 | u8 twiceAntennaReduction, | ||
1162 | u8 twiceMaxRegulatoryPower, | ||
1163 | u8 powerLimit) | ||
1164 | { | ||
1165 | #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) | ||
1166 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; | ||
1167 | struct modal_eep_header *pModal = | ||
1168 | &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
1169 | int16_t ratesArray[Ar5416RateSize]; | ||
1170 | int16_t txPowerIndexOffset = 0; | ||
1171 | u8 ht40PowerIncForPdadc = 2; | ||
1172 | int i, cck_ofdm_delta = 0; | ||
1173 | |||
1174 | memset(ratesArray, 0, sizeof(ratesArray)); | ||
1175 | |||
1176 | if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | ||
1177 | AR5416_EEP_MINOR_VER_2) { | ||
1178 | ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; | ||
1179 | } | ||
1180 | |||
1181 | ath9k_hw_set_def_power_per_rate_table(ah, chan, | ||
1182 | &ratesArray[0], cfgCtl, | ||
1183 | twiceAntennaReduction, | ||
1184 | twiceMaxRegulatoryPower, | ||
1185 | powerLimit); | ||
1186 | |||
1187 | ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset); | ||
1188 | |||
1189 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | ||
1190 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
1191 | if (ratesArray[i] > AR5416_MAX_RATE_POWER) | ||
1192 | ratesArray[i] = AR5416_MAX_RATE_POWER; | ||
1193 | } | ||
1194 | |||
1195 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
1196 | for (i = 0; i < Ar5416RateSize; i++) | ||
1197 | ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; | ||
1198 | } | ||
1199 | |||
1200 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, | ||
1201 | ATH9K_POW_SM(ratesArray[rate18mb], 24) | ||
1202 | | ATH9K_POW_SM(ratesArray[rate12mb], 16) | ||
1203 | | ATH9K_POW_SM(ratesArray[rate9mb], 8) | ||
1204 | | ATH9K_POW_SM(ratesArray[rate6mb], 0)); | ||
1205 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, | ||
1206 | ATH9K_POW_SM(ratesArray[rate54mb], 24) | ||
1207 | | ATH9K_POW_SM(ratesArray[rate48mb], 16) | ||
1208 | | ATH9K_POW_SM(ratesArray[rate36mb], 8) | ||
1209 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); | ||
1210 | |||
1211 | if (IS_CHAN_2GHZ(chan)) { | ||
1212 | if (OLC_FOR_AR9280_20_LATER) { | ||
1213 | cck_ofdm_delta = 2; | ||
1214 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
1215 | ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24) | ||
1216 | | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16) | ||
1217 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
1218 | | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0)); | ||
1219 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
1220 | ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24) | ||
1221 | | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16) | ||
1222 | | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8) | ||
1223 | | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0)); | ||
1224 | } else { | ||
1225 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
1226 | ATH9K_POW_SM(ratesArray[rate2s], 24) | ||
1227 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | ||
1228 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
1229 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | ||
1230 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
1231 | ATH9K_POW_SM(ratesArray[rate11s], 24) | ||
1232 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | ||
1233 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | ||
1234 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | ||
1235 | } | ||
1236 | } | ||
1237 | |||
1238 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, | ||
1239 | ATH9K_POW_SM(ratesArray[rateHt20_3], 24) | ||
1240 | | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) | ||
1241 | | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) | ||
1242 | | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); | ||
1243 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, | ||
1244 | ATH9K_POW_SM(ratesArray[rateHt20_7], 24) | ||
1245 | | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) | ||
1246 | | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) | ||
1247 | | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); | ||
1248 | |||
1249 | if (IS_CHAN_HT40(chan)) { | ||
1250 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, | ||
1251 | ATH9K_POW_SM(ratesArray[rateHt40_3] + | ||
1252 | ht40PowerIncForPdadc, 24) | ||
1253 | | ATH9K_POW_SM(ratesArray[rateHt40_2] + | ||
1254 | ht40PowerIncForPdadc, 16) | ||
1255 | | ATH9K_POW_SM(ratesArray[rateHt40_1] + | ||
1256 | ht40PowerIncForPdadc, 8) | ||
1257 | | ATH9K_POW_SM(ratesArray[rateHt40_0] + | ||
1258 | ht40PowerIncForPdadc, 0)); | ||
1259 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, | ||
1260 | ATH9K_POW_SM(ratesArray[rateHt40_7] + | ||
1261 | ht40PowerIncForPdadc, 24) | ||
1262 | | ATH9K_POW_SM(ratesArray[rateHt40_6] + | ||
1263 | ht40PowerIncForPdadc, 16) | ||
1264 | | ATH9K_POW_SM(ratesArray[rateHt40_5] + | ||
1265 | ht40PowerIncForPdadc, 8) | ||
1266 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + | ||
1267 | ht40PowerIncForPdadc, 0)); | ||
1268 | if (OLC_FOR_AR9280_20_LATER) { | ||
1269 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
1270 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
1271 | | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16) | ||
1272 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
1273 | | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0)); | ||
1274 | } else { | ||
1275 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
1276 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
1277 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ||
1278 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
1279 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | ||
1280 | } | ||
1281 | } | ||
1282 | |||
1283 | REG_WRITE(ah, AR_PHY_POWER_TX_SUB, | ||
1284 | ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) | ||
1285 | | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); | ||
1286 | |||
1287 | i = rate6mb; | ||
1288 | |||
1289 | if (IS_CHAN_HT40(chan)) | ||
1290 | i = rateHt40_0; | ||
1291 | else if (IS_CHAN_HT20(chan)) | ||
1292 | i = rateHt20_0; | ||
1293 | |||
1294 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
1295 | ah->regulatory.max_power_level = | ||
1296 | ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; | ||
1297 | else | ||
1298 | ah->regulatory.max_power_level = ratesArray[i]; | ||
1299 | |||
1300 | switch(ar5416_get_ntxchains(ah->txchainmask)) { | ||
1301 | case 1: | ||
1302 | break; | ||
1303 | case 2: | ||
1304 | ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; | ||
1305 | break; | ||
1306 | case 3: | ||
1307 | ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; | ||
1308 | break; | ||
1309 | default: | ||
1310 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
1311 | "Invalid chainmask configuration\n"); | ||
1312 | break; | ||
1313 | } | ||
1314 | } | ||
1315 | |||
1316 | static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, | ||
1317 | enum ieee80211_band freq_band) | ||
1318 | { | ||
1319 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
1320 | struct modal_eep_header *pModal = | ||
1321 | &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]); | ||
1322 | struct base_eep_header *pBase = &eep->baseEepHeader; | ||
1323 | u8 num_ant_config; | ||
1324 | |||
1325 | num_ant_config = 1; | ||
1326 | |||
1327 | if (pBase->version >= 0x0E0D) | ||
1328 | if (pModal->useAnt1) | ||
1329 | num_ant_config += 1; | ||
1330 | |||
1331 | return num_ant_config; | ||
1332 | } | ||
1333 | |||
1334 | static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah, | ||
1335 | struct ath9k_channel *chan) | ||
1336 | { | ||
1337 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
1338 | struct modal_eep_header *pModal = | ||
1339 | &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); | ||
1340 | |||
1341 | return pModal->antCtrlCommon & 0xFFFF; | ||
1342 | } | ||
1343 | |||
1344 | static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) | ||
1345 | { | ||
1346 | #define EEP_DEF_SPURCHAN \ | ||
1347 | (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) | ||
1348 | |||
1349 | u16 spur_val = AR_NO_SPUR; | ||
1350 | |||
1351 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1352 | "Getting spur idx %d is2Ghz. %d val %x\n", | ||
1353 | i, is2GHz, ah->config.spurchans[i][is2GHz]); | ||
1354 | |||
1355 | switch (ah->config.spurmode) { | ||
1356 | case SPUR_DISABLE: | ||
1357 | break; | ||
1358 | case SPUR_ENABLE_IOCTL: | ||
1359 | spur_val = ah->config.spurchans[i][is2GHz]; | ||
1360 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, | ||
1361 | "Getting spur val from new loc. %d\n", spur_val); | ||
1362 | break; | ||
1363 | case SPUR_ENABLE_EEPROM: | ||
1364 | spur_val = EEP_DEF_SPURCHAN; | ||
1365 | break; | ||
1366 | } | ||
1367 | |||
1368 | return spur_val; | ||
1369 | |||
1370 | #undef EEP_DEF_SPURCHAN | ||
1371 | } | ||
1372 | |||
1373 | const struct eeprom_ops eep_def_ops = { | ||
1374 | .check_eeprom = ath9k_hw_def_check_eeprom, | ||
1375 | .get_eeprom = ath9k_hw_def_get_eeprom, | ||
1376 | .fill_eeprom = ath9k_hw_def_fill_eeprom, | ||
1377 | .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver, | ||
1378 | .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev, | ||
1379 | .get_num_ant_config = ath9k_hw_def_get_num_ant_config, | ||
1380 | .get_eeprom_antenna_cfg = ath9k_hw_def_get_eeprom_antenna_cfg, | ||
1381 | .set_board_values = ath9k_hw_def_set_board_values, | ||
1382 | .set_addac = ath9k_hw_def_set_addac, | ||
1383 | .set_txpower = ath9k_hw_def_set_txpower, | ||
1384 | .get_spur_channel = ath9k_hw_def_get_spur_channel | ||
1385 | }; | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 71a3bcc450a2..9f1b34d9861a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -407,7 +407,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah) | |||
407 | ah->config.cck_trig_high = 200; | 407 | ah->config.cck_trig_high = 200; |
408 | ah->config.cck_trig_low = 100; | 408 | ah->config.cck_trig_low = 100; |
409 | ah->config.enable_ani = 1; | 409 | ah->config.enable_ani = 1; |
410 | ah->config.diversity_control = 0; | 410 | ah->config.diversity_control = ATH9K_ANT_VARIABLE; |
411 | ah->config.antenna_switch_swap = 0; | 411 | ah->config.antenna_switch_swap = 0; |
412 | 412 | ||
413 | for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { | 413 | for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { |
@@ -452,9 +452,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) | |||
452 | ah->regulatory.power_limit = MAX_RATE_POWER; | 452 | ah->regulatory.power_limit = MAX_RATE_POWER; |
453 | ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX; | 453 | ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX; |
454 | ah->atim_window = 0; | 454 | ah->atim_window = 0; |
455 | ah->diversity_control = ah->config.diversity_control; | ||
456 | ah->antenna_switch_swap = | ||
457 | ah->config.antenna_switch_swap; | ||
458 | ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE; | 455 | ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE; |
459 | ah->beacon_interval = 100; | 456 | ah->beacon_interval = 100; |
460 | ah->enable_32kHz_clock = DONT_USE_32KHZ; | 457 | ah->enable_32kHz_clock = DONT_USE_32KHZ; |
@@ -3891,7 +3888,7 @@ bool ath9k_hw_setantennaswitch(struct ath_hw *ah, | |||
3891 | break; | 3888 | break; |
3892 | } | 3889 | } |
3893 | } else { | 3890 | } else { |
3894 | ah->diversity_control = settings; | 3891 | ah->config.diversity_control = settings; |
3895 | } | 3892 | } |
3896 | 3893 | ||
3897 | return true; | 3894 | return true; |
@@ -4019,14 +4016,12 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah) | |||
4019 | ath9k_ps_restore(ah->ah_sc); | 4016 | ath9k_ps_restore(ah->ah_sc); |
4020 | } | 4017 | } |
4021 | 4018 | ||
4022 | bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) | 4019 | void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) |
4023 | { | 4020 | { |
4024 | if (setting) | 4021 | if (setting) |
4025 | ah->misc_mode |= AR_PCU_TX_ADD_TSF; | 4022 | ah->misc_mode |= AR_PCU_TX_ADD_TSF; |
4026 | else | 4023 | else |
4027 | ah->misc_mode &= ~AR_PCU_TX_ADD_TSF; | 4024 | ah->misc_mode &= ~AR_PCU_TX_ADD_TSF; |
4028 | |||
4029 | return true; | ||
4030 | } | 4025 | } |
4031 | 4026 | ||
4032 | bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) | 4027 | bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index d4aaf4f8db29..0336981a70ec 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -127,6 +127,12 @@ enum wireless_mode { | |||
127 | ATH9K_MODE_MAX, | 127 | ATH9K_MODE_MAX, |
128 | }; | 128 | }; |
129 | 129 | ||
130 | enum ath9k_ant_setting { | ||
131 | ATH9K_ANT_VARIABLE = 0, | ||
132 | ATH9K_ANT_FIXED_A, | ||
133 | ATH9K_ANT_FIXED_B | ||
134 | }; | ||
135 | |||
130 | enum ath9k_hw_caps { | 136 | enum ath9k_hw_caps { |
131 | ATH9K_HW_CAP_MIC_AESCCM = BIT(0), | 137 | ATH9K_HW_CAP_MIC_AESCCM = BIT(0), |
132 | ATH9K_HW_CAP_MIC_CKIP = BIT(1), | 138 | ATH9K_HW_CAP_MIC_CKIP = BIT(1), |
@@ -191,7 +197,7 @@ struct ath9k_ops_config { | |||
191 | u32 cck_trig_high; | 197 | u32 cck_trig_high; |
192 | u32 cck_trig_low; | 198 | u32 cck_trig_low; |
193 | u32 enable_ani; | 199 | u32 enable_ani; |
194 | u16 diversity_control; | 200 | enum ath9k_ant_setting diversity_control; |
195 | u16 antenna_switch_swap; | 201 | u16 antenna_switch_swap; |
196 | int serialize_regmode; | 202 | int serialize_regmode; |
197 | bool intr_mitigation; | 203 | bool intr_mitigation; |
@@ -330,12 +336,6 @@ enum ath9k_power_mode { | |||
330 | ATH9K_PM_UNDEFINED | 336 | ATH9K_PM_UNDEFINED |
331 | }; | 337 | }; |
332 | 338 | ||
333 | enum ath9k_ant_setting { | ||
334 | ATH9K_ANT_VARIABLE = 0, | ||
335 | ATH9K_ANT_FIXED_A, | ||
336 | ATH9K_ANT_FIXED_B | ||
337 | }; | ||
338 | |||
339 | enum ath9k_tp_scale { | 339 | enum ath9k_tp_scale { |
340 | ATH9K_TP_SCALE_MAX = 0, | 340 | ATH9K_TP_SCALE_MAX = 0, |
341 | ATH9K_TP_SCALE_50, | 341 | ATH9K_TP_SCALE_50, |
@@ -437,8 +437,6 @@ struct ath_hw { | |||
437 | u32 txurn_interrupt_mask; | 437 | u32 txurn_interrupt_mask; |
438 | bool chip_fullsleep; | 438 | bool chip_fullsleep; |
439 | u32 atim_window; | 439 | u32 atim_window; |
440 | u16 antenna_switch_swap; | ||
441 | enum ath9k_ant_setting diversity_control; | ||
442 | 440 | ||
443 | /* Calibration */ | 441 | /* Calibration */ |
444 | enum ath9k_cal_types supp_cals; | 442 | enum ath9k_cal_types supp_cals; |
@@ -507,7 +505,6 @@ struct ath_hw { | |||
507 | 505 | ||
508 | /* ANI */ | 506 | /* ANI */ |
509 | u32 proc_phyerr; | 507 | u32 proc_phyerr; |
510 | bool has_hw_phycounters; | ||
511 | u32 aniperiod; | 508 | u32 aniperiod; |
512 | struct ar5416AniState *curani; | 509 | struct ar5416AniState *curani; |
513 | struct ar5416AniState ani[255]; | 510 | struct ar5416AniState ani[255]; |
@@ -601,7 +598,7 @@ void ath9k_hw_write_associd(struct ath_softc *sc); | |||
601 | u64 ath9k_hw_gettsf64(struct ath_hw *ah); | 598 | u64 ath9k_hw_gettsf64(struct ath_hw *ah); |
602 | void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); | 599 | void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); |
603 | void ath9k_hw_reset_tsf(struct ath_hw *ah); | 600 | void ath9k_hw_reset_tsf(struct ath_hw *ah); |
604 | bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); | 601 | void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); |
605 | bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); | 602 | bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); |
606 | void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode); | 603 | void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode); |
607 | void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); | 604 | void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); |
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 6f923e318727..800bfab94635 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c | |||
@@ -40,20 +40,15 @@ u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q) | |||
40 | return REG_READ(ah, AR_QTXDP(q)); | 40 | return REG_READ(ah, AR_QTXDP(q)); |
41 | } | 41 | } |
42 | 42 | ||
43 | bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) | 43 | void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) |
44 | { | 44 | { |
45 | REG_WRITE(ah, AR_QTXDP(q), txdp); | 45 | REG_WRITE(ah, AR_QTXDP(q), txdp); |
46 | |||
47 | return true; | ||
48 | } | 46 | } |
49 | 47 | ||
50 | bool ath9k_hw_txstart(struct ath_hw *ah, u32 q) | 48 | void ath9k_hw_txstart(struct ath_hw *ah, u32 q) |
51 | { | 49 | { |
52 | DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q); | 50 | DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q); |
53 | |||
54 | REG_WRITE(ah, AR_Q_TXE, 1 << q); | 51 | REG_WRITE(ah, AR_Q_TXE, 1 << q); |
55 | |||
56 | return true; | ||
57 | } | 52 | } |
58 | 53 | ||
59 | u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q) | 54 | u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q) |
@@ -178,7 +173,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) | |||
178 | #undef ATH9K_TIME_QUANTUM | 173 | #undef ATH9K_TIME_QUANTUM |
179 | } | 174 | } |
180 | 175 | ||
181 | bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, | 176 | void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, |
182 | u32 segLen, bool firstSeg, | 177 | u32 segLen, bool firstSeg, |
183 | bool lastSeg, const struct ath_desc *ds0) | 178 | bool lastSeg, const struct ath_desc *ds0) |
184 | { | 179 | { |
@@ -202,8 +197,6 @@ bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, | |||
202 | ads->ds_txstatus4 = ads->ds_txstatus5 = 0; | 197 | ads->ds_txstatus4 = ads->ds_txstatus5 = 0; |
203 | ads->ds_txstatus6 = ads->ds_txstatus7 = 0; | 198 | ads->ds_txstatus6 = ads->ds_txstatus7 = 0; |
204 | ads->ds_txstatus8 = ads->ds_txstatus9 = 0; | 199 | ads->ds_txstatus8 = ads->ds_txstatus9 = 0; |
205 | |||
206 | return true; | ||
207 | } | 200 | } |
208 | 201 | ||
209 | void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds) | 202 | void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds) |
@@ -888,7 +881,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, | |||
888 | return 0; | 881 | return 0; |
889 | } | 882 | } |
890 | 883 | ||
891 | bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, | 884 | void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, |
892 | u32 size, u32 flags) | 885 | u32 size, u32 flags) |
893 | { | 886 | { |
894 | struct ar5416_desc *ads = AR5416DESC(ds); | 887 | struct ar5416_desc *ads = AR5416DESC(ds); |
@@ -901,8 +894,6 @@ bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, | |||
901 | ads->ds_rxstatus8 &= ~AR_RxDone; | 894 | ads->ds_rxstatus8 &= ~AR_RxDone; |
902 | if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) | 895 | if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) |
903 | memset(&(ads->u), 0, sizeof(ads->u)); | 896 | memset(&(ads->u), 0, sizeof(ads->u)); |
904 | |||
905 | return true; | ||
906 | } | 897 | } |
907 | 898 | ||
908 | bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) | 899 | bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) |
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 1176bce8b76c..7b3982295a43 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h | |||
@@ -628,12 +628,12 @@ struct ath9k_channel; | |||
628 | struct ath_rate_table; | 628 | struct ath_rate_table; |
629 | 629 | ||
630 | u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); | 630 | u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); |
631 | bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); | 631 | void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); |
632 | bool ath9k_hw_txstart(struct ath_hw *ah, u32 q); | 632 | void ath9k_hw_txstart(struct ath_hw *ah, u32 q); |
633 | u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); | 633 | u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); |
634 | bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); | 634 | bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); |
635 | bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q); | 635 | bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q); |
636 | bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, | 636 | void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, |
637 | u32 segLen, bool firstSeg, | 637 | u32 segLen, bool firstSeg, |
638 | bool lastSeg, const struct ath_desc *ds0); | 638 | bool lastSeg, const struct ath_desc *ds0); |
639 | void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds); | 639 | void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds); |
@@ -668,7 +668,7 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q); | |||
668 | bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q); | 668 | bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q); |
669 | int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, | 669 | int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, |
670 | u32 pa, struct ath_desc *nds, u64 tsf); | 670 | u32 pa, struct ath_desc *nds, u64 tsf); |
671 | bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, | 671 | void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, |
672 | u32 size, u32 flags); | 672 | u32 size, u32 flags); |
673 | bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); | 673 | bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); |
674 | void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp); | 674 | void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp); |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a9e43f7a23f6..fa4c6e74f977 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -1327,7 +1327,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) | |||
1327 | */ | 1327 | */ |
1328 | ath_read_cachesize(sc, &csz); | 1328 | ath_read_cachesize(sc, &csz); |
1329 | /* XXX assert csz is non-zero */ | 1329 | /* XXX assert csz is non-zero */ |
1330 | sc->cachelsz = csz << 2; /* convert to bytes */ | 1330 | sc->common.cachelsz = csz << 2; /* convert to bytes */ |
1331 | 1331 | ||
1332 | ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); | 1332 | ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); |
1333 | if (!ah) { | 1333 | if (!ah) { |
@@ -2140,6 +2140,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
2140 | /* disable HAL and put h/w to sleep */ | 2140 | /* disable HAL and put h/w to sleep */ |
2141 | ath9k_hw_disable(sc->sc_ah); | 2141 | ath9k_hw_disable(sc->sc_ah); |
2142 | ath9k_hw_configpcipowersave(sc->sc_ah, 1); | 2142 | ath9k_hw_configpcipowersave(sc->sc_ah, 1); |
2143 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); | ||
2143 | 2144 | ||
2144 | sc->sc_flags |= SC_OP_INVALID; | 2145 | sc->sc_flags |= SC_OP_INVALID; |
2145 | 2146 | ||
@@ -2214,8 +2215,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
2214 | if ((conf->type == NL80211_IFTYPE_STATION) || | 2215 | if ((conf->type == NL80211_IFTYPE_STATION) || |
2215 | (conf->type == NL80211_IFTYPE_ADHOC) || | 2216 | (conf->type == NL80211_IFTYPE_ADHOC) || |
2216 | (conf->type == NL80211_IFTYPE_MESH_POINT)) { | 2217 | (conf->type == NL80211_IFTYPE_MESH_POINT)) { |
2217 | if (ath9k_hw_phycounters(sc->sc_ah)) | 2218 | sc->imask |= ATH9K_INT_MIB; |
2218 | sc->imask |= ATH9K_INT_MIB; | ||
2219 | sc->imask |= ATH9K_INT_TSFOOR; | 2219 | sc->imask |= ATH9K_INT_TSFOOR; |
2220 | } | 2220 | } |
2221 | 2221 | ||
@@ -2380,6 +2380,7 @@ skip_chan_change: | |||
2380 | (FIF_PROMISC_IN_BSS | \ | 2380 | (FIF_PROMISC_IN_BSS | \ |
2381 | FIF_ALLMULTI | \ | 2381 | FIF_ALLMULTI | \ |
2382 | FIF_CONTROL | \ | 2382 | FIF_CONTROL | \ |
2383 | FIF_PSPOLL | \ | ||
2383 | FIF_OTHER_BSS | \ | 2384 | FIF_OTHER_BSS | \ |
2384 | FIF_BCN_PRBRESP_PROMISC | \ | 2385 | FIF_BCN_PRBRESP_PROMISC | \ |
2385 | FIF_FCSFAIL) | 2386 | FIF_FCSFAIL) |
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 3546504a83c4..616bdff2b6a1 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c | |||
@@ -253,10 +253,12 @@ static int ath_pci_resume(struct pci_dev *pdev) | |||
253 | u32 val; | 253 | u32 val; |
254 | int err; | 254 | int err; |
255 | 255 | ||
256 | pci_restore_state(pdev); | ||
257 | |||
256 | err = pci_enable_device(pdev); | 258 | err = pci_enable_device(pdev); |
257 | if (err) | 259 | if (err) |
258 | return err; | 260 | return err; |
259 | pci_restore_state(pdev); | 261 | |
260 | /* | 262 | /* |
261 | * Suspend/Resume resets the PCI configuration space, so we have to | 263 | * Suspend/Resume resets the PCI configuration space, so we have to |
262 | * re-disable the RETRY_TIMEOUT register (0x41) to keep | 264 | * re-disable the RETRY_TIMEOUT register (0x41) to keep |
diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 59bb3ce1e646..63bf9a307c6a 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c | |||
@@ -353,18 +353,16 @@ ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan) | |||
353 | u32 bank6SelMask; | 353 | u32 bank6SelMask; |
354 | u32 *bank6Temp = ah->bank6Temp; | 354 | u32 *bank6Temp = ah->bank6Temp; |
355 | 355 | ||
356 | switch (ah->diversity_control) { | 356 | switch (ah->config.diversity_control) { |
357 | case ATH9K_ANT_FIXED_A: | 357 | case ATH9K_ANT_FIXED_A: |
358 | bank6SelMask = | 358 | bank6SelMask = |
359 | (ah-> | 359 | (ah->config.antenna_switch_swap & ANTSWAP_AB) ? |
360 | antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_0 : | 360 | REDUCE_CHAIN_0 : REDUCE_CHAIN_1; |
361 | REDUCE_CHAIN_1; | ||
362 | break; | 361 | break; |
363 | case ATH9K_ANT_FIXED_B: | 362 | case ATH9K_ANT_FIXED_B: |
364 | bank6SelMask = | 363 | bank6SelMask = |
365 | (ah-> | 364 | (ah->config.antenna_switch_swap & ANTSWAP_AB) ? |
366 | antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_1 : | 365 | REDUCE_CHAIN_1 : REDUCE_CHAIN_0; |
367 | REDUCE_CHAIN_0; | ||
368 | break; | 366 | break; |
369 | case ATH9K_ANT_VARIABLE: | 367 | case ATH9K_ANT_VARIABLE: |
370 | return; | 368 | return; |
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 27bd93c6e74d..e83cd4ab87f0 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h | |||
@@ -312,7 +312,25 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, | |||
312 | #define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12)) | 312 | #define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12)) |
313 | #define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000 | 313 | #define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000 |
314 | #define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000 | 314 | #define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000 |
315 | #define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac | 315 | |
316 | #define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac | ||
317 | #define AR_PHY_9285_ANT_DIV_CTL_ALL 0x7f000000 | ||
318 | #define AR_PHY_9285_ANT_DIV_CTL 0x01000000 | ||
319 | #define AR_PHY_9285_ANT_DIV_CTL_S 24 | ||
320 | #define AR_PHY_9285_ANT_DIV_ALT_LNACONF 0x06000000 | ||
321 | #define AR_PHY_9285_ANT_DIV_ALT_LNACONF_S 25 | ||
322 | #define AR_PHY_9285_ANT_DIV_MAIN_LNACONF 0x18000000 | ||
323 | #define AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S 27 | ||
324 | #define AR_PHY_9285_ANT_DIV_ALT_GAINTB 0x20000000 | ||
325 | #define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S 29 | ||
326 | #define AR_PHY_9285_ANT_DIV_MAIN_GAINTB 0x40000000 | ||
327 | #define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S 30 | ||
328 | #define AR_PHY_9285_ANT_DIV_LNA1 2 | ||
329 | #define AR_PHY_9285_ANT_DIV_LNA2 1 | ||
330 | #define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2 3 | ||
331 | #define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0 | ||
332 | #define AR_PHY_9285_ANT_DIV_GAINTB_0 0 | ||
333 | #define AR_PHY_9285_ANT_DIV_GAINTB_1 1 | ||
316 | 334 | ||
317 | #define AR_PHY_EXT_CCA0 0x99b8 | 335 | #define AR_PHY_EXT_CCA0 0x99b8 |
318 | #define AR_PHY_EXT_CCA0_THRESH62 0x000000FF | 336 | #define AR_PHY_EXT_CCA0_THRESH62 0x000000FF |
@@ -401,6 +419,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, | |||
401 | #define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0 | 419 | #define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0 |
402 | #define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6 | 420 | #define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6 |
403 | #define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000 | 421 | #define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000 |
422 | #define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S 13 | ||
404 | 423 | ||
405 | #define AR_PHY_GAIN_2GHZ 0xA20C | 424 | #define AR_PHY_GAIN_2GHZ 0xA20C |
406 | #define AR_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00FC0000 | 425 | #define AR_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00FC0000 |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 61edfab20ffc..61dbdd227444 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -100,38 +100,6 @@ static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) | |||
100 | return (tsf & ~0x7fff) | rstamp; | 100 | return (tsf & ~0x7fff) | rstamp; |
101 | } | 101 | } |
102 | 102 | ||
103 | static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len, gfp_t gfp_mask) | ||
104 | { | ||
105 | struct sk_buff *skb; | ||
106 | u32 off; | ||
107 | |||
108 | /* | ||
109 | * Cache-line-align. This is important (for the | ||
110 | * 5210 at least) as not doing so causes bogus data | ||
111 | * in rx'd frames. | ||
112 | */ | ||
113 | |||
114 | /* Note: the kernel can allocate a value greater than | ||
115 | * what we ask it to give us. We really only need 4 KB as that | ||
116 | * is this hardware supports and in fact we need at least 3849 | ||
117 | * as that is the MAX AMSDU size this hardware supports. | ||
118 | * Unfortunately this means we may get 8 KB here from the | ||
119 | * kernel... and that is actually what is observed on some | ||
120 | * systems :( */ | ||
121 | skb = __dev_alloc_skb(len + sc->cachelsz - 1, gfp_mask); | ||
122 | if (skb != NULL) { | ||
123 | off = ((unsigned long) skb->data) % sc->cachelsz; | ||
124 | if (off != 0) | ||
125 | skb_reserve(skb, sc->cachelsz - off); | ||
126 | } else { | ||
127 | DPRINTF(sc, ATH_DBG_FATAL, | ||
128 | "skbuff alloc of size %u failed\n", len); | ||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | return skb; | ||
133 | } | ||
134 | |||
135 | /* | 103 | /* |
136 | * For Decrypt or Demic errors, we only mark packet status here and always push | 104 | * For Decrypt or Demic errors, we only mark packet status here and always push |
137 | * up the frame up to let mac80211 handle the actual error case, be it no | 105 | * up the frame up to let mac80211 handle the actual error case, be it no |
@@ -252,6 +220,10 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, | |||
252 | else if (ds->ds_rxstat.rs_rssi > 127) | 220 | else if (ds->ds_rxstat.rs_rssi > 127) |
253 | ds->ds_rxstat.rs_rssi = 127; | 221 | ds->ds_rxstat.rs_rssi = 127; |
254 | 222 | ||
223 | /* Update Beacon RSSI, this is used by ANI. */ | ||
224 | if (ieee80211_is_beacon(fc)) | ||
225 | sc->nodestats.ns_avgbrssi = ds->ds_rxstat.rs_rssi; | ||
226 | |||
255 | rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); | 227 | rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); |
256 | rx_status->band = hw->conf.channel->band; | 228 | rx_status->band = hw->conf.channel->band; |
257 | rx_status->freq = hw->conf.channel->center_freq; | 229 | rx_status->freq = hw->conf.channel->center_freq; |
@@ -332,10 +304,10 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) | |||
332 | spin_lock_init(&sc->rx.rxbuflock); | 304 | spin_lock_init(&sc->rx.rxbuflock); |
333 | 305 | ||
334 | sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, | 306 | sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, |
335 | min(sc->cachelsz, (u16)64)); | 307 | min(sc->common.cachelsz, (u16)64)); |
336 | 308 | ||
337 | DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", | 309 | DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", |
338 | sc->cachelsz, sc->rx.bufsize); | 310 | sc->common.cachelsz, sc->rx.bufsize); |
339 | 311 | ||
340 | /* Initialize rx descriptors */ | 312 | /* Initialize rx descriptors */ |
341 | 313 | ||
@@ -348,7 +320,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) | |||
348 | } | 320 | } |
349 | 321 | ||
350 | list_for_each_entry(bf, &sc->rx.rxbuf, list) { | 322 | list_for_each_entry(bf, &sc->rx.rxbuf, list) { |
351 | skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL); | 323 | skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_KERNEL); |
352 | if (skb == NULL) { | 324 | if (skb == NULL) { |
353 | error = -ENOMEM; | 325 | error = -ENOMEM; |
354 | goto err; | 326 | goto err; |
@@ -448,8 +420,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) | |||
448 | else | 420 | else |
449 | rfilt |= ATH9K_RX_FILTER_BEACON; | 421 | rfilt |= ATH9K_RX_FILTER_BEACON; |
450 | 422 | ||
451 | /* If in HOSTAP mode, want to enable reception of PSPOLL frames */ | 423 | if (sc->rx.rxfilter & FIF_PSPOLL) |
452 | if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) | ||
453 | rfilt |= ATH9K_RX_FILTER_PSPOLL; | 424 | rfilt |= ATH9K_RX_FILTER_PSPOLL; |
454 | 425 | ||
455 | if (sc->sec_wiphy) { | 426 | if (sc->sec_wiphy) { |
@@ -774,7 +745,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
774 | 745 | ||
775 | /* Ensure we always have an skb to requeue once we are done | 746 | /* Ensure we always have an skb to requeue once we are done |
776 | * processing the current buffer's skb */ | 747 | * processing the current buffer's skb */ |
777 | requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_ATOMIC); | 748 | requeue_skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_ATOMIC); |
778 | 749 | ||
779 | /* If there is no memory we ignore the current RX'd frame, | 750 | /* If there is no memory we ignore the current RX'd frame, |
780 | * tell hardware it can give us a new frame using the old | 751 | * tell hardware it can give us a new frame using the old |
@@ -789,7 +760,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
789 | DMA_FROM_DEVICE); | 760 | DMA_FROM_DEVICE); |
790 | 761 | ||
791 | skb_put(skb, ds->ds_rxstat.rs_datalen); | 762 | skb_put(skb, ds->ds_rxstat.rs_datalen); |
792 | skb->protocol = cpu_to_be16(ETH_P_CONTROL); | ||
793 | 763 | ||
794 | /* see if any padding is done by the hw and remove it */ | 764 | /* see if any padding is done by the hw and remove it */ |
795 | hdr = (struct ieee80211_hdr *)skb->data; | 765 | hdr = (struct ieee80211_hdr *)skb->data; |
diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c index 9949b11cb151..487193f1de1a 100644 --- a/drivers/net/wireless/ath/main.c +++ b/drivers/net/wireless/ath/main.c | |||
@@ -17,6 +17,42 @@ | |||
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | 19 | ||
20 | #include "ath.h" | ||
21 | |||
20 | MODULE_AUTHOR("Atheros Communications"); | 22 | MODULE_AUTHOR("Atheros Communications"); |
21 | MODULE_DESCRIPTION("Shared library for Atheros wireless LAN cards."); | 23 | MODULE_DESCRIPTION("Shared library for Atheros wireless LAN cards."); |
22 | MODULE_LICENSE("Dual BSD/GPL"); | 24 | MODULE_LICENSE("Dual BSD/GPL"); |
25 | |||
26 | struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, | ||
27 | u32 len, | ||
28 | gfp_t gfp_mask) | ||
29 | { | ||
30 | struct sk_buff *skb; | ||
31 | u32 off; | ||
32 | |||
33 | /* | ||
34 | * Cache-line-align. This is important (for the | ||
35 | * 5210 at least) as not doing so causes bogus data | ||
36 | * in rx'd frames. | ||
37 | */ | ||
38 | |||
39 | /* Note: the kernel can allocate a value greater than | ||
40 | * what we ask it to give us. We really only need 4 KB as that | ||
41 | * is this hardware supports and in fact we need at least 3849 | ||
42 | * as that is the MAX AMSDU size this hardware supports. | ||
43 | * Unfortunately this means we may get 8 KB here from the | ||
44 | * kernel... and that is actually what is observed on some | ||
45 | * systems :( */ | ||
46 | skb = __dev_alloc_skb(len + common->cachelsz - 1, gfp_mask); | ||
47 | if (skb != NULL) { | ||
48 | off = ((unsigned long) skb->data) % common->cachelsz; | ||
49 | if (off != 0) | ||
50 | skb_reserve(skb, common->cachelsz - off); | ||
51 | } else { | ||
52 | printk(KERN_ERR "skbuff alloc of size %u failed\n", len); | ||
53 | return NULL; | ||
54 | } | ||
55 | |||
56 | return skb; | ||
57 | } | ||
58 | EXPORT_SYMBOL(ath_rxbuf_alloc); | ||
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index b6811cff18ba..a1b3b731935b 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -493,6 +493,10 @@ enum { | |||
493 | 493 | ||
494 | /* Max size of a security key */ | 494 | /* Max size of a security key */ |
495 | #define B43_SEC_KEYSIZE 16 | 495 | #define B43_SEC_KEYSIZE 16 |
496 | /* Max number of group keys */ | ||
497 | #define B43_NR_GROUP_KEYS 4 | ||
498 | /* Max number of pairwise keys */ | ||
499 | #define B43_NR_PAIRWISE_KEYS 50 | ||
496 | /* Security algorithms. */ | 500 | /* Security algorithms. */ |
497 | enum { | 501 | enum { |
498 | B43_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */ | 502 | B43_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */ |
@@ -639,7 +643,7 @@ struct b43_wl { | |||
639 | u8 mac_addr[ETH_ALEN]; | 643 | u8 mac_addr[ETH_ALEN]; |
640 | /* Current BSSID */ | 644 | /* Current BSSID */ |
641 | u8 bssid[ETH_ALEN]; | 645 | u8 bssid[ETH_ALEN]; |
642 | /* Interface type. (IEEE80211_IF_TYPE_XXX) */ | 646 | /* Interface type. (NL80211_IFTYPE_XXX) */ |
643 | int if_type; | 647 | int if_type; |
644 | /* Is the card operating in AP, STA or IBSS mode? */ | 648 | /* Is the card operating in AP, STA or IBSS mode? */ |
645 | bool operating; | 649 | bool operating; |
@@ -819,8 +823,7 @@ struct b43_wldev { | |||
819 | 823 | ||
820 | /* encryption/decryption */ | 824 | /* encryption/decryption */ |
821 | u16 ktp; /* Key table pointer */ | 825 | u16 ktp; /* Key table pointer */ |
822 | u8 max_nr_keys; | 826 | struct b43_key key[B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS]; |
823 | struct b43_key key[58]; | ||
824 | 827 | ||
825 | /* Firmware data */ | 828 | /* Firmware data */ |
826 | struct b43_firmware fw; | 829 | struct b43_firmware fw; |
@@ -845,7 +848,7 @@ static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev) | |||
845 | return ssb_get_drvdata(ssb_dev); | 848 | return ssb_get_drvdata(ssb_dev); |
846 | } | 849 | } |
847 | 850 | ||
848 | /* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */ | 851 | /* Is the device operating in a specified mode (NL80211_IFTYPE_XXX). */ |
849 | static inline int b43_is_mode(struct b43_wl *wl, int type) | 852 | static inline int b43_is_mode(struct b43_wl *wl, int type) |
850 | { | 853 | { |
851 | return (wl->operating && wl->if_type == type); | 854 | return (wl->operating && wl->if_type == type); |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 925f346ea361..950beefbeaeb 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -796,18 +796,19 @@ static void key_write(struct b43_wldev *dev, | |||
796 | static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr) | 796 | static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr) |
797 | { | 797 | { |
798 | u32 addrtmp[2] = { 0, 0, }; | 798 | u32 addrtmp[2] = { 0, 0, }; |
799 | u8 per_sta_keys_start = 8; | 799 | u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2; |
800 | 800 | ||
801 | if (b43_new_kidx_api(dev)) | 801 | if (b43_new_kidx_api(dev)) |
802 | per_sta_keys_start = 4; | 802 | pairwise_keys_start = B43_NR_GROUP_KEYS; |
803 | 803 | ||
804 | B43_WARN_ON(index < per_sta_keys_start); | 804 | B43_WARN_ON(index < pairwise_keys_start); |
805 | /* We have two default TX keys and possibly two default RX keys. | 805 | /* We have four default TX keys and possibly four default RX keys. |
806 | * Physical mac 0 is mapped to physical key 4 or 8, depending | 806 | * Physical mac 0 is mapped to physical key 4 or 8, depending |
807 | * on the firmware version. | 807 | * on the firmware version. |
808 | * So we must adjust the index here. | 808 | * So we must adjust the index here. |
809 | */ | 809 | */ |
810 | index -= per_sta_keys_start; | 810 | index -= pairwise_keys_start; |
811 | B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS); | ||
811 | 812 | ||
812 | if (addr) { | 813 | if (addr) { |
813 | addrtmp[0] = addr[0]; | 814 | addrtmp[0] = addr[0]; |
@@ -818,27 +819,11 @@ static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr) | |||
818 | addrtmp[1] |= ((u32) (addr[5]) << 8); | 819 | addrtmp[1] |= ((u32) (addr[5]) << 8); |
819 | } | 820 | } |
820 | 821 | ||
821 | if (dev->dev->id.revision >= 5) { | 822 | /* Receive match transmitter address (RCMTA) mechanism */ |
822 | /* Receive match transmitter address mechanism */ | 823 | b43_shm_write32(dev, B43_SHM_RCMTA, |
823 | b43_shm_write32(dev, B43_SHM_RCMTA, | 824 | (index * 2) + 0, addrtmp[0]); |
824 | (index * 2) + 0, addrtmp[0]); | 825 | b43_shm_write16(dev, B43_SHM_RCMTA, |
825 | b43_shm_write16(dev, B43_SHM_RCMTA, | 826 | (index * 2) + 1, addrtmp[1]); |
826 | (index * 2) + 1, addrtmp[1]); | ||
827 | } else { | ||
828 | /* RXE (Receive Engine) and | ||
829 | * PSM (Programmable State Machine) mechanism | ||
830 | */ | ||
831 | if (index < 8) { | ||
832 | /* TODO write to RCM 16, 19, 22 and 25 */ | ||
833 | } else { | ||
834 | b43_shm_write32(dev, B43_SHM_SHARED, | ||
835 | B43_SHM_SH_PSM + (index * 6) + 0, | ||
836 | addrtmp[0]); | ||
837 | b43_shm_write16(dev, B43_SHM_SHARED, | ||
838 | B43_SHM_SH_PSM + (index * 6) + 4, | ||
839 | addrtmp[1]); | ||
840 | } | ||
841 | } | ||
842 | } | 827 | } |
843 | 828 | ||
844 | static void do_key_write(struct b43_wldev *dev, | 829 | static void do_key_write(struct b43_wldev *dev, |
@@ -846,20 +831,20 @@ static void do_key_write(struct b43_wldev *dev, | |||
846 | const u8 *key, size_t key_len, const u8 *mac_addr) | 831 | const u8 *key, size_t key_len, const u8 *mac_addr) |
847 | { | 832 | { |
848 | u8 buf[B43_SEC_KEYSIZE] = { 0, }; | 833 | u8 buf[B43_SEC_KEYSIZE] = { 0, }; |
849 | u8 per_sta_keys_start = 8; | 834 | u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2; |
850 | 835 | ||
851 | if (b43_new_kidx_api(dev)) | 836 | if (b43_new_kidx_api(dev)) |
852 | per_sta_keys_start = 4; | 837 | pairwise_keys_start = B43_NR_GROUP_KEYS; |
853 | 838 | ||
854 | B43_WARN_ON(index >= dev->max_nr_keys); | 839 | B43_WARN_ON(index >= ARRAY_SIZE(dev->key)); |
855 | B43_WARN_ON(key_len > B43_SEC_KEYSIZE); | 840 | B43_WARN_ON(key_len > B43_SEC_KEYSIZE); |
856 | 841 | ||
857 | if (index >= per_sta_keys_start) | 842 | if (index >= pairwise_keys_start) |
858 | keymac_write(dev, index, NULL); /* First zero out mac. */ | 843 | keymac_write(dev, index, NULL); /* First zero out mac. */ |
859 | if (key) | 844 | if (key) |
860 | memcpy(buf, key, key_len); | 845 | memcpy(buf, key, key_len); |
861 | key_write(dev, index, algorithm, buf); | 846 | key_write(dev, index, algorithm, buf); |
862 | if (index >= per_sta_keys_start) | 847 | if (index >= pairwise_keys_start) |
863 | keymac_write(dev, index, mac_addr); | 848 | keymac_write(dev, index, mac_addr); |
864 | 849 | ||
865 | dev->key[index].algorithm = algorithm; | 850 | dev->key[index].algorithm = algorithm; |
@@ -872,21 +857,24 @@ static int b43_key_write(struct b43_wldev *dev, | |||
872 | struct ieee80211_key_conf *keyconf) | 857 | struct ieee80211_key_conf *keyconf) |
873 | { | 858 | { |
874 | int i; | 859 | int i; |
875 | int sta_keys_start; | 860 | int pairwise_keys_start; |
876 | 861 | ||
877 | if (key_len > B43_SEC_KEYSIZE) | 862 | if (key_len > B43_SEC_KEYSIZE) |
878 | return -EINVAL; | 863 | return -EINVAL; |
879 | for (i = 0; i < dev->max_nr_keys; i++) { | 864 | for (i = 0; i < ARRAY_SIZE(dev->key); i++) { |
880 | /* Check that we don't already have this key. */ | 865 | /* Check that we don't already have this key. */ |
881 | B43_WARN_ON(dev->key[i].keyconf == keyconf); | 866 | B43_WARN_ON(dev->key[i].keyconf == keyconf); |
882 | } | 867 | } |
883 | if (index < 0) { | 868 | if (index < 0) { |
884 | /* Pairwise key. Get an empty slot for the key. */ | 869 | /* Pairwise key. Get an empty slot for the key. */ |
885 | if (b43_new_kidx_api(dev)) | 870 | if (b43_new_kidx_api(dev)) |
886 | sta_keys_start = 4; | 871 | pairwise_keys_start = B43_NR_GROUP_KEYS; |
887 | else | 872 | else |
888 | sta_keys_start = 8; | 873 | pairwise_keys_start = B43_NR_GROUP_KEYS * 2; |
889 | for (i = sta_keys_start; i < dev->max_nr_keys; i++) { | 874 | for (i = pairwise_keys_start; |
875 | i < pairwise_keys_start + B43_NR_PAIRWISE_KEYS; | ||
876 | i++) { | ||
877 | B43_WARN_ON(i >= ARRAY_SIZE(dev->key)); | ||
890 | if (!dev->key[i].keyconf) { | 878 | if (!dev->key[i].keyconf) { |
891 | /* found empty */ | 879 | /* found empty */ |
892 | index = i; | 880 | index = i; |
@@ -914,7 +902,7 @@ static int b43_key_write(struct b43_wldev *dev, | |||
914 | 902 | ||
915 | static int b43_key_clear(struct b43_wldev *dev, int index) | 903 | static int b43_key_clear(struct b43_wldev *dev, int index) |
916 | { | 904 | { |
917 | if (B43_WARN_ON((index < 0) || (index >= dev->max_nr_keys))) | 905 | if (B43_WARN_ON((index < 0) || (index >= ARRAY_SIZE(dev->key)))) |
918 | return -EINVAL; | 906 | return -EINVAL; |
919 | do_key_write(dev, index, B43_SEC_ALGO_NONE, | 907 | do_key_write(dev, index, B43_SEC_ALGO_NONE, |
920 | NULL, B43_SEC_KEYSIZE, NULL); | 908 | NULL, B43_SEC_KEYSIZE, NULL); |
@@ -929,15 +917,19 @@ static int b43_key_clear(struct b43_wldev *dev, int index) | |||
929 | 917 | ||
930 | static void b43_clear_keys(struct b43_wldev *dev) | 918 | static void b43_clear_keys(struct b43_wldev *dev) |
931 | { | 919 | { |
932 | int i; | 920 | int i, count; |
933 | 921 | ||
934 | for (i = 0; i < dev->max_nr_keys; i++) | 922 | if (b43_new_kidx_api(dev)) |
923 | count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS; | ||
924 | else | ||
925 | count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS; | ||
926 | for (i = 0; i < count; i++) | ||
935 | b43_key_clear(dev, i); | 927 | b43_key_clear(dev, i); |
936 | } | 928 | } |
937 | 929 | ||
938 | static void b43_dump_keymemory(struct b43_wldev *dev) | 930 | static void b43_dump_keymemory(struct b43_wldev *dev) |
939 | { | 931 | { |
940 | unsigned int i, index, offset; | 932 | unsigned int i, index, count, offset, pairwise_keys_start; |
941 | u8 mac[ETH_ALEN]; | 933 | u8 mac[ETH_ALEN]; |
942 | u16 algo; | 934 | u16 algo; |
943 | u32 rcmta0; | 935 | u32 rcmta0; |
@@ -951,7 +943,14 @@ static void b43_dump_keymemory(struct b43_wldev *dev) | |||
951 | hf = b43_hf_read(dev); | 943 | hf = b43_hf_read(dev); |
952 | b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n", | 944 | b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n", |
953 | !!(hf & B43_HF_USEDEFKEYS)); | 945 | !!(hf & B43_HF_USEDEFKEYS)); |
954 | for (index = 0; index < dev->max_nr_keys; index++) { | 946 | if (b43_new_kidx_api(dev)) { |
947 | pairwise_keys_start = B43_NR_GROUP_KEYS; | ||
948 | count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS; | ||
949 | } else { | ||
950 | pairwise_keys_start = B43_NR_GROUP_KEYS * 2; | ||
951 | count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS; | ||
952 | } | ||
953 | for (index = 0; index < count; index++) { | ||
955 | key = &(dev->key[index]); | 954 | key = &(dev->key[index]); |
956 | printk(KERN_DEBUG "Key slot %02u: %s", | 955 | printk(KERN_DEBUG "Key slot %02u: %s", |
957 | index, (key->keyconf == NULL) ? " " : "*"); | 956 | index, (key->keyconf == NULL) ? " " : "*"); |
@@ -965,11 +964,11 @@ static void b43_dump_keymemory(struct b43_wldev *dev) | |||
965 | B43_SHM_SH_KEYIDXBLOCK + (index * 2)); | 964 | B43_SHM_SH_KEYIDXBLOCK + (index * 2)); |
966 | printk(" Algo: %04X/%02X", algo, key->algorithm); | 965 | printk(" Algo: %04X/%02X", algo, key->algorithm); |
967 | 966 | ||
968 | if (index >= 4) { | 967 | if (index >= pairwise_keys_start) { |
969 | rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA, | 968 | rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA, |
970 | ((index - 4) * 2) + 0); | 969 | ((index - pairwise_keys_start) * 2) + 0); |
971 | rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA, | 970 | rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA, |
972 | ((index - 4) * 2) + 1); | 971 | ((index - pairwise_keys_start) * 2) + 1); |
973 | *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0); | 972 | *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0); |
974 | *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1); | 973 | *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1); |
975 | printk(" MAC: %pM", mac); | 974 | printk(" MAC: %pM", mac); |
@@ -1429,116 +1428,6 @@ static void b43_write_beacon_template(struct b43_wldev *dev, | |||
1429 | b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset); | 1428 | b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset); |
1430 | } | 1429 | } |
1431 | 1430 | ||
1432 | static void b43_write_probe_resp_plcp(struct b43_wldev *dev, | ||
1433 | u16 shm_offset, u16 size, | ||
1434 | struct ieee80211_rate *rate) | ||
1435 | { | ||
1436 | struct b43_plcp_hdr4 plcp; | ||
1437 | u32 tmp; | ||
1438 | __le16 dur; | ||
1439 | |||
1440 | plcp.data = 0; | ||
1441 | b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value); | ||
1442 | dur = ieee80211_generic_frame_duration(dev->wl->hw, | ||
1443 | dev->wl->vif, size, | ||
1444 | rate); | ||
1445 | /* Write PLCP in two parts and timing for packet transfer */ | ||
1446 | tmp = le32_to_cpu(plcp.data); | ||
1447 | b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF); | ||
1448 | b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 2, tmp >> 16); | ||
1449 | b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 6, le16_to_cpu(dur)); | ||
1450 | } | ||
1451 | |||
1452 | /* Instead of using custom probe response template, this function | ||
1453 | * just patches custom beacon template by: | ||
1454 | * 1) Changing packet type | ||
1455 | * 2) Patching duration field | ||
1456 | * 3) Stripping TIM | ||
1457 | */ | ||
1458 | static const u8 *b43_generate_probe_resp(struct b43_wldev *dev, | ||
1459 | u16 *dest_size, | ||
1460 | struct ieee80211_rate *rate) | ||
1461 | { | ||
1462 | const u8 *src_data; | ||
1463 | u8 *dest_data; | ||
1464 | u16 src_size, elem_size, src_pos, dest_pos; | ||
1465 | __le16 dur; | ||
1466 | struct ieee80211_hdr *hdr; | ||
1467 | size_t ie_start; | ||
1468 | |||
1469 | src_size = dev->wl->current_beacon->len; | ||
1470 | src_data = (const u8 *)dev->wl->current_beacon->data; | ||
1471 | |||
1472 | /* Get the start offset of the variable IEs in the packet. */ | ||
1473 | ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); | ||
1474 | B43_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, u.beacon.variable)); | ||
1475 | |||
1476 | if (B43_WARN_ON(src_size < ie_start)) | ||
1477 | return NULL; | ||
1478 | |||
1479 | dest_data = kmalloc(src_size, GFP_ATOMIC); | ||
1480 | if (unlikely(!dest_data)) | ||
1481 | return NULL; | ||
1482 | |||
1483 | /* Copy the static data and all Information Elements, except the TIM. */ | ||
1484 | memcpy(dest_data, src_data, ie_start); | ||
1485 | src_pos = ie_start; | ||
1486 | dest_pos = ie_start; | ||
1487 | for ( ; src_pos < src_size - 2; src_pos += elem_size) { | ||
1488 | elem_size = src_data[src_pos + 1] + 2; | ||
1489 | if (src_data[src_pos] == 5) { | ||
1490 | /* This is the TIM. */ | ||
1491 | continue; | ||
1492 | } | ||
1493 | memcpy(dest_data + dest_pos, src_data + src_pos, | ||
1494 | elem_size); | ||
1495 | dest_pos += elem_size; | ||
1496 | } | ||
1497 | *dest_size = dest_pos; | ||
1498 | hdr = (struct ieee80211_hdr *)dest_data; | ||
1499 | |||
1500 | /* Set the frame control. */ | ||
1501 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
1502 | IEEE80211_STYPE_PROBE_RESP); | ||
1503 | dur = ieee80211_generic_frame_duration(dev->wl->hw, | ||
1504 | dev->wl->vif, *dest_size, | ||
1505 | rate); | ||
1506 | hdr->duration_id = dur; | ||
1507 | |||
1508 | return dest_data; | ||
1509 | } | ||
1510 | |||
1511 | static void b43_write_probe_resp_template(struct b43_wldev *dev, | ||
1512 | u16 ram_offset, | ||
1513 | u16 shm_size_offset, | ||
1514 | struct ieee80211_rate *rate) | ||
1515 | { | ||
1516 | const u8 *probe_resp_data; | ||
1517 | u16 size; | ||
1518 | |||
1519 | size = dev->wl->current_beacon->len; | ||
1520 | probe_resp_data = b43_generate_probe_resp(dev, &size, rate); | ||
1521 | if (unlikely(!probe_resp_data)) | ||
1522 | return; | ||
1523 | |||
1524 | /* Looks like PLCP headers plus packet timings are stored for | ||
1525 | * all possible basic rates | ||
1526 | */ | ||
1527 | /* FIXME this is the wrong offset : it goes in tkip rx phase1 shm */ | ||
1528 | #if 0 | ||
1529 | b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]); | ||
1530 | b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]); | ||
1531 | b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]); | ||
1532 | b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]); | ||
1533 | #endif | ||
1534 | |||
1535 | size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6)); | ||
1536 | b43_write_template_common(dev, probe_resp_data, | ||
1537 | size, ram_offset, shm_size_offset, | ||
1538 | rate->hw_value); | ||
1539 | kfree(probe_resp_data); | ||
1540 | } | ||
1541 | |||
1542 | static void b43_upload_beacon0(struct b43_wldev *dev) | 1431 | static void b43_upload_beacon0(struct b43_wldev *dev) |
1543 | { | 1432 | { |
1544 | struct b43_wl *wl = dev->wl; | 1433 | struct b43_wl *wl = dev->wl; |
@@ -1546,10 +1435,6 @@ static void b43_upload_beacon0(struct b43_wldev *dev) | |||
1546 | if (wl->beacon0_uploaded) | 1435 | if (wl->beacon0_uploaded) |
1547 | return; | 1436 | return; |
1548 | b43_write_beacon_template(dev, 0x68, 0x18); | 1437 | b43_write_beacon_template(dev, 0x68, 0x18); |
1549 | /* FIXME: Probe resp upload doesn't really belong here, | ||
1550 | * but we don't use that feature anyway. */ | ||
1551 | b43_write_probe_resp_template(dev, 0x268, 0x4A, | ||
1552 | &__b43_ratetable[3]); | ||
1553 | wl->beacon0_uploaded = 1; | 1438 | wl->beacon0_uploaded = 1; |
1554 | } | 1439 | } |
1555 | 1440 | ||
@@ -2990,17 +2875,14 @@ error: | |||
2990 | 2875 | ||
2991 | static void b43_security_init(struct b43_wldev *dev) | 2876 | static void b43_security_init(struct b43_wldev *dev) |
2992 | { | 2877 | { |
2993 | dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20; | ||
2994 | B43_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key)); | ||
2995 | dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP); | 2878 | dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP); |
2996 | /* KTP is a word address, but we address SHM bytewise. | 2879 | /* KTP is a word address, but we address SHM bytewise. |
2997 | * So multiply by two. | 2880 | * So multiply by two. |
2998 | */ | 2881 | */ |
2999 | dev->ktp *= 2; | 2882 | dev->ktp *= 2; |
3000 | if (dev->dev->id.revision >= 5) { | 2883 | /* Number of RCMTA address slots */ |
3001 | /* Number of RCMTA address slots */ | 2884 | b43_write16(dev, B43_MMIO_RCMTA_COUNT, B43_NR_PAIRWISE_KEYS); |
3002 | b43_write16(dev, B43_MMIO_RCMTA_COUNT, dev->max_nr_keys - 8); | 2885 | /* Clear the key memory. */ |
3003 | } | ||
3004 | b43_clear_keys(dev); | 2886 | b43_clear_keys(dev); |
3005 | } | 2887 | } |
3006 | 2888 | ||
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index aa1486a1354b..cfb8337d3859 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c | |||
@@ -59,9 +59,126 @@ static void b43_lpphy_op_free(struct b43_wldev *dev) | |||
59 | dev->phy.lp = NULL; | 59 | dev->phy.lp = NULL; |
60 | } | 60 | } |
61 | 61 | ||
62 | static void lpphy_read_band_sprom(struct b43_wldev *dev) | ||
63 | { | ||
64 | struct b43_phy_lp *lpphy = dev->phy.lp; | ||
65 | struct ssb_bus *bus = dev->dev->bus; | ||
66 | u16 cckpo, maxpwr; | ||
67 | u32 ofdmpo; | ||
68 | int i; | ||
69 | |||
70 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { | ||
71 | lpphy->tx_isolation_med_band = bus->sprom.tri2g; | ||
72 | lpphy->bx_arch = bus->sprom.bxa2g; | ||
73 | lpphy->rx_pwr_offset = bus->sprom.rxpo2g; | ||
74 | lpphy->rssi_vf = bus->sprom.rssismf2g; | ||
75 | lpphy->rssi_vc = bus->sprom.rssismc2g; | ||
76 | lpphy->rssi_gs = bus->sprom.rssisav2g; | ||
77 | lpphy->txpa[0] = bus->sprom.pa0b0; | ||
78 | lpphy->txpa[1] = bus->sprom.pa0b1; | ||
79 | lpphy->txpa[2] = bus->sprom.pa0b2; | ||
80 | maxpwr = bus->sprom.maxpwr_bg; | ||
81 | lpphy->max_tx_pwr_med_band = maxpwr; | ||
82 | cckpo = bus->sprom.cck2gpo; | ||
83 | ofdmpo = bus->sprom.ofdm2gpo; | ||
84 | if (cckpo) { | ||
85 | for (i = 0; i < 4; i++) { | ||
86 | lpphy->tx_max_rate[i] = | ||
87 | maxpwr - (ofdmpo & 0xF) * 2; | ||
88 | ofdmpo >>= 4; | ||
89 | } | ||
90 | ofdmpo = bus->sprom.ofdm2gpo; | ||
91 | for (i = 4; i < 15; i++) { | ||
92 | lpphy->tx_max_rate[i] = | ||
93 | maxpwr - (ofdmpo & 0xF) * 2; | ||
94 | ofdmpo >>= 4; | ||
95 | } | ||
96 | } else { | ||
97 | ofdmpo &= 0xFF; | ||
98 | for (i = 0; i < 4; i++) | ||
99 | lpphy->tx_max_rate[i] = maxpwr; | ||
100 | for (i = 4; i < 15; i++) | ||
101 | lpphy->tx_max_rate[i] = maxpwr - ofdmpo; | ||
102 | } | ||
103 | } else { /* 5GHz */ | ||
104 | lpphy->tx_isolation_low_band = bus->sprom.tri5gl; | ||
105 | lpphy->tx_isolation_med_band = bus->sprom.tri5g; | ||
106 | lpphy->tx_isolation_hi_band = bus->sprom.tri5gh; | ||
107 | lpphy->bx_arch = bus->sprom.bxa5g; | ||
108 | lpphy->rx_pwr_offset = bus->sprom.rxpo5g; | ||
109 | lpphy->rssi_vf = bus->sprom.rssismf5g; | ||
110 | lpphy->rssi_vc = bus->sprom.rssismc5g; | ||
111 | lpphy->rssi_gs = bus->sprom.rssisav5g; | ||
112 | lpphy->txpa[0] = bus->sprom.pa1b0; | ||
113 | lpphy->txpa[1] = bus->sprom.pa1b1; | ||
114 | lpphy->txpa[2] = bus->sprom.pa1b2; | ||
115 | lpphy->txpal[0] = bus->sprom.pa1lob0; | ||
116 | lpphy->txpal[1] = bus->sprom.pa1lob1; | ||
117 | lpphy->txpal[2] = bus->sprom.pa1lob2; | ||
118 | lpphy->txpah[0] = bus->sprom.pa1hib0; | ||
119 | lpphy->txpah[1] = bus->sprom.pa1hib1; | ||
120 | lpphy->txpah[2] = bus->sprom.pa1hib2; | ||
121 | maxpwr = bus->sprom.maxpwr_al; | ||
122 | ofdmpo = bus->sprom.ofdm5glpo; | ||
123 | lpphy->max_tx_pwr_low_band = maxpwr; | ||
124 | for (i = 4; i < 12; i++) { | ||
125 | lpphy->tx_max_ratel[i] = maxpwr - (ofdmpo & 0xF) * 2; | ||
126 | ofdmpo >>= 4; | ||
127 | } | ||
128 | maxpwr = bus->sprom.maxpwr_a; | ||
129 | ofdmpo = bus->sprom.ofdm5gpo; | ||
130 | lpphy->max_tx_pwr_med_band = maxpwr; | ||
131 | for (i = 4; i < 12; i++) { | ||
132 | lpphy->tx_max_rate[i] = maxpwr - (ofdmpo & 0xF) * 2; | ||
133 | ofdmpo >>= 4; | ||
134 | } | ||
135 | maxpwr = bus->sprom.maxpwr_ah; | ||
136 | ofdmpo = bus->sprom.ofdm5ghpo; | ||
137 | lpphy->max_tx_pwr_hi_band = maxpwr; | ||
138 | for (i = 4; i < 12; i++) { | ||
139 | lpphy->tx_max_rateh[i] = maxpwr - (ofdmpo & 0xF) * 2; | ||
140 | ofdmpo >>= 4; | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static void lpphy_adjust_gain_table(struct b43_wldev *dev) | ||
146 | { | ||
147 | struct b43_phy_lp *lpphy = dev->phy.lp; | ||
148 | u32 freq = dev->wl->hw->conf.channel->center_freq; | ||
149 | u16 temp[3]; | ||
150 | u16 isolation; | ||
151 | |||
152 | B43_WARN_ON(dev->phy.rev >= 2); | ||
153 | |||
154 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) | ||
155 | isolation = lpphy->tx_isolation_med_band; | ||
156 | else if (freq <= 5320) | ||
157 | isolation = lpphy->tx_isolation_low_band; | ||
158 | else if (freq <= 5700) | ||
159 | isolation = lpphy->tx_isolation_med_band; | ||
160 | else | ||
161 | isolation = lpphy->tx_isolation_hi_band; | ||
162 | |||
163 | temp[0] = ((isolation - 26) / 12) << 12; | ||
164 | temp[1] = temp[0] + 0x1000; | ||
165 | temp[2] = temp[0] + 0x2000; | ||
166 | |||
167 | b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp); | ||
168 | b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), 3, temp); | ||
169 | } | ||
170 | |||
62 | static void lpphy_table_init(struct b43_wldev *dev) | 171 | static void lpphy_table_init(struct b43_wldev *dev) |
63 | { | 172 | { |
64 | //TODO | 173 | if (dev->phy.rev < 2) |
174 | lpphy_rev0_1_table_init(dev); | ||
175 | else | ||
176 | lpphy_rev2plus_table_init(dev); | ||
177 | |||
178 | lpphy_init_tx_gain_table(dev); | ||
179 | |||
180 | if (dev->phy.rev < 2) | ||
181 | lpphy_adjust_gain_table(dev); | ||
65 | } | 182 | } |
66 | 183 | ||
67 | static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) | 184 | static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) |
@@ -130,7 +247,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) | |||
130 | b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006); | 247 | b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006); |
131 | b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005); | 248 | b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005); |
132 | b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF); | 249 | b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF); |
133 | b43_hf_write(dev, b43_hf_read(dev) | 0x0800ULL << 32); | 250 | b43_hf_write(dev, b43_hf_read(dev) | B43_HF_PR45960W); |
134 | } | 251 | } |
135 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { | 252 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { |
136 | b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000); | 253 | b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000); |
@@ -161,6 +278,56 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) | |||
161 | } | 278 | } |
162 | } | 279 | } |
163 | 280 | ||
281 | static void lpphy_save_dig_flt_state(struct b43_wldev *dev) | ||
282 | { | ||
283 | static const u16 addr[] = { | ||
284 | B43_PHY_OFDM(0xC1), | ||
285 | B43_PHY_OFDM(0xC2), | ||
286 | B43_PHY_OFDM(0xC3), | ||
287 | B43_PHY_OFDM(0xC4), | ||
288 | B43_PHY_OFDM(0xC5), | ||
289 | B43_PHY_OFDM(0xC6), | ||
290 | B43_PHY_OFDM(0xC7), | ||
291 | B43_PHY_OFDM(0xC8), | ||
292 | B43_PHY_OFDM(0xCF), | ||
293 | }; | ||
294 | |||
295 | static const u16 coefs[] = { | ||
296 | 0xDE5E, 0xE832, 0xE331, 0x4D26, | ||
297 | 0x0026, 0x1420, 0x0020, 0xFE08, | ||
298 | 0x0008, | ||
299 | }; | ||
300 | |||
301 | struct b43_phy_lp *lpphy = dev->phy.lp; | ||
302 | int i; | ||
303 | |||
304 | for (i = 0; i < ARRAY_SIZE(addr); i++) { | ||
305 | lpphy->dig_flt_state[i] = b43_phy_read(dev, addr[i]); | ||
306 | b43_phy_write(dev, addr[i], coefs[i]); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | static void lpphy_restore_dig_flt_state(struct b43_wldev *dev) | ||
311 | { | ||
312 | static const u16 addr[] = { | ||
313 | B43_PHY_OFDM(0xC1), | ||
314 | B43_PHY_OFDM(0xC2), | ||
315 | B43_PHY_OFDM(0xC3), | ||
316 | B43_PHY_OFDM(0xC4), | ||
317 | B43_PHY_OFDM(0xC5), | ||
318 | B43_PHY_OFDM(0xC6), | ||
319 | B43_PHY_OFDM(0xC7), | ||
320 | B43_PHY_OFDM(0xC8), | ||
321 | B43_PHY_OFDM(0xCF), | ||
322 | }; | ||
323 | |||
324 | struct b43_phy_lp *lpphy = dev->phy.lp; | ||
325 | int i; | ||
326 | |||
327 | for (i = 0; i < ARRAY_SIZE(addr); i++) | ||
328 | b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]); | ||
329 | } | ||
330 | |||
164 | static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) | 331 | static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) |
165 | { | 332 | { |
166 | struct ssb_bus *bus = dev->dev->bus; | 333 | struct ssb_bus *bus = dev->dev->bus; |
@@ -175,7 +342,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) | |||
175 | b43_phy_write(dev, B43_PHY_OFDM(0xF9), 0); | 342 | b43_phy_write(dev, B43_PHY_OFDM(0xF9), 0); |
176 | b43_phy_write(dev, B43_LPPHY_TR_LOOKUP_1, 0); | 343 | b43_phy_write(dev, B43_LPPHY_TR_LOOKUP_1, 0); |
177 | b43_phy_set(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x10); | 344 | b43_phy_set(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x10); |
178 | b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x78); | 345 | b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0xB4); |
179 | b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xF8FF, 0x200); | 346 | b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xF8FF, 0x200); |
180 | b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xFF00, 0x7F); | 347 | b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xFF00, 0x7F); |
181 | b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFF0F, 0x40); | 348 | b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFF0F, 0x40); |
@@ -183,7 +350,12 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) | |||
183 | b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x4000); | 350 | b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x4000); |
184 | b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x2000); | 351 | b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x2000); |
185 | b43_phy_set(dev, B43_PHY_OFDM(0x10A), 0x1); | 352 | b43_phy_set(dev, B43_PHY_OFDM(0x10A), 0x1); |
186 | b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10); | 353 | if (bus->boardinfo.rev >= 0x18) { |
354 | b43_lptab_write(dev, B43_LPTAB32(17, 65), 0xEC); | ||
355 | b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x14); | ||
356 | } else { | ||
357 | b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10); | ||
358 | } | ||
187 | b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0xFF00, 0xF4); | 359 | b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0xFF00, 0xF4); |
188 | b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0x00FF, 0xF100); | 360 | b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0x00FF, 0xF100); |
189 | b43_phy_write(dev, B43_LPPHY_CLIPTHRESH, 0x48); | 361 | b43_phy_write(dev, B43_LPPHY_CLIPTHRESH, 0x48); |
@@ -213,8 +385,10 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) | |||
213 | b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12); | 385 | b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12); |
214 | b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000); | 386 | b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000); |
215 | 387 | ||
216 | b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0); | 388 | if ((bus->chip_id == 0x4325) && (bus->chip_rev == 1)) { |
217 | b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40); | 389 | b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0); |
390 | b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40); | ||
391 | } | ||
218 | 392 | ||
219 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { | 393 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { |
220 | b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x40); | 394 | b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x40); |
@@ -234,6 +408,14 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) | |||
234 | b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_1, | 408 | b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_1, |
235 | 0x2000 | ((u16)lpphy->rssi_gs << 10) | | 409 | 0x2000 | ((u16)lpphy->rssi_gs << 10) | |
236 | ((u16)lpphy->rssi_vc << 4) | lpphy->rssi_vf); | 410 | ((u16)lpphy->rssi_vc << 4) | lpphy->rssi_vf); |
411 | |||
412 | if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { | ||
413 | b43_phy_set(dev, B43_LPPHY_AFE_ADC_CTL_0, 0x1C); | ||
414 | b43_phy_maskset(dev, B43_LPPHY_AFE_CTL, 0x00FF, 0x8800); | ||
415 | b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_1, 0xFC3C, 0x0400); | ||
416 | } | ||
417 | |||
418 | lpphy_save_dig_flt_state(dev); | ||
237 | } | 419 | } |
238 | 420 | ||
239 | static void lpphy_baseband_init(struct b43_wldev *dev) | 421 | static void lpphy_baseband_init(struct b43_wldev *dev) |
@@ -333,12 +515,73 @@ static void lpphy_2062_init(struct b43_wldev *dev) | |||
333 | /* Initialize the 2063 radio. */ | 515 | /* Initialize the 2063 radio. */ |
334 | static void lpphy_2063_init(struct b43_wldev *dev) | 516 | static void lpphy_2063_init(struct b43_wldev *dev) |
335 | { | 517 | { |
336 | //TODO | 518 | b2063_upload_init_table(dev); |
519 | b43_radio_write(dev, B2063_LOGEN_SP5, 0); | ||
520 | b43_radio_set(dev, B2063_COMM8, 0x38); | ||
521 | b43_radio_write(dev, B2063_REG_SP1, 0x56); | ||
522 | b43_radio_mask(dev, B2063_RX_BB_CTL2, ~0x2); | ||
523 | b43_radio_write(dev, B2063_PA_SP7, 0); | ||
524 | b43_radio_write(dev, B2063_TX_RF_SP6, 0x20); | ||
525 | b43_radio_write(dev, B2063_TX_RF_SP9, 0x40); | ||
526 | b43_radio_write(dev, B2063_PA_SP3, 0xa0); | ||
527 | b43_radio_write(dev, B2063_PA_SP4, 0xa0); | ||
528 | b43_radio_write(dev, B2063_PA_SP2, 0x18); | ||
337 | } | 529 | } |
338 | 530 | ||
531 | struct lpphy_stx_table_entry { | ||
532 | u16 phy_offset; | ||
533 | u16 phy_shift; | ||
534 | u16 rf_addr; | ||
535 | u16 rf_shift; | ||
536 | u16 mask; | ||
537 | }; | ||
538 | |||
539 | static const struct lpphy_stx_table_entry lpphy_stx_table[] = { | ||
540 | { .phy_offset = 2, .phy_shift = 6, .rf_addr = 0x3d, .rf_shift = 3, .mask = 0x01, }, | ||
541 | { .phy_offset = 1, .phy_shift = 12, .rf_addr = 0x4c, .rf_shift = 1, .mask = 0x01, }, | ||
542 | { .phy_offset = 1, .phy_shift = 8, .rf_addr = 0x50, .rf_shift = 0, .mask = 0x7f, }, | ||
543 | { .phy_offset = 0, .phy_shift = 8, .rf_addr = 0x44, .rf_shift = 0, .mask = 0xff, }, | ||
544 | { .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4a, .rf_shift = 0, .mask = 0xff, }, | ||
545 | { .phy_offset = 0, .phy_shift = 4, .rf_addr = 0x4d, .rf_shift = 0, .mask = 0xff, }, | ||
546 | { .phy_offset = 1, .phy_shift = 4, .rf_addr = 0x4e, .rf_shift = 0, .mask = 0xff, }, | ||
547 | { .phy_offset = 0, .phy_shift = 12, .rf_addr = 0x4f, .rf_shift = 0, .mask = 0x0f, }, | ||
548 | { .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4f, .rf_shift = 4, .mask = 0x0f, }, | ||
549 | { .phy_offset = 3, .phy_shift = 0, .rf_addr = 0x49, .rf_shift = 0, .mask = 0x0f, }, | ||
550 | { .phy_offset = 4, .phy_shift = 3, .rf_addr = 0x46, .rf_shift = 4, .mask = 0x07, }, | ||
551 | { .phy_offset = 3, .phy_shift = 15, .rf_addr = 0x46, .rf_shift = 0, .mask = 0x01, }, | ||
552 | { .phy_offset = 4, .phy_shift = 0, .rf_addr = 0x46, .rf_shift = 1, .mask = 0x07, }, | ||
553 | { .phy_offset = 3, .phy_shift = 8, .rf_addr = 0x48, .rf_shift = 4, .mask = 0x07, }, | ||
554 | { .phy_offset = 3, .phy_shift = 11, .rf_addr = 0x48, .rf_shift = 0, .mask = 0x0f, }, | ||
555 | { .phy_offset = 3, .phy_shift = 4, .rf_addr = 0x49, .rf_shift = 4, .mask = 0x0f, }, | ||
556 | { .phy_offset = 2, .phy_shift = 15, .rf_addr = 0x45, .rf_shift = 0, .mask = 0x01, }, | ||
557 | { .phy_offset = 5, .phy_shift = 13, .rf_addr = 0x52, .rf_shift = 4, .mask = 0x07, }, | ||
558 | { .phy_offset = 6, .phy_shift = 0, .rf_addr = 0x52, .rf_shift = 7, .mask = 0x01, }, | ||
559 | { .phy_offset = 5, .phy_shift = 3, .rf_addr = 0x41, .rf_shift = 5, .mask = 0x07, }, | ||
560 | { .phy_offset = 5, .phy_shift = 6, .rf_addr = 0x41, .rf_shift = 0, .mask = 0x0f, }, | ||
561 | { .phy_offset = 5, .phy_shift = 10, .rf_addr = 0x42, .rf_shift = 5, .mask = 0x07, }, | ||
562 | { .phy_offset = 4, .phy_shift = 15, .rf_addr = 0x42, .rf_shift = 0, .mask = 0x01, }, | ||
563 | { .phy_offset = 5, .phy_shift = 0, .rf_addr = 0x42, .rf_shift = 1, .mask = 0x07, }, | ||
564 | { .phy_offset = 4, .phy_shift = 11, .rf_addr = 0x43, .rf_shift = 4, .mask = 0x0f, }, | ||
565 | { .phy_offset = 4, .phy_shift = 7, .rf_addr = 0x43, .rf_shift = 0, .mask = 0x0f, }, | ||
566 | { .phy_offset = 4, .phy_shift = 6, .rf_addr = 0x45, .rf_shift = 1, .mask = 0x01, }, | ||
567 | { .phy_offset = 2, .phy_shift = 7, .rf_addr = 0x40, .rf_shift = 4, .mask = 0x0f, }, | ||
568 | { .phy_offset = 2, .phy_shift = 11, .rf_addr = 0x40, .rf_shift = 0, .mask = 0x0f, }, | ||
569 | }; | ||
570 | |||
339 | static void lpphy_sync_stx(struct b43_wldev *dev) | 571 | static void lpphy_sync_stx(struct b43_wldev *dev) |
340 | { | 572 | { |
341 | //TODO | 573 | const struct lpphy_stx_table_entry *e; |
574 | unsigned int i; | ||
575 | u16 tmp; | ||
576 | |||
577 | for (i = 0; i < ARRAY_SIZE(lpphy_stx_table); i++) { | ||
578 | e = &lpphy_stx_table[i]; | ||
579 | tmp = b43_radio_read(dev, e->rf_addr); | ||
580 | tmp >>= e->rf_shift; | ||
581 | tmp <<= e->phy_shift; | ||
582 | b43_phy_maskset(dev, B43_PHY_OFDM(0xF2 + e->phy_offset), | ||
583 | ~(e->mask << e->phy_shift), tmp); | ||
584 | } | ||
342 | } | 585 | } |
343 | 586 | ||
344 | static void lpphy_radio_init(struct b43_wldev *dev) | 587 | static void lpphy_radio_init(struct b43_wldev *dev) |
@@ -356,8 +599,343 @@ static void lpphy_radio_init(struct b43_wldev *dev) | |||
356 | lpphy_sync_stx(dev); | 599 | lpphy_sync_stx(dev); |
357 | b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80); | 600 | b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80); |
358 | b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0); | 601 | b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0); |
359 | //TODO Do something on the backplane | 602 | if (dev->dev->bus->chip_id == 0x4325) { |
603 | // TODO SSB PMU recalibration | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | |||
608 | struct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; }; | ||
609 | |||
610 | static void lpphy_set_rc_cap(struct b43_wldev *dev) | ||
611 | { | ||
612 | u8 rc_cap = dev->phy.lp->rc_cap; | ||
613 | |||
614 | b43_radio_write(dev, B2062_N_RXBB_CALIB2, max_t(u8, rc_cap-4, 0x80)); | ||
615 | b43_radio_write(dev, B2062_N_TX_CTL_A, ((rc_cap & 0x1F) >> 1) | 0x80); | ||
616 | b43_radio_write(dev, B2062_S_RXG_CNT16, ((rc_cap & 0x1F) >> 2) | 0x80); | ||
617 | } | ||
618 | |||
619 | static u8 lpphy_get_bb_mult(struct b43_wldev *dev) | ||
620 | { | ||
621 | return (b43_lptab_read(dev, B43_LPTAB16(0, 87)) & 0xFF00) >> 8; | ||
622 | } | ||
623 | |||
624 | static void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult) | ||
625 | { | ||
626 | b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8); | ||
627 | } | ||
628 | |||
629 | static void lpphy_disable_crs(struct b43_wldev *dev) | ||
630 | { | ||
631 | b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80); | ||
632 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x1); | ||
633 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3); | ||
634 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB); | ||
635 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4); | ||
636 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7); | ||
637 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8); | ||
638 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x10); | ||
639 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10); | ||
640 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFDF); | ||
641 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20); | ||
642 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFBF); | ||
643 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40); | ||
644 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x7); | ||
645 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x38); | ||
646 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F); | ||
647 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x100); | ||
648 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFDFF); | ||
649 | b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL0, 0); | ||
650 | b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL1, 1); | ||
651 | b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL2, 0x20); | ||
652 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFBFF); | ||
653 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xF7FF); | ||
654 | b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, 0); | ||
655 | b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45AF); | ||
656 | b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF); | ||
657 | } | ||
658 | |||
659 | static void lpphy_restore_crs(struct b43_wldev *dev) | ||
660 | { | ||
661 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) | ||
662 | b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x60); | ||
663 | else | ||
664 | b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x20); | ||
665 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80); | ||
666 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00); | ||
667 | } | ||
668 | |||
669 | struct lpphy_tx_gains { u16 gm, pga, pad, dac; }; | ||
670 | |||
671 | static struct lpphy_tx_gains lpphy_get_tx_gains(struct b43_wldev *dev) | ||
672 | { | ||
673 | struct lpphy_tx_gains gains; | ||
674 | u16 tmp; | ||
675 | |||
676 | gains.dac = (b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0x380) >> 7; | ||
677 | if (dev->phy.rev < 2) { | ||
678 | tmp = b43_phy_read(dev, | ||
679 | B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7FF; | ||
680 | gains.gm = tmp & 0x0007; | ||
681 | gains.pga = (tmp & 0x0078) >> 3; | ||
682 | gains.pad = (tmp & 0x780) >> 7; | ||
683 | } else { | ||
684 | tmp = b43_phy_read(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL); | ||
685 | gains.pad = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0xFF; | ||
686 | gains.gm = tmp & 0xFF; | ||
687 | gains.pga = (tmp >> 8) & 0xFF; | ||
688 | } | ||
689 | |||
690 | return gains; | ||
691 | } | ||
692 | |||
693 | static void lpphy_set_dac_gain(struct b43_wldev *dev, u16 dac) | ||
694 | { | ||
695 | u16 ctl = b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0xC7F; | ||
696 | ctl |= dac << 7; | ||
697 | b43_phy_maskset(dev, B43_LPPHY_AFE_DAC_CTL, 0xF000, ctl); | ||
698 | } | ||
699 | |||
700 | static void lpphy_set_tx_gains(struct b43_wldev *dev, | ||
701 | struct lpphy_tx_gains gains) | ||
702 | { | ||
703 | u16 rf_gain, pa_gain; | ||
704 | |||
705 | if (dev->phy.rev < 2) { | ||
706 | rf_gain = (gains.pad << 7) | (gains.pga << 3) | gains.gm; | ||
707 | b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, | ||
708 | 0xF800, rf_gain); | ||
709 | } else { | ||
710 | pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F00; | ||
711 | b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, | ||
712 | (gains.pga << 8) | gains.gm); | ||
713 | b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, | ||
714 | 0x8000, gains.pad | pa_gain); | ||
715 | b43_phy_write(dev, B43_PHY_OFDM(0xFC), | ||
716 | (gains.pga << 8) | gains.gm); | ||
717 | b43_phy_maskset(dev, B43_PHY_OFDM(0xFD), | ||
718 | 0x8000, gains.pad | pa_gain); | ||
719 | } | ||
720 | lpphy_set_dac_gain(dev, gains.dac); | ||
721 | if (dev->phy.rev < 2) { | ||
722 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF, 1 << 8); | ||
723 | } else { | ||
724 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7); | ||
725 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14); | ||
726 | } | ||
727 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFBF, 1 << 4); | ||
728 | } | ||
729 | |||
730 | static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain) | ||
731 | { | ||
732 | u16 trsw = gain & 0x1; | ||
733 | u16 lna = (gain & 0xFFFC) | ((gain & 0xC) >> 2); | ||
734 | u16 ext_lna = (gain & 2) >> 1; | ||
735 | |||
736 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw); | ||
737 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, | ||
738 | 0xFBFF, ext_lna << 10); | ||
739 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, | ||
740 | 0xF7FF, ext_lna << 11); | ||
741 | b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, lna); | ||
742 | } | ||
743 | |||
744 | static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain) | ||
745 | { | ||
746 | u16 low_gain = gain & 0xFFFF; | ||
747 | u16 high_gain = (gain >> 16) & 0xF; | ||
748 | u16 ext_lna = (gain >> 21) & 0x1; | ||
749 | u16 trsw = ~(gain >> 20) & 0x1; | ||
750 | u16 tmp; | ||
751 | |||
752 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw); | ||
753 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, | ||
754 | 0xFDFF, ext_lna << 9); | ||
755 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, | ||
756 | 0xFBFF, ext_lna << 10); | ||
757 | b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain); | ||
758 | b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF0, high_gain); | ||
759 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { | ||
760 | tmp = (gain >> 2) & 0x3; | ||
761 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, | ||
762 | 0xE7FF, tmp<<11); | ||
763 | b43_phy_maskset(dev, B43_PHY_OFDM(0xE6), 0xFFE7, tmp << 3); | ||
764 | } | ||
765 | } | ||
766 | |||
767 | static void lpphy_enable_rx_gain_override(struct b43_wldev *dev) | ||
768 | { | ||
769 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE); | ||
770 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF); | ||
771 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF); | ||
772 | if (dev->phy.rev >= 2) { | ||
773 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF); | ||
774 | if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) | ||
775 | return; | ||
776 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF); | ||
777 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFF7); | ||
778 | } else { | ||
779 | b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF); | ||
780 | } | ||
781 | } | ||
782 | |||
783 | static void lpphy_disable_rx_gain_override(struct b43_wldev *dev) | ||
784 | { | ||
785 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1); | ||
786 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10); | ||
787 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40); | ||
788 | if (dev->phy.rev >= 2) { | ||
789 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100); | ||
790 | if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) | ||
791 | return; | ||
792 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400); | ||
793 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x8); | ||
794 | } else { | ||
795 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200); | ||
796 | } | ||
797 | } | ||
798 | |||
799 | static void lpphy_set_rx_gain(struct b43_wldev *dev, u32 gain) | ||
800 | { | ||
801 | if (dev->phy.rev < 2) | ||
802 | lpphy_rev0_1_set_rx_gain(dev, gain); | ||
803 | else | ||
804 | lpphy_rev2plus_set_rx_gain(dev, gain); | ||
805 | lpphy_enable_rx_gain_override(dev); | ||
806 | } | ||
807 | |||
808 | static void lpphy_set_rx_gain_by_index(struct b43_wldev *dev, u16 idx) | ||
809 | { | ||
810 | u32 gain = b43_lptab_read(dev, B43_LPTAB16(12, idx)); | ||
811 | lpphy_set_rx_gain(dev, gain); | ||
812 | } | ||
813 | |||
814 | static void lpphy_stop_ddfs(struct b43_wldev *dev) | ||
815 | { | ||
816 | b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFD); | ||
817 | b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xFFDF); | ||
818 | } | ||
819 | |||
820 | static void lpphy_run_ddfs(struct b43_wldev *dev, int i_on, int q_on, | ||
821 | int incr1, int incr2, int scale_idx) | ||
822 | { | ||
823 | lpphy_stop_ddfs(dev); | ||
824 | b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0xFF80); | ||
825 | b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0x80FF); | ||
826 | b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0xFF80, incr1); | ||
827 | b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0x80FF, incr2 << 8); | ||
828 | b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF7, i_on << 3); | ||
829 | b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFEF, q_on << 4); | ||
830 | b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFF9F, scale_idx << 5); | ||
831 | b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFB); | ||
832 | b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x2); | ||
833 | b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x20); | ||
834 | } | ||
835 | |||
836 | static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time, | ||
837 | struct lpphy_iq_est *iq_est) | ||
838 | { | ||
839 | int i; | ||
840 | |||
841 | b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFF7); | ||
842 | b43_phy_write(dev, B43_LPPHY_IQ_NUM_SMPLS_ADDR, samples); | ||
843 | b43_phy_maskset(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFF00, time); | ||
844 | b43_phy_mask(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFEFF); | ||
845 | b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFDFF); | ||
846 | |||
847 | for (i = 0; i < 500; i++) { | ||
848 | if (!(b43_phy_read(dev, | ||
849 | B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) | ||
850 | break; | ||
851 | msleep(1); | ||
852 | } | ||
853 | |||
854 | if ((b43_phy_read(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) { | ||
855 | b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8); | ||
856 | return false; | ||
857 | } | ||
858 | |||
859 | iq_est->iq_prod = b43_phy_read(dev, B43_LPPHY_IQ_ACC_HI_ADDR); | ||
860 | iq_est->iq_prod <<= 16; | ||
861 | iq_est->iq_prod |= b43_phy_read(dev, B43_LPPHY_IQ_ACC_LO_ADDR); | ||
862 | |||
863 | iq_est->i_pwr = b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_HI_ADDR); | ||
864 | iq_est->i_pwr <<= 16; | ||
865 | iq_est->i_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_LO_ADDR); | ||
866 | |||
867 | iq_est->q_pwr = b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_HI_ADDR); | ||
868 | iq_est->q_pwr <<= 16; | ||
869 | iq_est->q_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_LO_ADDR); | ||
870 | |||
871 | b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8); | ||
872 | return true; | ||
873 | } | ||
874 | |||
875 | static int lpphy_loopback(struct b43_wldev *dev) | ||
876 | { | ||
877 | struct lpphy_iq_est iq_est; | ||
878 | int i, index = -1; | ||
879 | u32 tmp; | ||
880 | |||
881 | memset(&iq_est, 0, sizeof(iq_est)); | ||
882 | |||
883 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x3); | ||
884 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3); | ||
885 | b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE); | ||
886 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800); | ||
887 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800); | ||
888 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8); | ||
889 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x8); | ||
890 | b43_radio_write(dev, B2062_N_TX_CTL_A, 0x80); | ||
891 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x80); | ||
892 | b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x80); | ||
893 | for (i = 0; i < 32; i++) { | ||
894 | lpphy_set_rx_gain_by_index(dev, i); | ||
895 | lpphy_run_ddfs(dev, 1, 1, 5, 5, 0); | ||
896 | if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est))) | ||
897 | continue; | ||
898 | tmp = (iq_est.i_pwr + iq_est.q_pwr) / 1000; | ||
899 | if ((tmp > 4000) && (tmp < 10000)) { | ||
900 | index = i; | ||
901 | break; | ||
902 | } | ||
360 | } | 903 | } |
904 | lpphy_stop_ddfs(dev); | ||
905 | return index; | ||
906 | } | ||
907 | |||
908 | static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision) | ||
909 | { | ||
910 | u32 quotient, remainder, rbit, roundup, tmp; | ||
911 | |||
912 | if (divisor == 0) { | ||
913 | quotient = 0; | ||
914 | remainder = 0; | ||
915 | } else { | ||
916 | quotient = dividend / divisor; | ||
917 | remainder = dividend % divisor; | ||
918 | } | ||
919 | |||
920 | rbit = divisor & 0x1; | ||
921 | roundup = (divisor >> 1) + rbit; | ||
922 | precision--; | ||
923 | |||
924 | while (precision != 0xFF) { | ||
925 | tmp = remainder - roundup; | ||
926 | quotient <<= 1; | ||
927 | remainder <<= 1; | ||
928 | if (remainder >= roundup) { | ||
929 | remainder = (tmp << 1) + rbit; | ||
930 | quotient--; | ||
931 | } | ||
932 | precision--; | ||
933 | } | ||
934 | |||
935 | if (remainder >= roundup) | ||
936 | quotient++; | ||
937 | |||
938 | return quotient; | ||
361 | } | 939 | } |
362 | 940 | ||
363 | /* Read the TX power control mode from hardware. */ | 941 | /* Read the TX power control mode from hardware. */ |
@@ -444,6 +1022,170 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev, | |||
444 | lpphy_write_tx_pctl_mode_to_hardware(dev); | 1022 | lpphy_write_tx_pctl_mode_to_hardware(dev); |
445 | } | 1023 | } |
446 | 1024 | ||
1025 | static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) | ||
1026 | { | ||
1027 | struct b43_phy_lp *lpphy = dev->phy.lp; | ||
1028 | struct lpphy_iq_est iq_est; | ||
1029 | struct lpphy_tx_gains tx_gains; | ||
1030 | static const u32 ideal_pwr_table[22] = { | ||
1031 | 0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64, | ||
1032 | 0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35, | ||
1033 | 0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088, | ||
1034 | 0x0004c, 0x0002c, 0x0001a, 0xc0006, | ||
1035 | }; | ||
1036 | bool old_txg_ovr; | ||
1037 | u8 old_bbmult; | ||
1038 | u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval, | ||
1039 | old_rf2_ovr, old_rf2_ovrval, old_phy_ctl, old_txpctl; | ||
1040 | u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0; | ||
1041 | int loopback, i, j, inner_sum; | ||
1042 | |||
1043 | memset(&iq_est, 0, sizeof(iq_est)); | ||
1044 | |||
1045 | b43_switch_channel(dev, 7); | ||
1046 | old_txg_ovr = (b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) >> 6) & 1; | ||
1047 | old_bbmult = lpphy_get_bb_mult(dev); | ||
1048 | if (old_txg_ovr) | ||
1049 | tx_gains = lpphy_get_tx_gains(dev); | ||
1050 | old_rf_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_0); | ||
1051 | old_rf_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_VAL_0); | ||
1052 | old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR); | ||
1053 | old_afe_ovrval = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVRVAL); | ||
1054 | old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2); | ||
1055 | old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL); | ||
1056 | old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL); | ||
1057 | old_txpctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD) & | ||
1058 | B43_LPPHY_TX_PWR_CTL_CMD_MODE; | ||
1059 | |||
1060 | lpphy_set_tx_power_control(dev, B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF); | ||
1061 | lpphy_disable_crs(dev); | ||
1062 | loopback = lpphy_loopback(dev); | ||
1063 | if (loopback == -1) | ||
1064 | goto finish; | ||
1065 | lpphy_set_rx_gain_by_index(dev, loopback); | ||
1066 | b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFFBF, 0x40); | ||
1067 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFF8, 0x1); | ||
1068 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFC7, 0x8); | ||
1069 | b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F, 0xC0); | ||
1070 | for (i = 128; i <= 159; i++) { | ||
1071 | b43_radio_write(dev, B2062_N_RXBB_CALIB2, i); | ||
1072 | inner_sum = 0; | ||
1073 | for (j = 5; j <= 25; j++) { | ||
1074 | lpphy_run_ddfs(dev, 1, 1, j, j, 0); | ||
1075 | if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est))) | ||
1076 | goto finish; | ||
1077 | mean_sq_pwr = iq_est.i_pwr + iq_est.q_pwr; | ||
1078 | if (j == 5) | ||
1079 | tmp = mean_sq_pwr; | ||
1080 | ideal_pwr = ((ideal_pwr_table[j-5] >> 3) + 1) >> 1; | ||
1081 | normal_pwr = lpphy_qdiv_roundup(mean_sq_pwr, tmp, 12); | ||
1082 | mean_sq_pwr = ideal_pwr - normal_pwr; | ||
1083 | mean_sq_pwr *= mean_sq_pwr; | ||
1084 | inner_sum += mean_sq_pwr; | ||
1085 | if ((i = 128) || (inner_sum < mean_sq_pwr_min)) { | ||
1086 | lpphy->rc_cap = i; | ||
1087 | mean_sq_pwr_min = inner_sum; | ||
1088 | } | ||
1089 | } | ||
1090 | } | ||
1091 | lpphy_stop_ddfs(dev); | ||
1092 | |||
1093 | finish: | ||
1094 | lpphy_restore_crs(dev); | ||
1095 | b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval); | ||
1096 | b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr); | ||
1097 | b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval); | ||
1098 | b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, old_afe_ovr); | ||
1099 | b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, old_rf2_ovrval); | ||
1100 | b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, old_rf2_ovr); | ||
1101 | b43_phy_write(dev, B43_LPPHY_LP_PHY_CTL, old_phy_ctl); | ||
1102 | |||
1103 | lpphy_set_bb_mult(dev, old_bbmult); | ||
1104 | if (old_txg_ovr) { | ||
1105 | /* | ||
1106 | * SPEC FIXME: The specs say "get_tx_gains" here, which is | ||
1107 | * illogical. According to lwfinger, vendor driver v4.150.10.5 | ||
1108 | * has a Set here, while v4.174.64.19 has a Get - regression in | ||
1109 | * the vendor driver? This should be tested this once the code | ||
1110 | * is testable. | ||
1111 | */ | ||
1112 | lpphy_set_tx_gains(dev, tx_gains); | ||
1113 | } | ||
1114 | lpphy_set_tx_power_control(dev, old_txpctl); | ||
1115 | if (lpphy->rc_cap) | ||
1116 | lpphy_set_rc_cap(dev); | ||
1117 | } | ||
1118 | |||
1119 | static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev) | ||
1120 | { | ||
1121 | struct ssb_bus *bus = dev->dev->bus; | ||
1122 | u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; | ||
1123 | u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF; | ||
1124 | int i; | ||
1125 | |||
1126 | b43_radio_write(dev, B2063_RX_BB_SP8, 0x0); | ||
1127 | b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); | ||
1128 | b43_radio_mask(dev, B2063_PLL_SP1, 0xF7); | ||
1129 | b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); | ||
1130 | b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x15); | ||
1131 | b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x70); | ||
1132 | b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x52); | ||
1133 | b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); | ||
1134 | b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7D); | ||
1135 | |||
1136 | for (i = 0; i < 10000; i++) { | ||
1137 | if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) | ||
1138 | break; | ||
1139 | msleep(1); | ||
1140 | } | ||
1141 | |||
1142 | if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) | ||
1143 | b43_radio_write(dev, B2063_RX_BB_SP8, tmp); | ||
1144 | |||
1145 | tmp = b43_radio_read(dev, B2063_TX_BB_SP3) & 0xFF; | ||
1146 | |||
1147 | b43_radio_write(dev, B2063_TX_BB_SP3, 0x0); | ||
1148 | b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); | ||
1149 | b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); | ||
1150 | b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x55); | ||
1151 | b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x76); | ||
1152 | |||
1153 | if (crystal_freq == 24000000) { | ||
1154 | b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0xFC); | ||
1155 | b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x0); | ||
1156 | } else { | ||
1157 | b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x13); | ||
1158 | b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); | ||
1159 | } | ||
1160 | |||
1161 | b43_radio_write(dev, B2063_PA_SP7, 0x7D); | ||
1162 | |||
1163 | for (i = 0; i < 10000; i++) { | ||
1164 | if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) | ||
1165 | break; | ||
1166 | msleep(1); | ||
1167 | } | ||
1168 | |||
1169 | if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) | ||
1170 | b43_radio_write(dev, B2063_TX_BB_SP3, tmp); | ||
1171 | |||
1172 | b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); | ||
1173 | } | ||
1174 | |||
1175 | static void lpphy_calibrate_rc(struct b43_wldev *dev) | ||
1176 | { | ||
1177 | struct b43_phy_lp *lpphy = dev->phy.lp; | ||
1178 | |||
1179 | if (dev->phy.rev >= 2) { | ||
1180 | lpphy_rev2plus_rc_calib(dev); | ||
1181 | } else if (!lpphy->rc_cap) { | ||
1182 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) | ||
1183 | lpphy_rev0_1_rc_calib(dev); | ||
1184 | } else { | ||
1185 | lpphy_set_rc_cap(dev); | ||
1186 | } | ||
1187 | } | ||
1188 | |||
447 | static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index) | 1189 | static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index) |
448 | { | 1190 | { |
449 | struct b43_phy_lp *lpphy = dev->phy.lp; | 1191 | struct b43_phy_lp *lpphy = dev->phy.lp; |
@@ -532,13 +1274,14 @@ static void lpphy_tx_pctl_init(struct b43_wldev *dev) | |||
532 | 1274 | ||
533 | static int b43_lpphy_op_init(struct b43_wldev *dev) | 1275 | static int b43_lpphy_op_init(struct b43_wldev *dev) |
534 | { | 1276 | { |
535 | /* TODO: band SPROM */ | 1277 | lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? |
536 | lpphy_baseband_init(dev); | 1278 | lpphy_baseband_init(dev); |
537 | lpphy_radio_init(dev); | 1279 | lpphy_radio_init(dev); |
538 | //TODO calibrate RC | 1280 | lpphy_calibrate_rc(dev); |
539 | //TODO set channel | 1281 | //TODO set channel |
540 | lpphy_tx_pctl_init(dev); | 1282 | lpphy_tx_pctl_init(dev); |
541 | //TODO full calib | 1283 | lpphy_calibration(dev); |
1284 | //TODO ACI init | ||
542 | 1285 | ||
543 | return 0; | 1286 | return 0; |
544 | } | 1287 | } |
@@ -616,7 +1359,6 @@ static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev, | |||
616 | return B43_TXPWR_RES_DONE; | 1359 | return B43_TXPWR_RES_DONE; |
617 | } | 1360 | } |
618 | 1361 | ||
619 | |||
620 | const struct b43_phy_operations b43_phyops_lp = { | 1362 | const struct b43_phy_operations b43_phyops_lp = { |
621 | .allocate = b43_lpphy_op_allocate, | 1363 | .allocate = b43_lpphy_op_allocate, |
622 | .free = b43_lpphy_op_free, | 1364 | .free = b43_lpphy_op_free, |
diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 829b2bba3ee1..0461d5b3144f 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h | |||
@@ -831,6 +831,22 @@ struct b43_phy_lp { | |||
831 | /* Transmit isolation high band */ | 831 | /* Transmit isolation high band */ |
832 | u8 tx_isolation_hi_band; /* FIXME initial value? */ | 832 | u8 tx_isolation_hi_band; /* FIXME initial value? */ |
833 | 833 | ||
834 | /* Max transmit power medium band */ | ||
835 | u16 max_tx_pwr_med_band; | ||
836 | /* Max transmit power low band */ | ||
837 | u16 max_tx_pwr_low_band; | ||
838 | /* Max transmit power high band */ | ||
839 | u16 max_tx_pwr_hi_band; | ||
840 | |||
841 | /* FIXME What are these used for? */ | ||
842 | /* FIXME Is 15 the correct array size? */ | ||
843 | u16 tx_max_rate[15]; | ||
844 | u16 tx_max_ratel[15]; | ||
845 | u16 tx_max_rateh[15]; | ||
846 | |||
847 | /* Transmit power arrays */ | ||
848 | s16 txpa[3], txpal[3], txpah[3]; | ||
849 | |||
834 | /* Receive power offset */ | 850 | /* Receive power offset */ |
835 | u8 rx_pwr_offset; /* FIXME initial value? */ | 851 | u8 rx_pwr_offset; /* FIXME initial value? */ |
836 | 852 | ||
@@ -865,6 +881,9 @@ struct b43_phy_lp { | |||
865 | /* Transmit iqlocal best coeffs */ | 881 | /* Transmit iqlocal best coeffs */ |
866 | bool tx_iqloc_best_coeffs_valid; | 882 | bool tx_iqloc_best_coeffs_valid; |
867 | u8 tx_iqloc_best_coeffs[11]; | 883 | u8 tx_iqloc_best_coeffs[11]; |
884 | |||
885 | /* Used for "Save/Restore Dig Filt State" */ | ||
886 | u16 dig_flt_state[9]; | ||
868 | }; | 887 | }; |
869 | 888 | ||
870 | 889 | ||
diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index 4ea734dce218..2721310acb2a 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c | |||
@@ -28,22 +28,22 @@ | |||
28 | #include "phy_lp.h" | 28 | #include "phy_lp.h" |
29 | 29 | ||
30 | 30 | ||
31 | /* Entry of the 2062 radio init table */ | 31 | /* Entry of the 2062/2063 radio init table */ |
32 | struct b2062_init_tab_entry { | 32 | struct b206x_init_tab_entry { |
33 | u16 offset; | 33 | u16 offset; |
34 | u16 value_a; | 34 | u16 value_a; |
35 | u16 value_g; | 35 | u16 value_g; |
36 | u8 flags; | 36 | u8 flags; |
37 | }; | 37 | }; |
38 | #define B2062_FLAG_A 0x01 /* Flag: Init in A mode */ | 38 | #define B206X_FLAG_A 0x01 /* Flag: Init in A mode */ |
39 | #define B2062_FLAG_G 0x02 /* Flag: Init in G mode */ | 39 | #define B206X_FLAG_G 0x02 /* Flag: Init in G mode */ |
40 | 40 | ||
41 | static const struct b2062_init_tab_entry b2062_init_tab[] = { | 41 | static const struct b206x_init_tab_entry b2062_init_tab[] = { |
42 | /* { .offset = B2062_N_COMM1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 42 | /* { .offset = B2062_N_COMM1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
43 | /* { .offset = 0x0001, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 43 | /* { .offset = 0x0001, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
44 | /* { .offset = B2062_N_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 44 | /* { .offset = B2062_N_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
45 | /* { .offset = B2062_N_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 45 | /* { .offset = B2062_N_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
46 | { .offset = B2062_N_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 46 | { .offset = B2062_N_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
47 | /* { .offset = B2062_N_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 47 | /* { .offset = B2062_N_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
48 | /* { .offset = B2062_N_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 48 | /* { .offset = B2062_N_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
49 | /* { .offset = B2062_N_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 49 | /* { .offset = B2062_N_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
@@ -56,42 +56,42 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { | |||
56 | /* { .offset = B2062_N_COMM14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 56 | /* { .offset = B2062_N_COMM14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
57 | /* { .offset = B2062_N_COMM15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 57 | /* { .offset = B2062_N_COMM15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
58 | /* { .offset = B2062_N_PDN_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 58 | /* { .offset = B2062_N_PDN_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
59 | { .offset = B2062_N_PDN_CTL1, .value_a = 0x0000, .value_g = 0x00CA, .flags = B2062_FLAG_G, }, | 59 | { .offset = B2062_N_PDN_CTL1, .value_a = 0x0000, .value_g = 0x00CA, .flags = B206X_FLAG_G, }, |
60 | /* { .offset = B2062_N_PDN_CTL2, .value_a = 0x0018, .value_g = 0x0018, .flags = 0, }, */ | 60 | /* { .offset = B2062_N_PDN_CTL2, .value_a = 0x0018, .value_g = 0x0018, .flags = 0, }, */ |
61 | { .offset = B2062_N_PDN_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 61 | { .offset = B2062_N_PDN_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
62 | { .offset = B2062_N_PDN_CTL4, .value_a = 0x0015, .value_g = 0x002A, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 62 | { .offset = B2062_N_PDN_CTL4, .value_a = 0x0015, .value_g = 0x002A, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
63 | /* { .offset = B2062_N_GEN_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 63 | /* { .offset = B2062_N_GEN_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
64 | /* { .offset = B2062_N_IQ_CALIB, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ | 64 | /* { .offset = B2062_N_IQ_CALIB, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ |
65 | { .offset = B2062_N_LGENC, .value_a = 0x00DB, .value_g = 0x00FF, .flags = B2062_FLAG_A, }, | 65 | { .offset = B2062_N_LGENC, .value_a = 0x00DB, .value_g = 0x00FF, .flags = B206X_FLAG_A, }, |
66 | /* { .offset = B2062_N_LGENA_LPF, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ | 66 | /* { .offset = B2062_N_LGENA_LPF, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ |
67 | /* { .offset = B2062_N_LGENA_BIAS0, .value_a = 0x0041, .value_g = 0x0041, .flags = 0, }, */ | 67 | /* { .offset = B2062_N_LGENA_BIAS0, .value_a = 0x0041, .value_g = 0x0041, .flags = 0, }, */ |
68 | /* { .offset = B2062_N_LGNEA_BIAS1, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ | 68 | /* { .offset = B2062_N_LGNEA_BIAS1, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ |
69 | /* { .offset = B2062_N_LGENA_CTL0, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */ | 69 | /* { .offset = B2062_N_LGENA_CTL0, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */ |
70 | /* { .offset = B2062_N_LGENA_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 70 | /* { .offset = B2062_N_LGENA_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
71 | /* { .offset = B2062_N_LGENA_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 71 | /* { .offset = B2062_N_LGENA_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
72 | { .offset = B2062_N_LGENA_TUNE0, .value_a = 0x00DD, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 72 | { .offset = B2062_N_LGENA_TUNE0, .value_a = 0x00DD, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
73 | /* { .offset = B2062_N_LGENA_TUNE1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 73 | /* { .offset = B2062_N_LGENA_TUNE1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
74 | { .offset = B2062_N_LGENA_TUNE2, .value_a = 0x00DD, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 74 | { .offset = B2062_N_LGENA_TUNE2, .value_a = 0x00DD, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
75 | { .offset = B2062_N_LGENA_TUNE3, .value_a = 0x0077, .value_g = 0x00B5, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 75 | { .offset = B2062_N_LGENA_TUNE3, .value_a = 0x0077, .value_g = 0x00B5, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
76 | { .offset = B2062_N_LGENA_CTL3, .value_a = 0x0000, .value_g = 0x00FF, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 76 | { .offset = B2062_N_LGENA_CTL3, .value_a = 0x0000, .value_g = 0x00FF, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
77 | /* { .offset = B2062_N_LGENA_CTL4, .value_a = 0x001F, .value_g = 0x001F, .flags = 0, }, */ | 77 | /* { .offset = B2062_N_LGENA_CTL4, .value_a = 0x001F, .value_g = 0x001F, .flags = 0, }, */ |
78 | /* { .offset = B2062_N_LGENA_CTL5, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */ | 78 | /* { .offset = B2062_N_LGENA_CTL5, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */ |
79 | /* { .offset = B2062_N_LGENA_CTL6, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */ | 79 | /* { .offset = B2062_N_LGENA_CTL6, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */ |
80 | { .offset = B2062_N_LGENA_CTL7, .value_a = 0x0033, .value_g = 0x0033, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 80 | { .offset = B2062_N_LGENA_CTL7, .value_a = 0x0033, .value_g = 0x0033, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
81 | /* { .offset = B2062_N_RXA_CTL0, .value_a = 0x0009, .value_g = 0x0009, .flags = 0, }, */ | 81 | /* { .offset = B2062_N_RXA_CTL0, .value_a = 0x0009, .value_g = 0x0009, .flags = 0, }, */ |
82 | { .offset = B2062_N_RXA_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = B2062_FLAG_G, }, | 82 | { .offset = B2062_N_RXA_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, |
83 | /* { .offset = B2062_N_RXA_CTL2, .value_a = 0x0018, .value_g = 0x0018, .flags = 0, }, */ | 83 | /* { .offset = B2062_N_RXA_CTL2, .value_a = 0x0018, .value_g = 0x0018, .flags = 0, }, */ |
84 | /* { .offset = B2062_N_RXA_CTL3, .value_a = 0x0027, .value_g = 0x0027, .flags = 0, }, */ | 84 | /* { .offset = B2062_N_RXA_CTL3, .value_a = 0x0027, .value_g = 0x0027, .flags = 0, }, */ |
85 | /* { .offset = B2062_N_RXA_CTL4, .value_a = 0x0028, .value_g = 0x0028, .flags = 0, }, */ | 85 | /* { .offset = B2062_N_RXA_CTL4, .value_a = 0x0028, .value_g = 0x0028, .flags = 0, }, */ |
86 | /* { .offset = B2062_N_RXA_CTL5, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ | 86 | /* { .offset = B2062_N_RXA_CTL5, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ |
87 | /* { .offset = B2062_N_RXA_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 87 | /* { .offset = B2062_N_RXA_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
88 | /* { .offset = B2062_N_RXA_CTL7, .value_a = 0x0008, .value_g = 0x0008, .flags = 0, }, */ | 88 | /* { .offset = B2062_N_RXA_CTL7, .value_a = 0x0008, .value_g = 0x0008, .flags = 0, }, */ |
89 | { .offset = B2062_N_RXBB_CTL0, .value_a = 0x0082, .value_g = 0x0080, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 89 | { .offset = B2062_N_RXBB_CTL0, .value_a = 0x0082, .value_g = 0x0080, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
90 | /* { .offset = B2062_N_RXBB_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 90 | /* { .offset = B2062_N_RXBB_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
91 | /* { .offset = B2062_N_RXBB_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 91 | /* { .offset = B2062_N_RXBB_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
92 | /* { .offset = B2062_N_RXBB_GAIN0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 92 | /* { .offset = B2062_N_RXBB_GAIN0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
93 | { .offset = B2062_N_RXBB_GAIN1, .value_a = 0x0004, .value_g = 0x0004, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 93 | { .offset = B2062_N_RXBB_GAIN1, .value_a = 0x0004, .value_g = 0x0004, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
94 | { .offset = B2062_N_RXBB_GAIN2, .value_a = 0x0000, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 94 | { .offset = B2062_N_RXBB_GAIN2, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
95 | /* { .offset = B2062_N_RXBB_GAIN3, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */ | 95 | /* { .offset = B2062_N_RXBB_GAIN3, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */ |
96 | /* { .offset = B2062_N_RXBB_RSSI0, .value_a = 0x0043, .value_g = 0x0043, .flags = 0, }, */ | 96 | /* { .offset = B2062_N_RXBB_RSSI0, .value_a = 0x0043, .value_g = 0x0043, .flags = 0, }, */ |
97 | /* { .offset = B2062_N_RXBB_RSSI1, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ | 97 | /* { .offset = B2062_N_RXBB_RSSI1, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ |
@@ -112,8 +112,8 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { | |||
112 | /* { .offset = B2062_N_TX_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 112 | /* { .offset = B2062_N_TX_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
113 | /* { .offset = B2062_N_TX_CTL2, .value_a = 0x0084, .value_g = 0x0084, .flags = 0, }, */ | 113 | /* { .offset = B2062_N_TX_CTL2, .value_a = 0x0084, .value_g = 0x0084, .flags = 0, }, */ |
114 | /* { .offset = B2062_N_TX_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 114 | /* { .offset = B2062_N_TX_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
115 | { .offset = B2062_N_TX_CTL4, .value_a = 0x0003, .value_g = 0x0003, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 115 | { .offset = B2062_N_TX_CTL4, .value_a = 0x0003, .value_g = 0x0003, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
116 | { .offset = B2062_N_TX_CTL5, .value_a = 0x0002, .value_g = 0x0002, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 116 | { .offset = B2062_N_TX_CTL5, .value_a = 0x0002, .value_g = 0x0002, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
117 | /* { .offset = B2062_N_TX_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 117 | /* { .offset = B2062_N_TX_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
118 | /* { .offset = B2062_N_TX_CTL7, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */ | 118 | /* { .offset = B2062_N_TX_CTL7, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */ |
119 | /* { .offset = B2062_N_TX_CTL8, .value_a = 0x0082, .value_g = 0x0082, .flags = 0, }, */ | 119 | /* { .offset = B2062_N_TX_CTL8, .value_a = 0x0082, .value_g = 0x0082, .flags = 0, }, */ |
@@ -121,7 +121,7 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { | |||
121 | /* { .offset = B2062_N_TX_CTL_A, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 121 | /* { .offset = B2062_N_TX_CTL_A, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
122 | /* { .offset = B2062_N_TX_GC2G, .value_a = 0x00FF, .value_g = 0x00FF, .flags = 0, }, */ | 122 | /* { .offset = B2062_N_TX_GC2G, .value_a = 0x00FF, .value_g = 0x00FF, .flags = 0, }, */ |
123 | /* { .offset = B2062_N_TX_GC5G, .value_a = 0x00FF, .value_g = 0x00FF, .flags = 0, }, */ | 123 | /* { .offset = B2062_N_TX_GC5G, .value_a = 0x00FF, .value_g = 0x00FF, .flags = 0, }, */ |
124 | { .offset = B2062_N_TX_TUNE, .value_a = 0x0088, .value_g = 0x001B, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 124 | { .offset = B2062_N_TX_TUNE, .value_a = 0x0088, .value_g = 0x001B, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
125 | /* { .offset = B2062_N_TX_PAD, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ | 125 | /* { .offset = B2062_N_TX_PAD, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ |
126 | /* { .offset = B2062_N_TX_PGA, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ | 126 | /* { .offset = B2062_N_TX_PGA, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ |
127 | /* { .offset = B2062_N_TX_PADAUX, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ | 127 | /* { .offset = B2062_N_TX_PADAUX, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ |
@@ -150,7 +150,7 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { | |||
150 | /* { .offset = B2062_S_RADIO_ID_CODE, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 150 | /* { .offset = B2062_S_RADIO_ID_CODE, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
151 | /* { .offset = B2062_S_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 151 | /* { .offset = B2062_S_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
152 | /* { .offset = B2062_S_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 152 | /* { .offset = B2062_S_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
153 | { .offset = B2062_S_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 153 | { .offset = B2062_S_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
154 | /* { .offset = B2062_S_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 154 | /* { .offset = B2062_S_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
155 | /* { .offset = B2062_S_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 155 | /* { .offset = B2062_S_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
156 | /* { .offset = B2062_S_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 156 | /* { .offset = B2062_S_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
@@ -162,24 +162,24 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { | |||
162 | /* { .offset = B2062_S_COMM13, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 162 | /* { .offset = B2062_S_COMM13, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
163 | /* { .offset = B2062_S_COMM14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 163 | /* { .offset = B2062_S_COMM14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
164 | /* { .offset = B2062_S_COMM15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 164 | /* { .offset = B2062_S_COMM15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
165 | { .offset = B2062_S_PDS_CTL0, .value_a = 0x00FF, .value_g = 0x00FF, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 165 | { .offset = B2062_S_PDS_CTL0, .value_a = 0x00FF, .value_g = 0x00FF, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
166 | /* { .offset = B2062_S_PDS_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 166 | /* { .offset = B2062_S_PDS_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
167 | /* { .offset = B2062_S_PDS_CTL2, .value_a = 0x008E, .value_g = 0x008E, .flags = 0, }, */ | 167 | /* { .offset = B2062_S_PDS_CTL2, .value_a = 0x008E, .value_g = 0x008E, .flags = 0, }, */ |
168 | /* { .offset = B2062_S_PDS_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 168 | /* { .offset = B2062_S_PDS_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
169 | /* { .offset = B2062_S_BG_CTL0, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */ | 169 | /* { .offset = B2062_S_BG_CTL0, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */ |
170 | /* { .offset = B2062_S_BG_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 170 | /* { .offset = B2062_S_BG_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
171 | /* { .offset = B2062_S_BG_CTL2, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */ | 171 | /* { .offset = B2062_S_BG_CTL2, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */ |
172 | { .offset = B2062_S_LGENG_CTL0, .value_a = 0x00F8, .value_g = 0x00D8, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 172 | { .offset = B2062_S_LGENG_CTL0, .value_a = 0x00F8, .value_g = 0x00D8, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
173 | { .offset = B2062_S_LGENG_CTL1, .value_a = 0x003C, .value_g = 0x0024, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 173 | { .offset = B2062_S_LGENG_CTL1, .value_a = 0x003C, .value_g = 0x0024, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
174 | /* { .offset = B2062_S_LGENG_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 174 | /* { .offset = B2062_S_LGENG_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
175 | /* { .offset = B2062_S_LGENG_CTL3, .value_a = 0x0041, .value_g = 0x0041, .flags = 0, }, */ | 175 | /* { .offset = B2062_S_LGENG_CTL3, .value_a = 0x0041, .value_g = 0x0041, .flags = 0, }, */ |
176 | /* { .offset = B2062_S_LGENG_CTL4, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ | 176 | /* { .offset = B2062_S_LGENG_CTL4, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ |
177 | /* { .offset = B2062_S_LGENG_CTL5, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ | 177 | /* { .offset = B2062_S_LGENG_CTL5, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ |
178 | /* { .offset = B2062_S_LGENG_CTL6, .value_a = 0x0022, .value_g = 0x0022, .flags = 0, }, */ | 178 | /* { .offset = B2062_S_LGENG_CTL6, .value_a = 0x0022, .value_g = 0x0022, .flags = 0, }, */ |
179 | /* { .offset = B2062_S_LGENG_CTL7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 179 | /* { .offset = B2062_S_LGENG_CTL7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
180 | { .offset = B2062_S_LGENG_CTL8, .value_a = 0x0088, .value_g = 0x0080, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 180 | { .offset = B2062_S_LGENG_CTL8, .value_a = 0x0088, .value_g = 0x0080, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
181 | /* { .offset = B2062_S_LGENG_CTL9, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ | 181 | /* { .offset = B2062_S_LGENG_CTL9, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ |
182 | { .offset = B2062_S_LGENG_CTL10, .value_a = 0x0088, .value_g = 0x0080, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 182 | { .offset = B2062_S_LGENG_CTL10, .value_a = 0x0088, .value_g = 0x0080, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
183 | /* { .offset = B2062_S_LGENG_CTL11, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 183 | /* { .offset = B2062_S_LGENG_CTL11, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
184 | /* { .offset = B2062_S_REFPLL_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 184 | /* { .offset = B2062_S_REFPLL_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
185 | /* { .offset = B2062_S_REFPLL_CTL1, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ | 185 | /* { .offset = B2062_S_REFPLL_CTL1, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ |
@@ -198,41 +198,41 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { | |||
198 | /* { .offset = B2062_S_REFPLL_CTL14, .value_a = 0x0075, .value_g = 0x0075, .flags = 0, }, */ | 198 | /* { .offset = B2062_S_REFPLL_CTL14, .value_a = 0x0075, .value_g = 0x0075, .flags = 0, }, */ |
199 | /* { .offset = B2062_S_REFPLL_CTL15, .value_a = 0x00B4, .value_g = 0x00B4, .flags = 0, }, */ | 199 | /* { .offset = B2062_S_REFPLL_CTL15, .value_a = 0x00B4, .value_g = 0x00B4, .flags = 0, }, */ |
200 | /* { .offset = B2062_S_REFPLL_CTL16, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 200 | /* { .offset = B2062_S_REFPLL_CTL16, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
201 | { .offset = B2062_S_RFPLL_CTL0, .value_a = 0x0098, .value_g = 0x0098, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 201 | { .offset = B2062_S_RFPLL_CTL0, .value_a = 0x0098, .value_g = 0x0098, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
202 | { .offset = B2062_S_RFPLL_CTL1, .value_a = 0x0010, .value_g = 0x0010, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 202 | { .offset = B2062_S_RFPLL_CTL1, .value_a = 0x0010, .value_g = 0x0010, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
203 | /* { .offset = B2062_S_RFPLL_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 203 | /* { .offset = B2062_S_RFPLL_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
204 | /* { .offset = B2062_S_RFPLL_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 204 | /* { .offset = B2062_S_RFPLL_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
205 | /* { .offset = B2062_S_RFPLL_CTL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 205 | /* { .offset = B2062_S_RFPLL_CTL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
206 | { .offset = B2062_S_RFPLL_CTL5, .value_a = 0x0043, .value_g = 0x0043, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 206 | { .offset = B2062_S_RFPLL_CTL5, .value_a = 0x0043, .value_g = 0x0043, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
207 | { .offset = B2062_S_RFPLL_CTL6, .value_a = 0x0047, .value_g = 0x0047, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 207 | { .offset = B2062_S_RFPLL_CTL6, .value_a = 0x0047, .value_g = 0x0047, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
208 | { .offset = B2062_S_RFPLL_CTL7, .value_a = 0x000C, .value_g = 0x000C, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 208 | { .offset = B2062_S_RFPLL_CTL7, .value_a = 0x000C, .value_g = 0x000C, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
209 | { .offset = B2062_S_RFPLL_CTL8, .value_a = 0x0011, .value_g = 0x0011, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 209 | { .offset = B2062_S_RFPLL_CTL8, .value_a = 0x0011, .value_g = 0x0011, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
210 | { .offset = B2062_S_RFPLL_CTL9, .value_a = 0x0011, .value_g = 0x0011, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 210 | { .offset = B2062_S_RFPLL_CTL9, .value_a = 0x0011, .value_g = 0x0011, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
211 | { .offset = B2062_S_RFPLL_CTL10, .value_a = 0x000E, .value_g = 0x000E, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 211 | { .offset = B2062_S_RFPLL_CTL10, .value_a = 0x000E, .value_g = 0x000E, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
212 | { .offset = B2062_S_RFPLL_CTL11, .value_a = 0x0008, .value_g = 0x0008, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 212 | { .offset = B2062_S_RFPLL_CTL11, .value_a = 0x0008, .value_g = 0x0008, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
213 | { .offset = B2062_S_RFPLL_CTL12, .value_a = 0x0033, .value_g = 0x0033, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 213 | { .offset = B2062_S_RFPLL_CTL12, .value_a = 0x0033, .value_g = 0x0033, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
214 | { .offset = B2062_S_RFPLL_CTL13, .value_a = 0x000A, .value_g = 0x000A, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 214 | { .offset = B2062_S_RFPLL_CTL13, .value_a = 0x000A, .value_g = 0x000A, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
215 | { .offset = B2062_S_RFPLL_CTL14, .value_a = 0x0006, .value_g = 0x0006, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 215 | { .offset = B2062_S_RFPLL_CTL14, .value_a = 0x0006, .value_g = 0x0006, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
216 | /* { .offset = B2062_S_RFPLL_CTL15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 216 | /* { .offset = B2062_S_RFPLL_CTL15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
217 | /* { .offset = B2062_S_RFPLL_CTL16, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 217 | /* { .offset = B2062_S_RFPLL_CTL16, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
218 | /* { .offset = B2062_S_RFPLL_CTL17, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 218 | /* { .offset = B2062_S_RFPLL_CTL17, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
219 | { .offset = B2062_S_RFPLL_CTL18, .value_a = 0x003E, .value_g = 0x003E, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 219 | { .offset = B2062_S_RFPLL_CTL18, .value_a = 0x003E, .value_g = 0x003E, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
220 | { .offset = B2062_S_RFPLL_CTL19, .value_a = 0x0013, .value_g = 0x0013, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 220 | { .offset = B2062_S_RFPLL_CTL19, .value_a = 0x0013, .value_g = 0x0013, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
221 | /* { .offset = B2062_S_RFPLL_CTL20, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 221 | /* { .offset = B2062_S_RFPLL_CTL20, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
222 | { .offset = B2062_S_RFPLL_CTL21, .value_a = 0x0062, .value_g = 0x0062, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 222 | { .offset = B2062_S_RFPLL_CTL21, .value_a = 0x0062, .value_g = 0x0062, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
223 | { .offset = B2062_S_RFPLL_CTL22, .value_a = 0x0007, .value_g = 0x0007, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 223 | { .offset = B2062_S_RFPLL_CTL22, .value_a = 0x0007, .value_g = 0x0007, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
224 | { .offset = B2062_S_RFPLL_CTL23, .value_a = 0x0016, .value_g = 0x0016, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 224 | { .offset = B2062_S_RFPLL_CTL23, .value_a = 0x0016, .value_g = 0x0016, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
225 | { .offset = B2062_S_RFPLL_CTL24, .value_a = 0x005C, .value_g = 0x005C, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 225 | { .offset = B2062_S_RFPLL_CTL24, .value_a = 0x005C, .value_g = 0x005C, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
226 | { .offset = B2062_S_RFPLL_CTL25, .value_a = 0x0095, .value_g = 0x0095, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 226 | { .offset = B2062_S_RFPLL_CTL25, .value_a = 0x0095, .value_g = 0x0095, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
227 | /* { .offset = B2062_S_RFPLL_CTL26, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 227 | /* { .offset = B2062_S_RFPLL_CTL26, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
228 | /* { .offset = B2062_S_RFPLL_CTL27, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 228 | /* { .offset = B2062_S_RFPLL_CTL27, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
229 | /* { .offset = B2062_S_RFPLL_CTL28, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 229 | /* { .offset = B2062_S_RFPLL_CTL28, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
230 | /* { .offset = B2062_S_RFPLL_CTL29, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 230 | /* { .offset = B2062_S_RFPLL_CTL29, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
231 | { .offset = B2062_S_RFPLL_CTL30, .value_a = 0x00A0, .value_g = 0x00A0, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 231 | { .offset = B2062_S_RFPLL_CTL30, .value_a = 0x00A0, .value_g = 0x00A0, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
232 | { .offset = B2062_S_RFPLL_CTL31, .value_a = 0x0004, .value_g = 0x0004, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 232 | { .offset = B2062_S_RFPLL_CTL31, .value_a = 0x0004, .value_g = 0x0004, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
233 | /* { .offset = B2062_S_RFPLL_CTL32, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 233 | /* { .offset = B2062_S_RFPLL_CTL32, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
234 | { .offset = B2062_S_RFPLL_CTL33, .value_a = 0x00CC, .value_g = 0x00CC, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 234 | { .offset = B2062_S_RFPLL_CTL33, .value_a = 0x00CC, .value_g = 0x00CC, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
235 | { .offset = B2062_S_RFPLL_CTL34, .value_a = 0x0007, .value_g = 0x0007, .flags = B2062_FLAG_A | B2062_FLAG_G, }, | 235 | { .offset = B2062_S_RFPLL_CTL34, .value_a = 0x0007, .value_g = 0x0007, .flags = B206X_FLAG_A | B206X_FLAG_G, }, |
236 | /* { .offset = B2062_S_RXG_CNT0, .value_a = 0x0010, .value_g = 0x0010, .flags = 0, }, */ | 236 | /* { .offset = B2062_S_RXG_CNT0, .value_a = 0x0010, .value_g = 0x0010, .flags = 0, }, */ |
237 | /* { .offset = B2062_S_RXG_CNT1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 237 | /* { .offset = B2062_S_RXG_CNT1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
238 | /* { .offset = B2062_S_RXG_CNT2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 238 | /* { .offset = B2062_S_RXG_CNT2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
@@ -241,7 +241,7 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { | |||
241 | /* { .offset = B2062_S_RXG_CNT5, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ | 241 | /* { .offset = B2062_S_RXG_CNT5, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ |
242 | /* { .offset = B2062_S_RXG_CNT6, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ | 242 | /* { .offset = B2062_S_RXG_CNT6, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ |
243 | /* { .offset = B2062_S_RXG_CNT7, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ | 243 | /* { .offset = B2062_S_RXG_CNT7, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ |
244 | { .offset = B2062_S_RXG_CNT8, .value_a = 0x000F, .value_g = 0x000F, .flags = B2062_FLAG_A, }, | 244 | { .offset = B2062_S_RXG_CNT8, .value_a = 0x000F, .value_g = 0x000F, .flags = B206X_FLAG_A, }, |
245 | /* { .offset = B2062_S_RXG_CNT9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | 245 | /* { .offset = B2062_S_RXG_CNT9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ |
246 | /* { .offset = B2062_S_RXG_CNT10, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ | 246 | /* { .offset = B2062_S_RXG_CNT10, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ |
247 | /* { .offset = B2062_S_RXG_CNT11, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | 247 | /* { .offset = B2062_S_RXG_CNT11, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ |
@@ -253,19 +253,337 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { | |||
253 | /* { .offset = B2062_S_RXG_CNT17, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ | 253 | /* { .offset = B2062_S_RXG_CNT17, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ |
254 | }; | 254 | }; |
255 | 255 | ||
256 | static const struct b206x_init_tab_entry b2063_init_tab[] = { | ||
257 | { .offset = B2063_COMM1, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, | ||
258 | /* { .offset = B2063_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
259 | /* { .offset = B2063_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
260 | /* { .offset = B2063_COMM4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
261 | /* { .offset = B2063_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
262 | /* { .offset = B2063_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
263 | /* { .offset = B2063_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
264 | /* { .offset = B2063_COMM8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
265 | /* { .offset = B2063_COMM9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
266 | { .offset = B2063_COMM10, .value_a = 0x0001, .value_g = 0x0000, .flags = B206X_FLAG_A, }, | ||
267 | /* { .offset = B2063_COMM11, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
268 | /* { .offset = B2063_COMM12, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
269 | /* { .offset = B2063_COMM13, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
270 | /* { .offset = B2063_COMM14, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */ | ||
271 | /* { .offset = B2063_COMM15, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */ | ||
272 | { .offset = B2063_COMM16, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, | ||
273 | { .offset = B2063_COMM17, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, | ||
274 | { .offset = B2063_COMM18, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, | ||
275 | { .offset = B2063_COMM19, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, | ||
276 | { .offset = B2063_COMM20, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, | ||
277 | { .offset = B2063_COMM21, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, | ||
278 | { .offset = B2063_COMM22, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, | ||
279 | { .offset = B2063_COMM23, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, | ||
280 | { .offset = B2063_COMM24, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, | ||
281 | /* { .offset = B2063_PWR_SWITCH_CTL, .value_a = 0x007f, .value_g = 0x007f, .flags = 0, }, */ | ||
282 | /* { .offset = B2063_PLL_SP1, .value_a = 0x003f, .value_g = 0x003f, .flags = 0, }, */ | ||
283 | /* { .offset = B2063_PLL_SP2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
284 | { .offset = B2063_LOGEN_SP1, .value_a = 0x00e8, .value_g = 0x00d4, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
285 | { .offset = B2063_LOGEN_SP2, .value_a = 0x00a7, .value_g = 0x0053, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
286 | /* { .offset = B2063_LOGEN_SP3, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ | ||
287 | { .offset = B2063_LOGEN_SP4, .value_a = 0x00f0, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
288 | /* { .offset = B2063_LOGEN_SP5, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ | ||
289 | { .offset = B2063_G_RX_SP1, .value_a = 0x001f, .value_g = 0x005e, .flags = B206X_FLAG_G, }, | ||
290 | { .offset = B2063_G_RX_SP2, .value_a = 0x007f, .value_g = 0x007e, .flags = B206X_FLAG_G, }, | ||
291 | { .offset = B2063_G_RX_SP3, .value_a = 0x0030, .value_g = 0x00f0, .flags = B206X_FLAG_G, }, | ||
292 | /* { .offset = B2063_G_RX_SP4, .value_a = 0x0035, .value_g = 0x0035, .flags = 0, }, */ | ||
293 | /* { .offset = B2063_G_RX_SP5, .value_a = 0x003f, .value_g = 0x003f, .flags = 0, }, */ | ||
294 | /* { .offset = B2063_G_RX_SP6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
295 | { .offset = B2063_G_RX_SP7, .value_a = 0x007f, .value_g = 0x007f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
296 | /* { .offset = B2063_G_RX_SP8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
297 | /* { .offset = B2063_G_RX_SP9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
298 | { .offset = B2063_G_RX_SP10, .value_a = 0x000c, .value_g = 0x000c, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
299 | /* { .offset = B2063_G_RX_SP11, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
300 | { .offset = B2063_A_RX_SP1, .value_a = 0x003c, .value_g = 0x003f, .flags = B206X_FLAG_A, }, | ||
301 | { .offset = B2063_A_RX_SP2, .value_a = 0x00fc, .value_g = 0x00fe, .flags = B206X_FLAG_A, }, | ||
302 | /* { .offset = B2063_A_RX_SP3, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ | ||
303 | /* { .offset = B2063_A_RX_SP4, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ | ||
304 | /* { .offset = B2063_A_RX_SP5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
305 | /* { .offset = B2063_A_RX_SP6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
306 | { .offset = B2063_A_RX_SP7, .value_a = 0x0008, .value_g = 0x0008, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
307 | /* { .offset = B2063_RX_BB_SP1, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */ | ||
308 | /* { .offset = B2063_RX_BB_SP2, .value_a = 0x0022, .value_g = 0x0022, .flags = 0, }, */ | ||
309 | /* { .offset = B2063_RX_BB_SP3, .value_a = 0x00a8, .value_g = 0x00a8, .flags = 0, }, */ | ||
310 | { .offset = B2063_RX_BB_SP4, .value_a = 0x0060, .value_g = 0x0060, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
311 | /* { .offset = B2063_RX_BB_SP5, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */ | ||
312 | /* { .offset = B2063_RX_BB_SP6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
313 | /* { .offset = B2063_RX_BB_SP7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
314 | { .offset = B2063_RX_BB_SP8, .value_a = 0x0030, .value_g = 0x0030, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
315 | /* { .offset = B2063_TX_RF_SP1, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ | ||
316 | /* { .offset = B2063_TX_RF_SP2, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */ | ||
317 | { .offset = B2063_TX_RF_SP3, .value_a = 0x000c, .value_g = 0x000b, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
318 | { .offset = B2063_TX_RF_SP4, .value_a = 0x0010, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
319 | /* { .offset = B2063_TX_RF_SP5, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */ | ||
320 | /* { .offset = B2063_TX_RF_SP6, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ | ||
321 | /* { .offset = B2063_TX_RF_SP7, .value_a = 0x0068, .value_g = 0x0068, .flags = 0, }, */ | ||
322 | /* { .offset = B2063_TX_RF_SP8, .value_a = 0x0068, .value_g = 0x0068, .flags = 0, }, */ | ||
323 | /* { .offset = B2063_TX_RF_SP9, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ | ||
324 | /* { .offset = B2063_TX_RF_SP10, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ | ||
325 | /* { .offset = B2063_TX_RF_SP11, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */ | ||
326 | /* { .offset = B2063_TX_RF_SP12, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */ | ||
327 | /* { .offset = B2063_TX_RF_SP13, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ | ||
328 | /* { .offset = B2063_TX_RF_SP14, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */ | ||
329 | /* { .offset = B2063_TX_RF_SP15, .value_a = 0x00c0, .value_g = 0x00c0, .flags = 0, }, */ | ||
330 | /* { .offset = B2063_TX_RF_SP16, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ | ||
331 | /* { .offset = B2063_TX_RF_SP17, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ | ||
332 | { .offset = B2063_PA_SP1, .value_a = 0x003d, .value_g = 0x00fd, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
333 | /* { .offset = B2063_PA_SP2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */ | ||
334 | /* { .offset = B2063_PA_SP3, .value_a = 0x0096, .value_g = 0x0096, .flags = 0, }, */ | ||
335 | /* { .offset = B2063_PA_SP4, .value_a = 0x005a, .value_g = 0x005a, .flags = 0, }, */ | ||
336 | /* { .offset = B2063_PA_SP5, .value_a = 0x007f, .value_g = 0x007f, .flags = 0, }, */ | ||
337 | /* { .offset = B2063_PA_SP6, .value_a = 0x007f, .value_g = 0x007f, .flags = 0, }, */ | ||
338 | /* { .offset = B2063_PA_SP7, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ | ||
339 | { .offset = B2063_TX_BB_SP1, .value_a = 0x0002, .value_g = 0x0002, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
340 | /* { .offset = B2063_TX_BB_SP2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
341 | /* { .offset = B2063_TX_BB_SP3, .value_a = 0x0030, .value_g = 0x0030, .flags = 0, }, */ | ||
342 | /* { .offset = B2063_REG_SP1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
343 | { .offset = B2063_BANDGAP_CTL1, .value_a = 0x0056, .value_g = 0x0056, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
344 | /* { .offset = B2063_BANDGAP_CTL2, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */ | ||
345 | /* { .offset = B2063_LPO_CTL1, .value_a = 0x000e, .value_g = 0x000e, .flags = 0, }, */ | ||
346 | /* { .offset = B2063_RC_CALIB_CTL1, .value_a = 0x007e, .value_g = 0x007e, .flags = 0, }, */ | ||
347 | /* { .offset = B2063_RC_CALIB_CTL2, .value_a = 0x0015, .value_g = 0x0015, .flags = 0, }, */ | ||
348 | /* { .offset = B2063_RC_CALIB_CTL3, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */ | ||
349 | /* { .offset = B2063_RC_CALIB_CTL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
350 | /* { .offset = B2063_RC_CALIB_CTL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
351 | /* { .offset = B2063_RC_CALIB_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
352 | /* { .offset = B2063_RC_CALIB_CTL7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
353 | /* { .offset = B2063_RC_CALIB_CTL8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
354 | /* { .offset = B2063_RC_CALIB_CTL9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
355 | /* { .offset = B2063_RC_CALIB_CTL10, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
356 | /* { .offset = B2063_PLL_JTAG_CALNRST, .value_a = 0x0004, .value_g = 0x0004, .flags = 0, }, */ | ||
357 | /* { .offset = B2063_PLL_JTAG_IN_PLL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
358 | /* { .offset = B2063_PLL_JTAG_IN_PLL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
359 | /* { .offset = B2063_PLL_JTAG_PLL_CP1, .value_a = 0x00cf, .value_g = 0x00cf, .flags = 0, }, */ | ||
360 | /* { .offset = B2063_PLL_JTAG_PLL_CP2, .value_a = 0x0059, .value_g = 0x0059, .flags = 0, }, */ | ||
361 | /* { .offset = B2063_PLL_JTAG_PLL_CP3, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ | ||
362 | /* { .offset = B2063_PLL_JTAG_PLL_CP4, .value_a = 0x0042, .value_g = 0x0042, .flags = 0, }, */ | ||
363 | /* { .offset = B2063_PLL_JTAG_PLL_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
364 | /* { .offset = B2063_PLL_JTAG_PLL_LF1, .value_a = 0x00db, .value_g = 0x00db, .flags = 0, }, */ | ||
365 | /* { .offset = B2063_PLL_JTAG_PLL_LF2, .value_a = 0x0094, .value_g = 0x0094, .flags = 0, }, */ | ||
366 | /* { .offset = B2063_PLL_JTAG_PLL_LF3, .value_a = 0x0028, .value_g = 0x0028, .flags = 0, }, */ | ||
367 | /* { .offset = B2063_PLL_JTAG_PLL_LF4, .value_a = 0x0063, .value_g = 0x0063, .flags = 0, }, */ | ||
368 | /* { .offset = B2063_PLL_JTAG_PLL_SG1, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ | ||
369 | /* { .offset = B2063_PLL_JTAG_PLL_SG2, .value_a = 0x00d3, .value_g = 0x00d3, .flags = 0, }, */ | ||
370 | /* { .offset = B2063_PLL_JTAG_PLL_SG3, .value_a = 0x00b1, .value_g = 0x00b1, .flags = 0, }, */ | ||
371 | /* { .offset = B2063_PLL_JTAG_PLL_SG4, .value_a = 0x003b, .value_g = 0x003b, .flags = 0, }, */ | ||
372 | /* { .offset = B2063_PLL_JTAG_PLL_SG5, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */ | ||
373 | /* { .offset = B2063_PLL_JTAG_PLL_VCO1, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */ | ||
374 | { .offset = B2063_PLL_JTAG_PLL_VCO2, .value_a = 0x00f7, .value_g = 0x00f7, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
375 | /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
376 | /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
377 | /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB3, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ | ||
378 | /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
379 | /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB5, .value_a = 0x0009, .value_g = 0x0009, .flags = 0, }, */ | ||
380 | /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB6, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ | ||
381 | /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB7, .value_a = 0x0016, .value_g = 0x0016, .flags = 0, }, */ | ||
382 | /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB8, .value_a = 0x006b, .value_g = 0x006b, .flags = 0, }, */ | ||
383 | /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
384 | /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB10, .value_a = 0x00b3, .value_g = 0x00b3, .flags = 0, }, */ | ||
385 | /* { .offset = B2063_PLL_JTAG_PLL_XTAL_12, .value_a = 0x0004, .value_g = 0x0004, .flags = 0, }, */ | ||
386 | /* { .offset = B2063_PLL_JTAG_PLL_XTAL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
387 | /* { .offset = B2063_LOGEN_ACL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
388 | /* { .offset = B2063_LOGEN_ACL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
389 | /* { .offset = B2063_LOGEN_ACL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
390 | /* { .offset = B2063_LOGEN_ACL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
391 | /* { .offset = B2063_LOGEN_ACL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
392 | /* { .offset = B2063_LO_CALIB_INPUTS, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
393 | /* { .offset = B2063_LO_CALIB_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
394 | /* { .offset = B2063_LO_CALIB_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
395 | /* { .offset = B2063_LO_CALIB_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
396 | /* { .offset = B2063_LO_CALIB_WAITCNT, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ | ||
397 | /* { .offset = B2063_LO_CALIB_OVR1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
398 | /* { .offset = B2063_LO_CALIB_OVR2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
399 | /* { .offset = B2063_LO_CALIB_OVAL1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
400 | /* { .offset = B2063_LO_CALIB_OVAL2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
401 | /* { .offset = B2063_LO_CALIB_OVAL3, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
402 | /* { .offset = B2063_LO_CALIB_OVAL4, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
403 | /* { .offset = B2063_LO_CALIB_OVAL5, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
404 | /* { .offset = B2063_LO_CALIB_OVAL6, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
405 | /* { .offset = B2063_LO_CALIB_OVAL7, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
406 | /* { .offset = B2063_LO_CALIB_CALVLD1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
407 | /* { .offset = B2063_LO_CALIB_CALVLD2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
408 | /* { .offset = B2063_LO_CALIB_CVAL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
409 | /* { .offset = B2063_LO_CALIB_CVAL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
410 | /* { .offset = B2063_LO_CALIB_CVAL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
411 | /* { .offset = B2063_LO_CALIB_CVAL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
412 | /* { .offset = B2063_LO_CALIB_CVAL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
413 | /* { .offset = B2063_LO_CALIB_CVAL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
414 | /* { .offset = B2063_LO_CALIB_CVAL7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
415 | /* { .offset = B2063_LOGEN_CALIB_EN, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
416 | /* { .offset = B2063_LOGEN_PEAKDET1, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ | ||
417 | /* { .offset = B2063_LOGEN_RCCR1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
418 | /* { .offset = B2063_LOGEN_VCOBUF1, .value_a = 0x0060, .value_g = 0x0060, .flags = 0, }, */ | ||
419 | /* { .offset = B2063_LOGEN_MIXER1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
420 | /* { .offset = B2063_LOGEN_MIXER2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */ | ||
421 | /* { .offset = B2063_LOGEN_BUF1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
422 | /* { .offset = B2063_LOGEN_BUF2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */ | ||
423 | /* { .offset = B2063_LOGEN_DIV1, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ | ||
424 | /* { .offset = B2063_LOGEN_DIV2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
425 | /* { .offset = B2063_LOGEN_DIV3, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
426 | /* { .offset = B2063_LOGEN_CBUFRX1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
427 | /* { .offset = B2063_LOGEN_CBUFRX2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
428 | /* { .offset = B2063_LOGEN_CBUFTX1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
429 | /* { .offset = B2063_LOGEN_CBUFTX2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ | ||
430 | /* { .offset = B2063_LOGEN_IDAC1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
431 | /* { .offset = B2063_LOGEN_SPARE1, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ | ||
432 | /* { .offset = B2063_LOGEN_SPARE2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
433 | /* { .offset = B2063_LOGEN_SPARE3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
434 | /* { .offset = B2063_G_RX_1ST1, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ | ||
435 | /* { .offset = B2063_G_RX_1ST2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
436 | /* { .offset = B2063_G_RX_1ST3, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ | ||
437 | /* { .offset = B2063_G_RX_2ND1, .value_a = 0x0030, .value_g = 0x0030, .flags = 0, }, */ | ||
438 | /* { .offset = B2063_G_RX_2ND2, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ | ||
439 | /* { .offset = B2063_G_RX_2ND3, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ | ||
440 | /* { .offset = B2063_G_RX_2ND4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
441 | /* { .offset = B2063_G_RX_2ND5, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ | ||
442 | /* { .offset = B2063_G_RX_2ND6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
443 | /* { .offset = B2063_G_RX_2ND7, .value_a = 0x0035, .value_g = 0x0035, .flags = 0, }, */ | ||
444 | /* { .offset = B2063_G_RX_2ND8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
445 | /* { .offset = B2063_G_RX_PS1, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ | ||
446 | /* { .offset = B2063_G_RX_PS2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
447 | /* { .offset = B2063_G_RX_PS3, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ | ||
448 | /* { .offset = B2063_G_RX_PS4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
449 | /* { .offset = B2063_G_RX_PS5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
450 | /* { .offset = B2063_G_RX_MIX1, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */ | ||
451 | /* { .offset = B2063_G_RX_MIX2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
452 | { .offset = B2063_G_RX_MIX3, .value_a = 0x0071, .value_g = 0x0071, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
453 | { .offset = B2063_G_RX_MIX4, .value_a = 0x0071, .value_g = 0x0071, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
454 | /* { .offset = B2063_G_RX_MIX5, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */ | ||
455 | /* { .offset = B2063_G_RX_MIX6, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ | ||
456 | /* { .offset = B2063_G_RX_MIX7, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */ | ||
457 | /* { .offset = B2063_G_RX_MIX8, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ | ||
458 | /* { .offset = B2063_G_RX_PDET1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
459 | /* { .offset = B2063_G_RX_SPARES1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
460 | /* { .offset = B2063_G_RX_SPARES2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
461 | /* { .offset = B2063_G_RX_SPARES3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
462 | /* { .offset = B2063_A_RX_1ST1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
463 | { .offset = B2063_A_RX_1ST2, .value_a = 0x00f0, .value_g = 0x0030, .flags = B206X_FLAG_A, }, | ||
464 | /* { .offset = B2063_A_RX_1ST3, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ | ||
465 | /* { .offset = B2063_A_RX_1ST4, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ | ||
466 | /* { .offset = B2063_A_RX_1ST5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
467 | /* { .offset = B2063_A_RX_2ND1, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ | ||
468 | /* { .offset = B2063_A_RX_2ND2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
469 | /* { .offset = B2063_A_RX_2ND3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
470 | /* { .offset = B2063_A_RX_2ND4, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ | ||
471 | /* { .offset = B2063_A_RX_2ND5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
472 | /* { .offset = B2063_A_RX_2ND6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
473 | /* { .offset = B2063_A_RX_2ND7, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ | ||
474 | /* { .offset = B2063_A_RX_PS1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
475 | /* { .offset = B2063_A_RX_PS2, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ | ||
476 | /* { .offset = B2063_A_RX_PS3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
477 | /* { .offset = B2063_A_RX_PS4, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ | ||
478 | /* { .offset = B2063_A_RX_PS5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
479 | { .offset = B2063_A_RX_PS6, .value_a = 0x0077, .value_g = 0x0077, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
480 | /* { .offset = B2063_A_RX_MIX1, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ | ||
481 | /* { .offset = B2063_A_RX_MIX2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
482 | /* { .offset = B2063_A_RX_MIX3, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */ | ||
483 | { .offset = B2063_A_RX_MIX4, .value_a = 0x0003, .value_g = 0x0003, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
484 | { .offset = B2063_A_RX_MIX5, .value_a = 0x000f, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
485 | { .offset = B2063_A_RX_MIX6, .value_a = 0x000f, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
486 | /* { .offset = B2063_A_RX_MIX7, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */ | ||
487 | /* { .offset = B2063_A_RX_MIX8, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ | ||
488 | /* { .offset = B2063_A_RX_PWRDET1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
489 | /* { .offset = B2063_A_RX_SPARE1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
490 | /* { .offset = B2063_A_RX_SPARE2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
491 | /* { .offset = B2063_A_RX_SPARE3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
492 | { .offset = B2063_RX_TIA_CTL1, .value_a = 0x0077, .value_g = 0x0077, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
493 | /* { .offset = B2063_RX_TIA_CTL2, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */ | ||
494 | { .offset = B2063_RX_TIA_CTL3, .value_a = 0x0077, .value_g = 0x0077, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
495 | /* { .offset = B2063_RX_TIA_CTL4, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */ | ||
496 | /* { .offset = B2063_RX_TIA_CTL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
497 | /* { .offset = B2063_RX_TIA_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
498 | /* { .offset = B2063_RX_BB_CTL1, .value_a = 0x0074, .value_g = 0x0074, .flags = 0, }, */ | ||
499 | { .offset = B2063_RX_BB_CTL2, .value_a = 0x0004, .value_g = 0x0004, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
500 | /* { .offset = B2063_RX_BB_CTL3, .value_a = 0x00a2, .value_g = 0x00a2, .flags = 0, }, */ | ||
501 | /* { .offset = B2063_RX_BB_CTL4, .value_a = 0x00aa, .value_g = 0x00aa, .flags = 0, }, */ | ||
502 | /* { .offset = B2063_RX_BB_CTL5, .value_a = 0x0024, .value_g = 0x0024, .flags = 0, }, */ | ||
503 | /* { .offset = B2063_RX_BB_CTL6, .value_a = 0x00a9, .value_g = 0x00a9, .flags = 0, }, */ | ||
504 | /* { .offset = B2063_RX_BB_CTL7, .value_a = 0x0028, .value_g = 0x0028, .flags = 0, }, */ | ||
505 | /* { .offset = B2063_RX_BB_CTL8, .value_a = 0x0010, .value_g = 0x0010, .flags = 0, }, */ | ||
506 | /* { .offset = B2063_RX_BB_CTL9, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ | ||
507 | /* { .offset = B2063_TX_RF_CTL1, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ | ||
508 | /* { .offset = B2063_TX_RF_IDAC_LO_RF_I, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ | ||
509 | /* { .offset = B2063_TX_RF_IDAC_LO_RF_Q, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ | ||
510 | /* { .offset = B2063_TX_RF_IDAC_LO_BB_I, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ | ||
511 | /* { .offset = B2063_TX_RF_IDAC_LO_BB_Q, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ | ||
512 | /* { .offset = B2063_TX_RF_CTL2, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ | ||
513 | /* { .offset = B2063_TX_RF_CTL3, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */ | ||
514 | /* { .offset = B2063_TX_RF_CTL4, .value_a = 0x00b8, .value_g = 0x00b8, .flags = 0, }, */ | ||
515 | /* { .offset = B2063_TX_RF_CTL5, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ | ||
516 | /* { .offset = B2063_TX_RF_CTL6, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */ | ||
517 | /* { .offset = B2063_TX_RF_CTL7, .value_a = 0x0078, .value_g = 0x0078, .flags = 0, }, */ | ||
518 | /* { .offset = B2063_TX_RF_CTL8, .value_a = 0x00c0, .value_g = 0x00c0, .flags = 0, }, */ | ||
519 | /* { .offset = B2063_TX_RF_CTL9, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */ | ||
520 | /* { .offset = B2063_TX_RF_CTL10, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
521 | /* { .offset = B2063_TX_RF_CTL14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
522 | /* { .offset = B2063_TX_RF_CTL15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
523 | { .offset = B2063_PA_CTL1, .value_a = 0x0000, .value_g = 0x0004, .flags = B206X_FLAG_A, }, | ||
524 | /* { .offset = B2063_PA_CTL2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */ | ||
525 | /* { .offset = B2063_PA_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
526 | /* { .offset = B2063_PA_CTL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
527 | /* { .offset = B2063_PA_CTL5, .value_a = 0x0096, .value_g = 0x0096, .flags = 0, }, */ | ||
528 | /* { .offset = B2063_PA_CTL6, .value_a = 0x0077, .value_g = 0x0077, .flags = 0, }, */ | ||
529 | /* { .offset = B2063_PA_CTL7, .value_a = 0x005a, .value_g = 0x005a, .flags = 0, }, */ | ||
530 | /* { .offset = B2063_PA_CTL8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
531 | /* { .offset = B2063_PA_CTL9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
532 | /* { .offset = B2063_PA_CTL10, .value_a = 0x0021, .value_g = 0x0021, .flags = 0, }, */ | ||
533 | /* { .offset = B2063_PA_CTL11, .value_a = 0x0070, .value_g = 0x0070, .flags = 0, }, */ | ||
534 | /* { .offset = B2063_PA_CTL12, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
535 | /* { .offset = B2063_PA_CTL13, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
536 | /* { .offset = B2063_TX_BB_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
537 | /* { .offset = B2063_TX_BB_CTL2, .value_a = 0x00b3, .value_g = 0x00b3, .flags = 0, }, */ | ||
538 | /* { .offset = B2063_TX_BB_CTL3, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ | ||
539 | /* { .offset = B2063_TX_BB_CTL4, .value_a = 0x000b, .value_g = 0x000b, .flags = 0, }, */ | ||
540 | /* { .offset = B2063_GPIO_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
541 | { .offset = B2063_VREG_CTL1, .value_a = 0x0003, .value_g = 0x0003, .flags = B206X_FLAG_A | B206X_FLAG_G, }, | ||
542 | /* { .offset = B2063_AMUX_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
543 | /* { .offset = B2063_IQ_CALIB_GVAR, .value_a = 0x00b3, .value_g = 0x00b3, .flags = 0, }, */ | ||
544 | /* { .offset = B2063_IQ_CALIB_CTL1, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ | ||
545 | /* { .offset = B2063_IQ_CALIB_CTL2, .value_a = 0x0030, .value_g = 0x0030, .flags = 0, }, */ | ||
546 | /* { .offset = B2063_TEMPSENSE_CTL1, .value_a = 0x0046, .value_g = 0x0046, .flags = 0, }, */ | ||
547 | /* { .offset = B2063_TEMPSENSE_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
548 | /* { .offset = B2063_TX_RX_LOOPBACK1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
549 | /* { .offset = B2063_TX_RX_LOOPBACK2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ | ||
550 | /* { .offset = B2063_EXT_TSSI_CTL1, .value_a = 0x0021, .value_g = 0x0021, .flags = 0, }, */ | ||
551 | /* { .offset = B2063_EXT_TSSI_CTL2, .value_a = 0x0023, .value_g = 0x0023, .flags = 0, }, */ | ||
552 | /* { .offset = B2063_AFE_CTL , .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ | ||
553 | }; | ||
554 | |||
256 | void b2062_upload_init_table(struct b43_wldev *dev) | 555 | void b2062_upload_init_table(struct b43_wldev *dev) |
257 | { | 556 | { |
258 | const struct b2062_init_tab_entry *e; | 557 | const struct b206x_init_tab_entry *e; |
259 | unsigned int i; | 558 | unsigned int i; |
260 | 559 | ||
261 | for (i = 0; i < ARRAY_SIZE(b2062_init_tab); i++) { | 560 | for (i = 0; i < ARRAY_SIZE(b2062_init_tab); i++) { |
262 | e = &b2062_init_tab[i]; | 561 | e = &b2062_init_tab[i]; |
263 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { | 562 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { |
264 | if (!(e->flags & B2062_FLAG_G)) | 563 | if (!(e->flags & B206X_FLAG_G)) |
564 | continue; | ||
565 | b43_radio_write(dev, e->offset, e->value_g); | ||
566 | } else { | ||
567 | if (!(e->flags & B206X_FLAG_A)) | ||
568 | continue; | ||
569 | b43_radio_write(dev, e->offset, e->value_a); | ||
570 | } | ||
571 | } | ||
572 | } | ||
573 | |||
574 | void b2063_upload_init_table(struct b43_wldev *dev) | ||
575 | { | ||
576 | const struct b206x_init_tab_entry *e; | ||
577 | unsigned int i; | ||
578 | |||
579 | for (i = 0; i < ARRAY_SIZE(b2063_init_tab); i++) { | ||
580 | e = &b2063_init_tab[i]; | ||
581 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { | ||
582 | if (!(e->flags & B206X_FLAG_G)) | ||
265 | continue; | 583 | continue; |
266 | b43_radio_write(dev, e->offset, e->value_g); | 584 | b43_radio_write(dev, e->offset, e->value_g); |
267 | } else { | 585 | } else { |
268 | if (!(e->flags & B2062_FLAG_A)) | 586 | if (!(e->flags & B206X_FLAG_A)) |
269 | continue; | 587 | continue; |
270 | b43_radio_write(dev, e->offset, e->value_a); | 588 | b43_radio_write(dev, e->offset, e->value_a); |
271 | } | 589 | } |
@@ -392,3 +710,1726 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, | |||
392 | offset++; | 710 | offset++; |
393 | } | 711 | } |
394 | } | 712 | } |
713 | |||
714 | static const u8 lpphy_min_sig_sq_table[] = { | ||
715 | 0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xcf, 0xcd, | ||
716 | 0xca, 0xc7, 0xc4, 0xc1, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, | ||
717 | 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x00, | ||
718 | 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, | ||
719 | 0xbe, 0xbe, 0xbe, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd, | ||
720 | 0xcf, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, | ||
721 | }; | ||
722 | |||
723 | static const u16 lpphy_rev01_noise_scale_table[] = { | ||
724 | 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, | ||
725 | 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, | ||
726 | 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0x00a4, | ||
727 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4c00, 0x2d36, | ||
728 | 0x0000, 0x0000, 0x4c00, 0x2d36, | ||
729 | }; | ||
730 | |||
731 | static const u16 lpphy_rev2plus_noise_scale_table[] = { | ||
732 | 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, | ||
733 | 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, | ||
734 | 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x0000, | ||
735 | 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, | ||
736 | 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, | ||
737 | 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, | ||
738 | 0x00a4, | ||
739 | }; | ||
740 | |||
741 | static const u16 lpphy_crs_gain_nft_table[] = { | ||
742 | 0x0366, 0x036a, 0x036f, 0x0364, 0x0367, 0x036d, 0x0374, 0x037f, 0x036f, | ||
743 | 0x037b, 0x038a, 0x0378, 0x0367, 0x036d, 0x0375, 0x0381, 0x0374, 0x0381, | ||
744 | 0x0392, 0x03a9, 0x03c4, 0x03e1, 0x0001, 0x001f, 0x0040, 0x005e, 0x007f, | ||
745 | 0x009e, 0x00bd, 0x00dd, 0x00fd, 0x011d, 0x013d, | ||
746 | }; | ||
747 | |||
748 | static const u16 lpphy_rev01_filter_control_table[] = { | ||
749 | 0xa0fc, 0x10fc, 0x10db, 0x20b7, 0xff93, 0x10bf, 0x109b, 0x2077, 0xff53, | ||
750 | 0x0127, | ||
751 | }; | ||
752 | |||
753 | static const u32 lpphy_rev2plus_filter_control_table[] = { | ||
754 | 0x000141fc, 0x000021fc, 0x000021b7, 0x0000416f, 0x0001ff27, 0x0000217f, | ||
755 | 0x00002137, 0x000040ef, 0x0001fea7, 0x0000024f, | ||
756 | }; | ||
757 | |||
758 | static const u32 lpphy_rev01_ps_control_table[] = { | ||
759 | 0x00010000, 0x000000a0, 0x00040000, 0x00000048, 0x08080101, 0x00000080, | ||
760 | 0x08080101, 0x00000040, 0x08080101, 0x000000c0, 0x08a81501, 0x000000c0, | ||
761 | 0x0fe8fd01, 0x000000c0, 0x08300105, 0x000000c0, 0x08080201, 0x000000c0, | ||
762 | 0x08280205, 0x000000c0, 0xe80802fe, 0x000000c7, 0x28080206, 0x000000c0, | ||
763 | 0x08080202, 0x000000c0, 0x0ba87602, 0x000000c0, 0x1068013d, 0x000000c0, | ||
764 | 0x10280105, 0x000000c0, 0x08880102, 0x000000c0, 0x08280106, 0x000000c0, | ||
765 | 0xe80801fd, 0x000000c7, 0xa8080115, 0x000000c0, | ||
766 | }; | ||
767 | |||
768 | static const u32 lpphy_rev2plus_ps_control_table[] = { | ||
769 | 0x00e38e08, 0x00e08e38, 0x00000000, 0x00000000, 0x00000000, 0x00002080, | ||
770 | 0x00006180, 0x00003002, 0x00000040, 0x00002042, 0x00180047, 0x00080043, | ||
771 | 0x00000041, 0x000020c1, 0x00046006, 0x00042002, 0x00040000, 0x00002003, | ||
772 | 0x00180006, 0x00080002, | ||
773 | }; | ||
774 | |||
775 | static const u8 lpphy_pll_fraction_table[] = { | ||
776 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, | ||
777 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, | ||
778 | }; | ||
779 | |||
780 | static const u16 lpphy_iq_local_table[] = { | ||
781 | 0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, | ||
782 | 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, | ||
783 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
784 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600, | ||
785 | 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, | ||
786 | 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000, | ||
787 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
788 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
789 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
790 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000, | ||
791 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
792 | 0x0000, 0x0000, | ||
793 | }; | ||
794 | |||
795 | static const u16 lpphy_ofdm_cck_gain_table[] = { | ||
796 | 0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001, 0x5001, | ||
797 | 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055, 0x2065, 0x2075, | ||
798 | 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d, 0x135d, 0x055d, 0x155d, | ||
799 | 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d, 0x755d, | ||
800 | }; | ||
801 | |||
802 | static const u16 lpphy_gain_delta_table[] = { | ||
803 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
804 | }; | ||
805 | |||
806 | static const u32 lpphy_tx_power_control_table[] = { | ||
807 | 0x00000050, 0x0000004f, 0x0000004e, 0x0000004d, 0x0000004c, 0x0000004b, | ||
808 | 0x0000004a, 0x00000049, 0x00000048, 0x00000047, 0x00000046, 0x00000045, | ||
809 | 0x00000044, 0x00000043, 0x00000042, 0x00000041, 0x00000040, 0x0000003f, | ||
810 | 0x0000003e, 0x0000003d, 0x0000003c, 0x0000003b, 0x0000003a, 0x00000039, | ||
811 | 0x00000038, 0x00000037, 0x00000036, 0x00000035, 0x00000034, 0x00000033, | ||
812 | 0x00000032, 0x00000031, 0x00000030, 0x0000002f, 0x0000002e, 0x0000002d, | ||
813 | 0x0000002c, 0x0000002b, 0x0000002a, 0x00000029, 0x00000028, 0x00000027, | ||
814 | 0x00000026, 0x00000025, 0x00000024, 0x00000023, 0x00000022, 0x00000021, | ||
815 | 0x00000020, 0x0000001f, 0x0000001e, 0x0000001d, 0x0000001c, 0x0000001b, | ||
816 | 0x0000001a, 0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015, | ||
817 | 0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000000, 0x00000000, | ||
818 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
819 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
820 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
821 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
822 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
823 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
824 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
825 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
826 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
827 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
828 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
829 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
830 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
831 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
832 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
833 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
834 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
835 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
836 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
837 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
838 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
839 | 0x000075a0, 0x000075a0, 0x000075a1, 0x000075a1, 0x000075a2, 0x000075a2, | ||
840 | 0x000075a3, 0x000075a3, 0x000074b0, 0x000074b0, 0x000074b1, 0x000074b1, | ||
841 | 0x000074b2, 0x000074b2, 0x000074b3, 0x000074b3, 0x00006d20, 0x00006d20, | ||
842 | 0x00006d21, 0x00006d21, 0x00006d22, 0x00006d22, 0x00006d23, 0x00006d23, | ||
843 | 0x00004660, 0x00004660, 0x00004661, 0x00004661, 0x00004662, 0x00004662, | ||
844 | 0x00004663, 0x00004663, 0x00003e60, 0x00003e60, 0x00003e61, 0x00003e61, | ||
845 | 0x00003e62, 0x00003e62, 0x00003e63, 0x00003e63, 0x00003660, 0x00003660, | ||
846 | 0x00003661, 0x00003661, 0x00003662, 0x00003662, 0x00003663, 0x00003663, | ||
847 | 0x00002e60, 0x00002e60, 0x00002e61, 0x00002e61, 0x00002e62, 0x00002e62, | ||
848 | 0x00002e63, 0x00002e63, 0x00002660, 0x00002660, 0x00002661, 0x00002661, | ||
849 | 0x00002662, 0x00002662, 0x00002663, 0x00002663, 0x000025e0, 0x000025e0, | ||
850 | 0x000025e1, 0x000025e1, 0x000025e2, 0x000025e2, 0x000025e3, 0x000025e3, | ||
851 | 0x00001de0, 0x00001de0, 0x00001de1, 0x00001de1, 0x00001de2, 0x00001de2, | ||
852 | 0x00001de3, 0x00001de3, 0x00001d60, 0x00001d60, 0x00001d61, 0x00001d61, | ||
853 | 0x00001d62, 0x00001d62, 0x00001d63, 0x00001d63, 0x00001560, 0x00001560, | ||
854 | 0x00001561, 0x00001561, 0x00001562, 0x00001562, 0x00001563, 0x00001563, | ||
855 | 0x00000d60, 0x00000d60, 0x00000d61, 0x00000d61, 0x00000d62, 0x00000d62, | ||
856 | 0x00000d63, 0x00000d63, 0x00000ce0, 0x00000ce0, 0x00000ce1, 0x00000ce1, | ||
857 | 0x00000ce2, 0x00000ce2, 0x00000ce3, 0x00000ce3, 0x00000e10, 0x00000e10, | ||
858 | 0x00000e11, 0x00000e11, 0x00000e12, 0x00000e12, 0x00000e13, 0x00000e13, | ||
859 | 0x00000bf0, 0x00000bf0, 0x00000bf1, 0x00000bf1, 0x00000bf2, 0x00000bf2, | ||
860 | 0x00000bf3, 0x00000bf3, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
861 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
862 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
863 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
864 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
865 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
866 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
867 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
868 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
869 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
870 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
871 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
872 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
873 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
874 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
875 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
876 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
877 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
878 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
879 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
880 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, | ||
881 | 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x000000ff, 0x000002fc, | ||
882 | 0x0000fa08, 0x00000305, 0x00000206, 0x00000304, 0x0000fb04, 0x0000fcff, | ||
883 | 0x000005fb, 0x0000fd01, 0x00000401, 0x00000006, 0x0000ff03, 0x000007fc, | ||
884 | 0x0000fc08, 0x00000203, 0x0000fffb, 0x00000600, 0x0000fa01, 0x0000fc03, | ||
885 | 0x0000fe06, 0x0000fe00, 0x00000102, 0x000007fd, 0x000004fb, 0x000006ff, | ||
886 | 0x000004fd, 0x0000fdfa, 0x000007fb, 0x0000fdfa, 0x0000fa06, 0x00000500, | ||
887 | 0x0000f902, 0x000007fa, 0x0000fafa, 0x00000500, 0x000007fa, 0x00000700, | ||
888 | 0x00000305, 0x000004ff, 0x00000801, 0x00000503, 0x000005f9, 0x00000404, | ||
889 | 0x0000fb08, 0x000005fd, 0x00000501, 0x00000405, 0x0000fb03, 0x000007fc, | ||
890 | 0x00000403, 0x00000303, 0x00000402, 0x0000faff, 0x0000fe05, 0x000005fd, | ||
891 | 0x0000fe01, 0x000007fa, 0x00000202, 0x00000504, 0x00000102, 0x000008fe, | ||
892 | 0x0000fa04, 0x0000fafc, 0x0000fe08, 0x000000f9, 0x000002fa, 0x000003fe, | ||
893 | 0x00000304, 0x000004f9, 0x00000100, 0x0000fd06, 0x000008fc, 0x00000701, | ||
894 | 0x00000504, 0x0000fdfe, 0x0000fdfc, 0x000003fe, 0x00000704, 0x000002fc, | ||
895 | 0x000004f9, 0x0000fdfd, 0x0000fa07, 0x00000205, 0x000003fd, 0x000005fb, | ||
896 | 0x000004f9, 0x00000804, 0x0000fc06, 0x0000fcf9, 0x00000100, 0x0000fe05, | ||
897 | 0x00000408, 0x0000fb02, 0x00000304, 0x000006fe, 0x000004fa, 0x00000305, | ||
898 | 0x000008fc, 0x00000102, 0x000001fd, 0x000004fc, 0x0000fe03, 0x00000701, | ||
899 | 0x000001fb, 0x000001f9, 0x00000206, 0x000006fd, 0x00000508, 0x00000700, | ||
900 | 0x00000304, 0x000005fe, 0x000005ff, 0x0000fa04, 0x00000303, 0x0000fefb, | ||
901 | 0x000007f9, 0x0000fefc, 0x000004fd, 0x000005fc, 0x0000fffd, 0x0000fc08, | ||
902 | 0x0000fbf9, 0x0000fd07, 0x000008fb, 0x0000fe02, 0x000006fb, 0x00000702, | ||
903 | }; | ||
904 | |||
905 | static const u32 lpphy_gain_idx_table[] = { | ||
906 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
907 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
908 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
909 | 0x10000001, 0x00000000, 0x20000082, 0x00000000, 0x40000104, 0x00000000, | ||
910 | 0x60004207, 0x00000001, 0x7000838a, 0x00000001, 0xd021050d, 0x00000001, | ||
911 | 0xe041c683, 0x00000001, 0x50828805, 0x00000000, 0x80e34288, 0x00000000, | ||
912 | 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, 0x12064711, 0x00000001, | ||
913 | 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010, 0x11630915, 0x00000011, | ||
914 | 0x31c3ca1b, 0x00000011, 0xc1848a9c, 0x00000018, 0xf1e50da0, 0x00000018, | ||
915 | 0x22468e21, 0x00000019, 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019, | ||
916 | 0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329, 0x0000001a, | ||
917 | 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, 0x54aa152c, 0x0000001a, | ||
918 | 0x64ca55ad, 0x0000001a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
919 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
920 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
921 | 0x00000000, 0x00000000, 0x10000001, 0x00000000, 0x20000082, 0x00000000, | ||
922 | 0x40000104, 0x00000000, 0x60004207, 0x00000001, 0x7000838a, 0x00000001, | ||
923 | 0xd021050d, 0x00000001, 0xe041c683, 0x00000001, 0x50828805, 0x00000000, | ||
924 | 0x80e34288, 0x00000000, 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, | ||
925 | 0x12064711, 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010, | ||
926 | 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011, 0xc1848a9c, 0x00000018, | ||
927 | 0xf1e50da0, 0x00000018, 0x22468e21, 0x00000019, 0x4286d023, 0x00000019, | ||
928 | 0xa347d0a4, 0x00000019, 0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, | ||
929 | 0x0408d329, 0x0000001a, 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, | ||
930 | 0x54aa152c, 0x0000001a, 0x64ca55ad, 0x0000001a, | ||
931 | }; | ||
932 | |||
933 | static const u16 lpphy_aux_gain_idx_table[] = { | ||
934 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
935 | 0x0001, 0x0002, 0x0004, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
936 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0016, | ||
937 | }; | ||
938 | |||
939 | static const u32 lpphy_gain_value_table[] = { | ||
940 | 0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb, 0x00000004, | ||
941 | 0x00000008, 0x0000000d, 0x00000001, 0x00000004, 0x00000007, 0x0000000a, | ||
942 | 0x0000000d, 0x00000010, 0x00000012, 0x00000015, 0x00000000, 0x00000006, | ||
943 | 0x0000000c, 0x00000000, 0x00000000, 0x00000000, 0x00000012, 0x00000000, | ||
944 | 0x00000000, 0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000, | ||
945 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
946 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
947 | 0x0000001e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
948 | 0x00000000, 0x00000003, 0x00000006, 0x00000009, 0x0000000c, 0x0000000f, | ||
949 | 0x00000012, 0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000, | ||
950 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009, 0x000000f1, | ||
951 | 0x00000000, 0x00000000, | ||
952 | }; | ||
953 | |||
954 | static const u16 lpphy_gain_table[] = { | ||
955 | 0x0000, 0x0400, 0x0800, 0x0802, 0x0804, 0x0806, 0x0807, 0x0808, 0x080a, | ||
956 | 0x080b, 0x080c, 0x080e, 0x080f, 0x0810, 0x0812, 0x0813, 0x0814, 0x0816, | ||
957 | 0x0817, 0x081a, 0x081b, 0x081f, 0x0820, 0x0824, 0x0830, 0x0834, 0x0837, | ||
958 | 0x083b, 0x083f, 0x0840, 0x0844, 0x0857, 0x085b, 0x085f, 0x08d7, 0x08db, | ||
959 | 0x08df, 0x0957, 0x095b, 0x095f, 0x0b57, 0x0b5b, 0x0b5f, 0x0f5f, 0x135f, | ||
960 | 0x175f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
961 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
962 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
963 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
964 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
965 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
966 | }; | ||
967 | |||
968 | static const u32 lpphy_a0_gain_idx_table[] = { | ||
969 | 0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060, 0x00511065, | ||
970 | 0x004c806b, 0x0047d072, 0x00444078, 0x00400080, 0x003ca087, 0x0039408f, | ||
971 | 0x0035e098, 0x0032e0a1, 0x003030aa, 0x002d80b4, 0x002ae0bf, 0x002880ca, | ||
972 | 0x002640d6, 0x002410e3, 0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, | ||
973 | 0x001b012f, 0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193, | ||
974 | 0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a, 0x000e523a, | ||
975 | 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd, 0x000ac2f8, 0x000a2325, | ||
976 | 0x00099355, 0x00091387, 0x000883bd, 0x000813f5, 0x0007a432, 0x00073471, | ||
977 | 0x0006c4b5, 0x000664fc, 0x00061547, 0x0005b598, 0x000565ec, 0x00051646, | ||
978 | 0x0004d6a5, 0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd, | ||
979 | 0x00036963, 0x000339f2, 0x00030a89, 0x0002db28, | ||
980 | }; | ||
981 | |||
982 | static const u16 lpphy_a0_aux_gain_idx_table[] = { | ||
983 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
984 | 0x0000, 0x0000, 0x0002, 0x0014, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
985 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0014, | ||
986 | }; | ||
987 | |||
988 | static const u32 lpphy_a0_gain_value_table[] = { | ||
989 | 0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb, 0x00000004, | ||
990 | 0x00000008, 0x0000000d, 0x00000001, 0x00000004, 0x00000007, 0x0000000a, | ||
991 | 0x0000000d, 0x00000010, 0x00000012, 0x00000015, 0x00000000, 0x00000006, | ||
992 | 0x0000000c, 0x00000000, 0x00000000, 0x00000000, 0x00000012, 0x00000000, | ||
993 | 0x00000000, 0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000, | ||
994 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
995 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
996 | 0x0000001e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
997 | 0x00000000, 0x00000003, 0x00000006, 0x00000009, 0x0000000c, 0x0000000f, | ||
998 | 0x00000012, 0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000, | ||
999 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f, 0x000000f7, | ||
1000 | 0x00000000, 0x00000000, | ||
1001 | }; | ||
1002 | |||
1003 | static const u16 lpphy_a0_gain_table[] = { | ||
1004 | 0x0000, 0x0002, 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, | ||
1005 | 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, 0x0014, 0x0016, 0x0017, 0x001a, | ||
1006 | 0x001b, 0x001f, 0x0020, 0x0024, 0x0030, 0x0034, 0x0037, 0x003b, 0x003f, | ||
1007 | 0x0040, 0x0044, 0x0057, 0x005b, 0x005f, 0x00d7, 0x00db, 0x00df, 0x0157, | ||
1008 | 0x015b, 0x015f, 0x0357, 0x035b, 0x035f, 0x075f, 0x0b5f, 0x0f5f, 0x0000, | ||
1009 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
1010 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
1011 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
1012 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
1013 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
1014 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
1015 | }; | ||
1016 | |||
1017 | static const u16 lpphy_sw_control_table[] = { | ||
1018 | 0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028, 0x0128, | ||
1019 | 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028, 0x0009, 0x0009, | ||
1020 | 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0018, 0x0018, 0x0018, | ||
1021 | 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0128, 0x0128, 0x0009, 0x0009, | ||
1022 | 0x0028, 0x0028, 0x0028, 0x0028, 0x0128, 0x0128, 0x0009, 0x0009, 0x0028, | ||
1023 | 0x0028, 0x0028, 0x0028, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, | ||
1024 | 0x0009, 0x0009, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, | ||
1025 | 0x0018, | ||
1026 | }; | ||
1027 | |||
1028 | static const u8 lpphy_hf_table[] = { | ||
1029 | 0x4b, 0x36, 0x24, 0x18, 0x49, 0x34, 0x23, 0x17, 0x48, | ||
1030 | 0x33, 0x23, 0x17, 0x48, 0x33, 0x23, 0x17, | ||
1031 | }; | ||
1032 | |||
1033 | static const u32 lpphy_papd_eps_table[] = { | ||
1034 | 0x00000000, 0x00013ffc, 0x0001dff3, 0x0001bff0, 0x00023fe9, 0x00021fdf, | ||
1035 | 0x00028fdf, 0x00033fd2, 0x00039fcb, 0x00043fc7, 0x0004efc2, 0x00055fb5, | ||
1036 | 0x0005cfb0, 0x00063fa8, 0x00068fa3, 0x00071f98, 0x0007ef92, 0x00084f8b, | ||
1037 | 0x0008df82, 0x00097f77, 0x0009df69, 0x000a3f62, 0x000adf57, 0x000b6f4c, | ||
1038 | 0x000bff41, 0x000c9f39, 0x000cff30, 0x000dbf27, 0x000e4f1e, 0x000edf16, | ||
1039 | 0x000f7f13, 0x00102f11, 0x00110f10, 0x0011df11, 0x0012ef15, 0x00143f1c, | ||
1040 | 0x00158f27, 0x00172f35, 0x00193f47, 0x001baf5f, 0x001e6f7e, 0x0021cfa4, | ||
1041 | 0x0025bfd2, 0x002a2008, 0x002fb047, 0x00360090, 0x003d40e0, 0x0045c135, | ||
1042 | 0x004fb189, 0x005ae1d7, 0x0067221d, 0x0075025a, 0x007ff291, 0x007ff2bf, | ||
1043 | 0x007ff2e3, 0x007ff2ff, 0x007ff315, 0x007ff329, 0x007ff33f, 0x007ff356, | ||
1044 | 0x007ff36e, 0x007ff39c, 0x007ff441, 0x007ff506, | ||
1045 | }; | ||
1046 | |||
1047 | static const u32 lpphy_papd_mult_table[] = { | ||
1048 | 0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060, 0x00511065, | ||
1049 | 0x004c806b, 0x0047d072, 0x00444078, 0x00400080, 0x003ca087, 0x0039408f, | ||
1050 | 0x0035e098, 0x0032e0a1, 0x003030aa, 0x002d80b4, 0x002ae0bf, 0x002880ca, | ||
1051 | 0x002640d6, 0x002410e3, 0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, | ||
1052 | 0x001b012f, 0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193, | ||
1053 | 0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a, 0x000e523a, | ||
1054 | 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd, 0x000ac2f8, 0x000a2325, | ||
1055 | 0x00099355, 0x00091387, 0x000883bd, 0x000813f5, 0x0007a432, 0x00073471, | ||
1056 | 0x0006c4b5, 0x000664fc, 0x00061547, 0x0005b598, 0x000565ec, 0x00051646, | ||
1057 | 0x0004d6a5, 0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd, | ||
1058 | 0x00036963, 0x000339f2, 0x00030a89, 0x0002db28, | ||
1059 | }; | ||
1060 | |||
1061 | static struct lpphy_tx_gain_table_entry lpphy_rev0_nopa_tx_gain_table[] = { | ||
1062 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 152, }, | ||
1063 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 147, }, | ||
1064 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 143, }, | ||
1065 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 139, }, | ||
1066 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 135, }, | ||
1067 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 131, }, | ||
1068 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 128, }, | ||
1069 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 124, }, | ||
1070 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 121, }, | ||
1071 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 117, }, | ||
1072 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 114, }, | ||
1073 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 111, }, | ||
1074 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 107, }, | ||
1075 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 104, }, | ||
1076 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 101, }, | ||
1077 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 99, }, | ||
1078 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 96, }, | ||
1079 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 93, }, | ||
1080 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 90, }, | ||
1081 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 88, }, | ||
1082 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 85, }, | ||
1083 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 83, }, | ||
1084 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 81, }, | ||
1085 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 78, }, | ||
1086 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 76, }, | ||
1087 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 74, }, | ||
1088 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, | ||
1089 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, | ||
1090 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, | ||
1091 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, | ||
1092 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, | ||
1093 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, | ||
1094 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, | ||
1095 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, }, | ||
1096 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 57, }, | ||
1097 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, }, | ||
1098 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, }, | ||
1099 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 68, }, | ||
1100 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 66, }, | ||
1101 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 64, }, | ||
1102 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, | ||
1103 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, | ||
1104 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 59, }, | ||
1105 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 57, }, | ||
1106 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 71, }, | ||
1107 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 69, }, | ||
1108 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 67, }, | ||
1109 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 65, }, | ||
1110 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 63, }, | ||
1111 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, | ||
1112 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, | ||
1113 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 58, }, | ||
1114 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, }, | ||
1115 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 70, }, | ||
1116 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 68, }, | ||
1117 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 66, }, | ||
1118 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, }, | ||
1119 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, }, | ||
1120 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, }, | ||
1121 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 59, }, | ||
1122 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, }, | ||
1123 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, }, | ||
1124 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, }, | ||
1125 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, }, | ||
1126 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, }, | ||
1127 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, }, | ||
1128 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, }, | ||
1129 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, | ||
1130 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, }, | ||
1131 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 56, }, | ||
1132 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1133 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1134 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1135 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1136 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, | ||
1137 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, }, | ||
1138 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1139 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, }, | ||
1140 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1141 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1142 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1143 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1144 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, }, | ||
1145 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, }, | ||
1146 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1147 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, }, | ||
1148 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1149 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1150 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1151 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1152 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, | ||
1153 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, | ||
1154 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1155 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, | ||
1156 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, }, | ||
1157 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, | ||
1158 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, | ||
1159 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, | ||
1160 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, | ||
1161 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, | ||
1162 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, | ||
1163 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, | ||
1164 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, }, | ||
1165 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, | ||
1166 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, | ||
1167 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, | ||
1168 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, | ||
1169 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, | ||
1170 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, | ||
1171 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, | ||
1172 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, }, | ||
1173 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, }, | ||
1174 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, }, | ||
1175 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, }, | ||
1176 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, }, | ||
1177 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, }, | ||
1178 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, | ||
1179 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, | ||
1180 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, }, | ||
1181 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, | ||
1182 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, | ||
1183 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, | ||
1184 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, }, | ||
1185 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, }, | ||
1186 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, | ||
1187 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, | ||
1188 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, }, | ||
1189 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, }, | ||
1190 | }; | ||
1191 | |||
1192 | static struct lpphy_tx_gain_table_entry lpphy_rev0_2ghz_tx_gain_table[] = { | ||
1193 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1194 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, | ||
1195 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, }, | ||
1196 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1197 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, }, | ||
1198 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1199 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1200 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1201 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1202 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, }, | ||
1203 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, }, | ||
1204 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1205 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, }, | ||
1206 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1207 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1208 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1209 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1210 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, | ||
1211 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, | ||
1212 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1213 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, | ||
1214 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, }, | ||
1215 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, | ||
1216 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, | ||
1217 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, | ||
1218 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, | ||
1219 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, | ||
1220 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, | ||
1221 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, | ||
1222 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, }, | ||
1223 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, | ||
1224 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, | ||
1225 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, | ||
1226 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, | ||
1227 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, | ||
1228 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, | ||
1229 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, | ||
1230 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, }, | ||
1231 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, }, | ||
1232 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, }, | ||
1233 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, }, | ||
1234 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, }, | ||
1235 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, }, | ||
1236 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, | ||
1237 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, | ||
1238 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, }, | ||
1239 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, | ||
1240 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, | ||
1241 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, | ||
1242 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, }, | ||
1243 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, }, | ||
1244 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, | ||
1245 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, | ||
1246 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, }, | ||
1247 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, }, | ||
1248 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, }, | ||
1249 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, }, | ||
1250 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, }, | ||
1251 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, }, | ||
1252 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 61, }, | ||
1253 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, }, | ||
1254 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 72, }, | ||
1255 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 70, }, | ||
1256 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 68, }, | ||
1257 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 66, }, | ||
1258 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 64, }, | ||
1259 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 62, }, | ||
1260 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 60, }, | ||
1261 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 59, }, | ||
1262 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 72, }, | ||
1263 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 70, }, | ||
1264 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 68, }, | ||
1265 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 66, }, | ||
1266 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 64, }, | ||
1267 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 62, }, | ||
1268 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 60, }, | ||
1269 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 59, }, | ||
1270 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 70, }, | ||
1271 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 68, }, | ||
1272 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 66, }, | ||
1273 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 64, }, | ||
1274 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 63, }, | ||
1275 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 61, }, | ||
1276 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 59, }, | ||
1277 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 71, }, | ||
1278 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 69, }, | ||
1279 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 67, }, | ||
1280 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 65, }, | ||
1281 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 63, }, | ||
1282 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 62, }, | ||
1283 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 60, }, | ||
1284 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 58, }, | ||
1285 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 70, }, | ||
1286 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 68, }, | ||
1287 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 66, }, | ||
1288 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 65, }, | ||
1289 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 63, }, | ||
1290 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 61, }, | ||
1291 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 59, }, | ||
1292 | { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 68, }, | ||
1293 | { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 66, }, | ||
1294 | { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 64, }, | ||
1295 | { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 62, }, | ||
1296 | { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 61, }, | ||
1297 | { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 59, }, | ||
1298 | { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 67, }, | ||
1299 | { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 65, }, | ||
1300 | { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 63, }, | ||
1301 | { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 62, }, | ||
1302 | { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 60, }, | ||
1303 | { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 65, }, | ||
1304 | { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 63, }, | ||
1305 | { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 61, }, | ||
1306 | { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 60, }, | ||
1307 | { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 58, }, | ||
1308 | { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 68, }, | ||
1309 | { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 66, }, | ||
1310 | { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 64, }, | ||
1311 | { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 62, }, | ||
1312 | { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 60, }, | ||
1313 | { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 59, }, | ||
1314 | { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 57, }, | ||
1315 | { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 83, }, | ||
1316 | { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 81, }, | ||
1317 | { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 78, }, | ||
1318 | { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 76, }, | ||
1319 | { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 74, }, | ||
1320 | { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 72, }, | ||
1321 | }; | ||
1322 | |||
1323 | static struct lpphy_tx_gain_table_entry lpphy_rev0_5ghz_tx_gain_table[] = { | ||
1324 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 99, }, | ||
1325 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 96, }, | ||
1326 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 93, }, | ||
1327 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 90, }, | ||
1328 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 88, }, | ||
1329 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 85, }, | ||
1330 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 83, }, | ||
1331 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 81, }, | ||
1332 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 78, }, | ||
1333 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 76, }, | ||
1334 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 74, }, | ||
1335 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 72, }, | ||
1336 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 70, }, | ||
1337 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 68, }, | ||
1338 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 66, }, | ||
1339 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 64, }, | ||
1340 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 62, }, | ||
1341 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 60, }, | ||
1342 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 59, }, | ||
1343 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 57, }, | ||
1344 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 55, }, | ||
1345 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, | ||
1346 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, | ||
1347 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, | ||
1348 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, | ||
1349 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, | ||
1350 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, | ||
1351 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, | ||
1352 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 58, }, | ||
1353 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 56, }, | ||
1354 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 55, }, | ||
1355 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 71, }, | ||
1356 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 69, }, | ||
1357 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 67, }, | ||
1358 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 65, }, | ||
1359 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 63, }, | ||
1360 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, | ||
1361 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, | ||
1362 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 58, }, | ||
1363 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 56, }, | ||
1364 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 72, }, | ||
1365 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 70, }, | ||
1366 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 68, }, | ||
1367 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 66, }, | ||
1368 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 64, }, | ||
1369 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, | ||
1370 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, | ||
1371 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 59, }, | ||
1372 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, }, | ||
1373 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 73, }, | ||
1374 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 71, }, | ||
1375 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 69, }, | ||
1376 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 67, }, | ||
1377 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, }, | ||
1378 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, }, | ||
1379 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, }, | ||
1380 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 60, }, | ||
1381 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, }, | ||
1382 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, }, | ||
1383 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, }, | ||
1384 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, }, | ||
1385 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, }, | ||
1386 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, }, | ||
1387 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, }, | ||
1388 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, | ||
1389 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, }, | ||
1390 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1391 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1392 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1393 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1394 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, | ||
1395 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 61, }, | ||
1396 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1397 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 57, }, | ||
1398 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 56, }, | ||
1399 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1400 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1401 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 65, }, | ||
1402 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 63, }, | ||
1403 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 61, }, | ||
1404 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1405 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 58, }, | ||
1406 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1407 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1408 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1409 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1410 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, | ||
1411 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, | ||
1412 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1413 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, | ||
1414 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, | ||
1415 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, | ||
1416 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, | ||
1417 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, | ||
1418 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, | ||
1419 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, | ||
1420 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, | ||
1421 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 57, }, | ||
1422 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, | ||
1423 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, | ||
1424 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, | ||
1425 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, | ||
1426 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, | ||
1427 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, | ||
1428 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, | ||
1429 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 57, }, | ||
1430 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 70, }, | ||
1431 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 68, }, | ||
1432 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 66, }, | ||
1433 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 64, }, | ||
1434 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 62, }, | ||
1435 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, | ||
1436 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, | ||
1437 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 57, }, | ||
1438 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, | ||
1439 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, | ||
1440 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, | ||
1441 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 64, }, | ||
1442 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 62, }, | ||
1443 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, | ||
1444 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, | ||
1445 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 57, }, | ||
1446 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, }, | ||
1447 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, }, | ||
1448 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, }, | ||
1449 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, }, | ||
1450 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 62, }, | ||
1451 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, }, | ||
1452 | }; | ||
1453 | |||
1454 | static struct lpphy_tx_gain_table_entry lpphy_rev1_nopa_tx_gain_table[] = { | ||
1455 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 152, }, | ||
1456 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 147, }, | ||
1457 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 143, }, | ||
1458 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 139, }, | ||
1459 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 135, }, | ||
1460 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 131, }, | ||
1461 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 128, }, | ||
1462 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 124, }, | ||
1463 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 121, }, | ||
1464 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 117, }, | ||
1465 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 114, }, | ||
1466 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 111, }, | ||
1467 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 107, }, | ||
1468 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 104, }, | ||
1469 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 101, }, | ||
1470 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 99, }, | ||
1471 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 96, }, | ||
1472 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 93, }, | ||
1473 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 90, }, | ||
1474 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 88, }, | ||
1475 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 85, }, | ||
1476 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 83, }, | ||
1477 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 81, }, | ||
1478 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 78, }, | ||
1479 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 76, }, | ||
1480 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 74, }, | ||
1481 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, | ||
1482 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, | ||
1483 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, | ||
1484 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, | ||
1485 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, | ||
1486 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, | ||
1487 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, | ||
1488 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, }, | ||
1489 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 57, }, | ||
1490 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, }, | ||
1491 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, }, | ||
1492 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, | ||
1493 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, | ||
1494 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, | ||
1495 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, | ||
1496 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, | ||
1497 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, }, | ||
1498 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 57, }, | ||
1499 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, }, | ||
1500 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, }, | ||
1501 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 68, }, | ||
1502 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 66, }, | ||
1503 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 64, }, | ||
1504 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, | ||
1505 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, | ||
1506 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 59, }, | ||
1507 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 57, }, | ||
1508 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 71, }, | ||
1509 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 69, }, | ||
1510 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 67, }, | ||
1511 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 65, }, | ||
1512 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 63, }, | ||
1513 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, | ||
1514 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, | ||
1515 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 58, }, | ||
1516 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, }, | ||
1517 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 70, }, | ||
1518 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 68, }, | ||
1519 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 66, }, | ||
1520 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, }, | ||
1521 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, }, | ||
1522 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, }, | ||
1523 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 59, }, | ||
1524 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, }, | ||
1525 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, }, | ||
1526 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, }, | ||
1527 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, }, | ||
1528 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, }, | ||
1529 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, }, | ||
1530 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, }, | ||
1531 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, | ||
1532 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, }, | ||
1533 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 56, }, | ||
1534 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1535 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1536 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1537 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1538 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, | ||
1539 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, }, | ||
1540 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1541 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, }, | ||
1542 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1543 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1544 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1545 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1546 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, }, | ||
1547 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, }, | ||
1548 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1549 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, }, | ||
1550 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1551 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1552 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1553 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1554 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, | ||
1555 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, | ||
1556 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1557 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, | ||
1558 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, }, | ||
1559 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, | ||
1560 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, | ||
1561 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, | ||
1562 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, | ||
1563 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, | ||
1564 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, | ||
1565 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, | ||
1566 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, }, | ||
1567 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, | ||
1568 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, | ||
1569 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, | ||
1570 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, | ||
1571 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, | ||
1572 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, | ||
1573 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, | ||
1574 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, }, | ||
1575 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, }, | ||
1576 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, }, | ||
1577 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, }, | ||
1578 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, }, | ||
1579 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, }, | ||
1580 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, | ||
1581 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, | ||
1582 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, }, | ||
1583 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, | ||
1584 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, | ||
1585 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, | ||
1586 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, }, | ||
1587 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, }, | ||
1588 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, | ||
1589 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, | ||
1590 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, }, | ||
1591 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, }, | ||
1592 | }; | ||
1593 | |||
1594 | static struct lpphy_tx_gain_table_entry lpphy_rev1_2ghz_tx_gain_table[] = { | ||
1595 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 85, }, | ||
1596 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 81, }, | ||
1597 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 78, }, | ||
1598 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 76, }, | ||
1599 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 74, }, | ||
1600 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 72, }, | ||
1601 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1602 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1603 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1604 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1605 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, | ||
1606 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, }, | ||
1607 | { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1608 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, }, | ||
1609 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1610 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1611 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1612 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1613 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, }, | ||
1614 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, }, | ||
1615 | { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1616 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, }, | ||
1617 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1618 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1619 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1620 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1621 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, | ||
1622 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, | ||
1623 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1624 | { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, | ||
1625 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, }, | ||
1626 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, | ||
1627 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, | ||
1628 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, | ||
1629 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, | ||
1630 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, | ||
1631 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, | ||
1632 | { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, | ||
1633 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, }, | ||
1634 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, | ||
1635 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, | ||
1636 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, | ||
1637 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, | ||
1638 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, | ||
1639 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, | ||
1640 | { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, | ||
1641 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, }, | ||
1642 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, }, | ||
1643 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, }, | ||
1644 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, }, | ||
1645 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, }, | ||
1646 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, }, | ||
1647 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, | ||
1648 | { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, | ||
1649 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, }, | ||
1650 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, | ||
1651 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, | ||
1652 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, | ||
1653 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, }, | ||
1654 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, }, | ||
1655 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, | ||
1656 | { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, | ||
1657 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, }, | ||
1658 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, }, | ||
1659 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, }, | ||
1660 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, }, | ||
1661 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, }, | ||
1662 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, }, | ||
1663 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 61, }, | ||
1664 | { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, }, | ||
1665 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 72, }, | ||
1666 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 70, }, | ||
1667 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 68, }, | ||
1668 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 66, }, | ||
1669 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 64, }, | ||
1670 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 62, }, | ||
1671 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 60, }, | ||
1672 | { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 59, }, | ||
1673 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 72, }, | ||
1674 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 70, }, | ||
1675 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 68, }, | ||
1676 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 66, }, | ||
1677 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 64, }, | ||
1678 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 62, }, | ||
1679 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 60, }, | ||
1680 | { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 59, }, | ||
1681 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 70, }, | ||
1682 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 68, }, | ||
1683 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 66, }, | ||
1684 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 64, }, | ||
1685 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 63, }, | ||
1686 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 61, }, | ||
1687 | { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 59, }, | ||
1688 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 71, }, | ||
1689 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 69, }, | ||
1690 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 67, }, | ||
1691 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 65, }, | ||
1692 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 63, }, | ||
1693 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 62, }, | ||
1694 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 60, }, | ||
1695 | { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 58, }, | ||
1696 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 70, }, | ||
1697 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 68, }, | ||
1698 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 66, }, | ||
1699 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 65, }, | ||
1700 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 63, }, | ||
1701 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 61, }, | ||
1702 | { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 59, }, | ||
1703 | { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 68, }, | ||
1704 | { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 66, }, | ||
1705 | { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 64, }, | ||
1706 | { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 62, }, | ||
1707 | { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 61, }, | ||
1708 | { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 59, }, | ||
1709 | { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 67, }, | ||
1710 | { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 65, }, | ||
1711 | { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 63, }, | ||
1712 | { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 62, }, | ||
1713 | { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 60, }, | ||
1714 | { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 65, }, | ||
1715 | { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 63, }, | ||
1716 | { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 61, }, | ||
1717 | { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 60, }, | ||
1718 | { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 58, }, | ||
1719 | { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 68, }, | ||
1720 | { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 66, }, | ||
1721 | { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 64, }, | ||
1722 | { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 62, }, | ||
1723 | }; | ||
1724 | |||
1725 | static struct lpphy_tx_gain_table_entry lpphy_rev1_5ghz_tx_gain_table[] = { | ||
1726 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 99, }, | ||
1727 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 96, }, | ||
1728 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 93, }, | ||
1729 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 90, }, | ||
1730 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 88, }, | ||
1731 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 85, }, | ||
1732 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 83, }, | ||
1733 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 81, }, | ||
1734 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 78, }, | ||
1735 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 76, }, | ||
1736 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 74, }, | ||
1737 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 72, }, | ||
1738 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 70, }, | ||
1739 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 68, }, | ||
1740 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 66, }, | ||
1741 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 64, }, | ||
1742 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 62, }, | ||
1743 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 60, }, | ||
1744 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 59, }, | ||
1745 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 57, }, | ||
1746 | { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 55, }, | ||
1747 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, | ||
1748 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, | ||
1749 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, | ||
1750 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, | ||
1751 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, | ||
1752 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, | ||
1753 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, | ||
1754 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 58, }, | ||
1755 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 56, }, | ||
1756 | { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 55, }, | ||
1757 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 71, }, | ||
1758 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 69, }, | ||
1759 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 67, }, | ||
1760 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 65, }, | ||
1761 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 63, }, | ||
1762 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, | ||
1763 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, | ||
1764 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 58, }, | ||
1765 | { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 56, }, | ||
1766 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 72, }, | ||
1767 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 70, }, | ||
1768 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 68, }, | ||
1769 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 66, }, | ||
1770 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 64, }, | ||
1771 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, | ||
1772 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, | ||
1773 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 59, }, | ||
1774 | { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, }, | ||
1775 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 73, }, | ||
1776 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 71, }, | ||
1777 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 69, }, | ||
1778 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 67, }, | ||
1779 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, }, | ||
1780 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, }, | ||
1781 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, }, | ||
1782 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 60, }, | ||
1783 | { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, }, | ||
1784 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, }, | ||
1785 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, }, | ||
1786 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, }, | ||
1787 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, }, | ||
1788 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, }, | ||
1789 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, }, | ||
1790 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, | ||
1791 | { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, }, | ||
1792 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1793 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1794 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1795 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1796 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, | ||
1797 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 61, }, | ||
1798 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1799 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 57, }, | ||
1800 | { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 56, }, | ||
1801 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1802 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1803 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 65, }, | ||
1804 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 63, }, | ||
1805 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 61, }, | ||
1806 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1807 | { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 58, }, | ||
1808 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, | ||
1809 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, | ||
1810 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, | ||
1811 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, | ||
1812 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, | ||
1813 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, | ||
1814 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, | ||
1815 | { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, | ||
1816 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, | ||
1817 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, | ||
1818 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, | ||
1819 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, | ||
1820 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, | ||
1821 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, | ||
1822 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, | ||
1823 | { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 57, }, | ||
1824 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, | ||
1825 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, | ||
1826 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, | ||
1827 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, | ||
1828 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, | ||
1829 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, | ||
1830 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, | ||
1831 | { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 57, }, | ||
1832 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 70, }, | ||
1833 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 68, }, | ||
1834 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 66, }, | ||
1835 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 64, }, | ||
1836 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 62, }, | ||
1837 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, | ||
1838 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, | ||
1839 | { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 57, }, | ||
1840 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, | ||
1841 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, | ||
1842 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, | ||
1843 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 64, }, | ||
1844 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 62, }, | ||
1845 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, | ||
1846 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, | ||
1847 | { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 57, }, | ||
1848 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, }, | ||
1849 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, }, | ||
1850 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, }, | ||
1851 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, }, | ||
1852 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 62, }, | ||
1853 | { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, }, | ||
1854 | }; | ||
1855 | |||
1856 | static struct lpphy_tx_gain_table_entry lpphy_rev2_nopa_tx_gain_table[] = { | ||
1857 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 152, }, | ||
1858 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 147, }, | ||
1859 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 143, }, | ||
1860 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 139, }, | ||
1861 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 135, }, | ||
1862 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 131, }, | ||
1863 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 128, }, | ||
1864 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 124, }, | ||
1865 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 121, }, | ||
1866 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 117, }, | ||
1867 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 114, }, | ||
1868 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 111, }, | ||
1869 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 107, }, | ||
1870 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 104, }, | ||
1871 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 101, }, | ||
1872 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 99, }, | ||
1873 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 96, }, | ||
1874 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 93, }, | ||
1875 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 90, }, | ||
1876 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 88, }, | ||
1877 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 85, }, | ||
1878 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 83, }, | ||
1879 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 81, }, | ||
1880 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 78, }, | ||
1881 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 76, }, | ||
1882 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 74, }, | ||
1883 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 72, }, | ||
1884 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 70, }, | ||
1885 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 68, }, | ||
1886 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 66, }, | ||
1887 | { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 64, }, | ||
1888 | { .gm = 255, .pga = 255, .pad = 197, .dac = 0, .bb_mult = 64, }, | ||
1889 | { .gm = 255, .pga = 255, .pad = 192, .dac = 0, .bb_mult = 64, }, | ||
1890 | { .gm = 255, .pga = 255, .pad = 186, .dac = 0, .bb_mult = 64, }, | ||
1891 | { .gm = 255, .pga = 255, .pad = 181, .dac = 0, .bb_mult = 64, }, | ||
1892 | { .gm = 255, .pga = 255, .pad = 176, .dac = 0, .bb_mult = 64, }, | ||
1893 | { .gm = 255, .pga = 255, .pad = 171, .dac = 0, .bb_mult = 64, }, | ||
1894 | { .gm = 255, .pga = 255, .pad = 166, .dac = 0, .bb_mult = 64, }, | ||
1895 | { .gm = 255, .pga = 255, .pad = 161, .dac = 0, .bb_mult = 64, }, | ||
1896 | { .gm = 255, .pga = 255, .pad = 157, .dac = 0, .bb_mult = 64, }, | ||
1897 | { .gm = 255, .pga = 255, .pad = 152, .dac = 0, .bb_mult = 64, }, | ||
1898 | { .gm = 255, .pga = 255, .pad = 148, .dac = 0, .bb_mult = 64, }, | ||
1899 | { .gm = 255, .pga = 255, .pad = 144, .dac = 0, .bb_mult = 64, }, | ||
1900 | { .gm = 255, .pga = 255, .pad = 140, .dac = 0, .bb_mult = 64, }, | ||
1901 | { .gm = 255, .pga = 255, .pad = 136, .dac = 0, .bb_mult = 64, }, | ||
1902 | { .gm = 255, .pga = 255, .pad = 132, .dac = 0, .bb_mult = 64, }, | ||
1903 | { .gm = 255, .pga = 255, .pad = 128, .dac = 0, .bb_mult = 64, }, | ||
1904 | { .gm = 255, .pga = 255, .pad = 124, .dac = 0, .bb_mult = 64, }, | ||
1905 | { .gm = 255, .pga = 255, .pad = 121, .dac = 0, .bb_mult = 64, }, | ||
1906 | { .gm = 255, .pga = 255, .pad = 117, .dac = 0, .bb_mult = 64, }, | ||
1907 | { .gm = 255, .pga = 255, .pad = 114, .dac = 0, .bb_mult = 64, }, | ||
1908 | { .gm = 255, .pga = 255, .pad = 111, .dac = 0, .bb_mult = 64, }, | ||
1909 | { .gm = 255, .pga = 255, .pad = 108, .dac = 0, .bb_mult = 64, }, | ||
1910 | { .gm = 255, .pga = 255, .pad = 105, .dac = 0, .bb_mult = 64, }, | ||
1911 | { .gm = 255, .pga = 255, .pad = 102, .dac = 0, .bb_mult = 64, }, | ||
1912 | { .gm = 255, .pga = 255, .pad = 99, .dac = 0, .bb_mult = 64, }, | ||
1913 | { .gm = 255, .pga = 255, .pad = 96, .dac = 0, .bb_mult = 64, }, | ||
1914 | { .gm = 255, .pga = 255, .pad = 93, .dac = 0, .bb_mult = 64, }, | ||
1915 | { .gm = 255, .pga = 255, .pad = 91, .dac = 0, .bb_mult = 64, }, | ||
1916 | { .gm = 255, .pga = 255, .pad = 88, .dac = 0, .bb_mult = 64, }, | ||
1917 | { .gm = 255, .pga = 255, .pad = 86, .dac = 0, .bb_mult = 64, }, | ||
1918 | { .gm = 255, .pga = 255, .pad = 83, .dac = 0, .bb_mult = 64, }, | ||
1919 | { .gm = 255, .pga = 255, .pad = 81, .dac = 0, .bb_mult = 64, }, | ||
1920 | { .gm = 255, .pga = 255, .pad = 79, .dac = 0, .bb_mult = 64, }, | ||
1921 | { .gm = 255, .pga = 255, .pad = 76, .dac = 0, .bb_mult = 64, }, | ||
1922 | { .gm = 255, .pga = 255, .pad = 74, .dac = 0, .bb_mult = 64, }, | ||
1923 | { .gm = 255, .pga = 255, .pad = 72, .dac = 0, .bb_mult = 64, }, | ||
1924 | { .gm = 255, .pga = 255, .pad = 70, .dac = 0, .bb_mult = 64, }, | ||
1925 | { .gm = 255, .pga = 255, .pad = 68, .dac = 0, .bb_mult = 64, }, | ||
1926 | { .gm = 255, .pga = 255, .pad = 66, .dac = 0, .bb_mult = 64, }, | ||
1927 | { .gm = 255, .pga = 255, .pad = 64, .dac = 0, .bb_mult = 64, }, | ||
1928 | { .gm = 255, .pga = 248, .pad = 64, .dac = 0, .bb_mult = 64, }, | ||
1929 | { .gm = 255, .pga = 248, .pad = 62, .dac = 0, .bb_mult = 64, }, | ||
1930 | { .gm = 255, .pga = 241, .pad = 62, .dac = 0, .bb_mult = 64, }, | ||
1931 | { .gm = 255, .pga = 241, .pad = 60, .dac = 0, .bb_mult = 64, }, | ||
1932 | { .gm = 255, .pga = 234, .pad = 60, .dac = 0, .bb_mult = 64, }, | ||
1933 | { .gm = 255, .pga = 234, .pad = 59, .dac = 0, .bb_mult = 64, }, | ||
1934 | { .gm = 255, .pga = 227, .pad = 59, .dac = 0, .bb_mult = 64, }, | ||
1935 | { .gm = 255, .pga = 227, .pad = 57, .dac = 0, .bb_mult = 64, }, | ||
1936 | { .gm = 255, .pga = 221, .pad = 57, .dac = 0, .bb_mult = 64, }, | ||
1937 | { .gm = 255, .pga = 221, .pad = 55, .dac = 0, .bb_mult = 64, }, | ||
1938 | { .gm = 255, .pga = 215, .pad = 55, .dac = 0, .bb_mult = 64, }, | ||
1939 | { .gm = 255, .pga = 215, .pad = 54, .dac = 0, .bb_mult = 64, }, | ||
1940 | { .gm = 255, .pga = 208, .pad = 54, .dac = 0, .bb_mult = 64, }, | ||
1941 | { .gm = 255, .pga = 208, .pad = 52, .dac = 0, .bb_mult = 64, }, | ||
1942 | { .gm = 255, .pga = 203, .pad = 52, .dac = 0, .bb_mult = 64, }, | ||
1943 | { .gm = 255, .pga = 203, .pad = 51, .dac = 0, .bb_mult = 64, }, | ||
1944 | { .gm = 255, .pga = 197, .pad = 51, .dac = 0, .bb_mult = 64, }, | ||
1945 | { .gm = 255, .pga = 197, .pad = 49, .dac = 0, .bb_mult = 64, }, | ||
1946 | { .gm = 255, .pga = 191, .pad = 49, .dac = 0, .bb_mult = 64, }, | ||
1947 | { .gm = 255, .pga = 191, .pad = 48, .dac = 0, .bb_mult = 64, }, | ||
1948 | { .gm = 255, .pga = 186, .pad = 48, .dac = 0, .bb_mult = 64, }, | ||
1949 | { .gm = 255, .pga = 186, .pad = 47, .dac = 0, .bb_mult = 64, }, | ||
1950 | { .gm = 255, .pga = 181, .pad = 47, .dac = 0, .bb_mult = 64, }, | ||
1951 | { .gm = 255, .pga = 181, .pad = 45, .dac = 0, .bb_mult = 64, }, | ||
1952 | { .gm = 255, .pga = 175, .pad = 45, .dac = 0, .bb_mult = 64, }, | ||
1953 | { .gm = 255, .pga = 175, .pad = 44, .dac = 0, .bb_mult = 64, }, | ||
1954 | { .gm = 255, .pga = 170, .pad = 44, .dac = 0, .bb_mult = 64, }, | ||
1955 | { .gm = 255, .pga = 170, .pad = 43, .dac = 0, .bb_mult = 64, }, | ||
1956 | { .gm = 255, .pga = 166, .pad = 43, .dac = 0, .bb_mult = 64, }, | ||
1957 | { .gm = 255, .pga = 166, .pad = 42, .dac = 0, .bb_mult = 64, }, | ||
1958 | { .gm = 255, .pga = 161, .pad = 42, .dac = 0, .bb_mult = 64, }, | ||
1959 | { .gm = 255, .pga = 161, .pad = 40, .dac = 0, .bb_mult = 64, }, | ||
1960 | { .gm = 255, .pga = 156, .pad = 40, .dac = 0, .bb_mult = 64, }, | ||
1961 | { .gm = 255, .pga = 156, .pad = 39, .dac = 0, .bb_mult = 64, }, | ||
1962 | { .gm = 255, .pga = 152, .pad = 39, .dac = 0, .bb_mult = 64, }, | ||
1963 | { .gm = 255, .pga = 152, .pad = 38, .dac = 0, .bb_mult = 64, }, | ||
1964 | { .gm = 255, .pga = 148, .pad = 38, .dac = 0, .bb_mult = 64, }, | ||
1965 | { .gm = 255, .pga = 148, .pad = 37, .dac = 0, .bb_mult = 64, }, | ||
1966 | { .gm = 255, .pga = 143, .pad = 37, .dac = 0, .bb_mult = 64, }, | ||
1967 | { .gm = 255, .pga = 143, .pad = 36, .dac = 0, .bb_mult = 64, }, | ||
1968 | { .gm = 255, .pga = 139, .pad = 36, .dac = 0, .bb_mult = 64, }, | ||
1969 | { .gm = 255, .pga = 139, .pad = 35, .dac = 0, .bb_mult = 64, }, | ||
1970 | { .gm = 255, .pga = 135, .pad = 35, .dac = 0, .bb_mult = 64, }, | ||
1971 | { .gm = 255, .pga = 135, .pad = 34, .dac = 0, .bb_mult = 64, }, | ||
1972 | { .gm = 255, .pga = 132, .pad = 34, .dac = 0, .bb_mult = 64, }, | ||
1973 | { .gm = 255, .pga = 132, .pad = 33, .dac = 0, .bb_mult = 64, }, | ||
1974 | { .gm = 255, .pga = 128, .pad = 33, .dac = 0, .bb_mult = 64, }, | ||
1975 | { .gm = 255, .pga = 128, .pad = 32, .dac = 0, .bb_mult = 64, }, | ||
1976 | { .gm = 255, .pga = 124, .pad = 32, .dac = 0, .bb_mult = 64, }, | ||
1977 | { .gm = 255, .pga = 124, .pad = 31, .dac = 0, .bb_mult = 64, }, | ||
1978 | { .gm = 255, .pga = 121, .pad = 31, .dac = 0, .bb_mult = 64, }, | ||
1979 | { .gm = 255, .pga = 121, .pad = 30, .dac = 0, .bb_mult = 64, }, | ||
1980 | { .gm = 255, .pga = 117, .pad = 30, .dac = 0, .bb_mult = 64, }, | ||
1981 | { .gm = 255, .pga = 117, .pad = 29, .dac = 0, .bb_mult = 64, }, | ||
1982 | { .gm = 255, .pga = 114, .pad = 29, .dac = 0, .bb_mult = 64, }, | ||
1983 | { .gm = 255, .pga = 114, .pad = 29, .dac = 0, .bb_mult = 64, }, | ||
1984 | { .gm = 255, .pga = 111, .pad = 29, .dac = 0, .bb_mult = 64, }, | ||
1985 | }; | ||
1986 | |||
1987 | static struct lpphy_tx_gain_table_entry lpphy_rev2_2ghz_tx_gain_table[] = { | ||
1988 | { .gm = 7, .pga = 99, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
1989 | { .gm = 7, .pga = 96, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
1990 | { .gm = 7, .pga = 93, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
1991 | { .gm = 7, .pga = 90, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
1992 | { .gm = 7, .pga = 88, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
1993 | { .gm = 7, .pga = 85, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
1994 | { .gm = 7, .pga = 83, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
1995 | { .gm = 7, .pga = 81, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
1996 | { .gm = 7, .pga = 78, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
1997 | { .gm = 7, .pga = 76, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
1998 | { .gm = 7, .pga = 74, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
1999 | { .gm = 7, .pga = 72, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2000 | { .gm = 7, .pga = 70, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2001 | { .gm = 7, .pga = 68, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2002 | { .gm = 7, .pga = 66, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2003 | { .gm = 7, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2004 | { .gm = 7, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2005 | { .gm = 7, .pga = 62, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2006 | { .gm = 7, .pga = 62, .pad = 248, .dac = 0, .bb_mult = 64, }, | ||
2007 | { .gm = 7, .pga = 60, .pad = 248, .dac = 0, .bb_mult = 64, }, | ||
2008 | { .gm = 7, .pga = 60, .pad = 241, .dac = 0, .bb_mult = 64, }, | ||
2009 | { .gm = 7, .pga = 59, .pad = 241, .dac = 0, .bb_mult = 64, }, | ||
2010 | { .gm = 7, .pga = 59, .pad = 234, .dac = 0, .bb_mult = 64, }, | ||
2011 | { .gm = 7, .pga = 57, .pad = 234, .dac = 0, .bb_mult = 64, }, | ||
2012 | { .gm = 7, .pga = 57, .pad = 227, .dac = 0, .bb_mult = 64, }, | ||
2013 | { .gm = 7, .pga = 55, .pad = 227, .dac = 0, .bb_mult = 64, }, | ||
2014 | { .gm = 7, .pga = 55, .pad = 221, .dac = 0, .bb_mult = 64, }, | ||
2015 | { .gm = 7, .pga = 54, .pad = 221, .dac = 0, .bb_mult = 64, }, | ||
2016 | { .gm = 7, .pga = 54, .pad = 215, .dac = 0, .bb_mult = 64, }, | ||
2017 | { .gm = 7, .pga = 52, .pad = 215, .dac = 0, .bb_mult = 64, }, | ||
2018 | { .gm = 7, .pga = 52, .pad = 208, .dac = 0, .bb_mult = 64, }, | ||
2019 | { .gm = 7, .pga = 51, .pad = 208, .dac = 0, .bb_mult = 64, }, | ||
2020 | { .gm = 7, .pga = 51, .pad = 203, .dac = 0, .bb_mult = 64, }, | ||
2021 | { .gm = 7, .pga = 49, .pad = 203, .dac = 0, .bb_mult = 64, }, | ||
2022 | { .gm = 7, .pga = 49, .pad = 197, .dac = 0, .bb_mult = 64, }, | ||
2023 | { .gm = 7, .pga = 48, .pad = 197, .dac = 0, .bb_mult = 64, }, | ||
2024 | { .gm = 7, .pga = 48, .pad = 191, .dac = 0, .bb_mult = 64, }, | ||
2025 | { .gm = 7, .pga = 47, .pad = 191, .dac = 0, .bb_mult = 64, }, | ||
2026 | { .gm = 7, .pga = 47, .pad = 186, .dac = 0, .bb_mult = 64, }, | ||
2027 | { .gm = 7, .pga = 45, .pad = 186, .dac = 0, .bb_mult = 64, }, | ||
2028 | { .gm = 7, .pga = 45, .pad = 181, .dac = 0, .bb_mult = 64, }, | ||
2029 | { .gm = 7, .pga = 44, .pad = 181, .dac = 0, .bb_mult = 64, }, | ||
2030 | { .gm = 7, .pga = 44, .pad = 175, .dac = 0, .bb_mult = 64, }, | ||
2031 | { .gm = 7, .pga = 43, .pad = 175, .dac = 0, .bb_mult = 64, }, | ||
2032 | { .gm = 7, .pga = 43, .pad = 170, .dac = 0, .bb_mult = 64, }, | ||
2033 | { .gm = 7, .pga = 42, .pad = 170, .dac = 0, .bb_mult = 64, }, | ||
2034 | { .gm = 7, .pga = 42, .pad = 166, .dac = 0, .bb_mult = 64, }, | ||
2035 | { .gm = 7, .pga = 40, .pad = 166, .dac = 0, .bb_mult = 64, }, | ||
2036 | { .gm = 7, .pga = 40, .pad = 161, .dac = 0, .bb_mult = 64, }, | ||
2037 | { .gm = 7, .pga = 39, .pad = 161, .dac = 0, .bb_mult = 64, }, | ||
2038 | { .gm = 7, .pga = 39, .pad = 156, .dac = 0, .bb_mult = 64, }, | ||
2039 | { .gm = 7, .pga = 38, .pad = 156, .dac = 0, .bb_mult = 64, }, | ||
2040 | { .gm = 7, .pga = 38, .pad = 152, .dac = 0, .bb_mult = 64, }, | ||
2041 | { .gm = 7, .pga = 37, .pad = 152, .dac = 0, .bb_mult = 64, }, | ||
2042 | { .gm = 7, .pga = 37, .pad = 148, .dac = 0, .bb_mult = 64, }, | ||
2043 | { .gm = 7, .pga = 36, .pad = 148, .dac = 0, .bb_mult = 64, }, | ||
2044 | { .gm = 7, .pga = 36, .pad = 143, .dac = 0, .bb_mult = 64, }, | ||
2045 | { .gm = 7, .pga = 35, .pad = 143, .dac = 0, .bb_mult = 64, }, | ||
2046 | { .gm = 7, .pga = 35, .pad = 139, .dac = 0, .bb_mult = 64, }, | ||
2047 | { .gm = 7, .pga = 34, .pad = 139, .dac = 0, .bb_mult = 64, }, | ||
2048 | { .gm = 7, .pga = 34, .pad = 135, .dac = 0, .bb_mult = 64, }, | ||
2049 | { .gm = 7, .pga = 33, .pad = 135, .dac = 0, .bb_mult = 64, }, | ||
2050 | { .gm = 7, .pga = 33, .pad = 132, .dac = 0, .bb_mult = 64, }, | ||
2051 | { .gm = 7, .pga = 32, .pad = 132, .dac = 0, .bb_mult = 64, }, | ||
2052 | { .gm = 7, .pga = 32, .pad = 128, .dac = 0, .bb_mult = 64, }, | ||
2053 | { .gm = 7, .pga = 31, .pad = 128, .dac = 0, .bb_mult = 64, }, | ||
2054 | { .gm = 7, .pga = 31, .pad = 124, .dac = 0, .bb_mult = 64, }, | ||
2055 | { .gm = 7, .pga = 30, .pad = 124, .dac = 0, .bb_mult = 64, }, | ||
2056 | { .gm = 7, .pga = 30, .pad = 121, .dac = 0, .bb_mult = 64, }, | ||
2057 | { .gm = 7, .pga = 29, .pad = 121, .dac = 0, .bb_mult = 64, }, | ||
2058 | { .gm = 7, .pga = 29, .pad = 117, .dac = 0, .bb_mult = 64, }, | ||
2059 | { .gm = 7, .pga = 29, .pad = 117, .dac = 0, .bb_mult = 64, }, | ||
2060 | { .gm = 7, .pga = 29, .pad = 114, .dac = 0, .bb_mult = 64, }, | ||
2061 | { .gm = 7, .pga = 28, .pad = 114, .dac = 0, .bb_mult = 64, }, | ||
2062 | { .gm = 7, .pga = 28, .pad = 111, .dac = 0, .bb_mult = 64, }, | ||
2063 | { .gm = 7, .pga = 27, .pad = 111, .dac = 0, .bb_mult = 64, }, | ||
2064 | { .gm = 7, .pga = 27, .pad = 108, .dac = 0, .bb_mult = 64, }, | ||
2065 | { .gm = 7, .pga = 26, .pad = 108, .dac = 0, .bb_mult = 64, }, | ||
2066 | { .gm = 7, .pga = 26, .pad = 104, .dac = 0, .bb_mult = 64, }, | ||
2067 | { .gm = 7, .pga = 25, .pad = 104, .dac = 0, .bb_mult = 64, }, | ||
2068 | { .gm = 7, .pga = 25, .pad = 102, .dac = 0, .bb_mult = 64, }, | ||
2069 | { .gm = 7, .pga = 25, .pad = 102, .dac = 0, .bb_mult = 64, }, | ||
2070 | { .gm = 7, .pga = 25, .pad = 99, .dac = 0, .bb_mult = 64, }, | ||
2071 | { .gm = 7, .pga = 24, .pad = 99, .dac = 0, .bb_mult = 64, }, | ||
2072 | { .gm = 7, .pga = 24, .pad = 96, .dac = 0, .bb_mult = 64, }, | ||
2073 | { .gm = 7, .pga = 23, .pad = 96, .dac = 0, .bb_mult = 64, }, | ||
2074 | { .gm = 7, .pga = 23, .pad = 93, .dac = 0, .bb_mult = 64, }, | ||
2075 | { .gm = 7, .pga = 23, .pad = 93, .dac = 0, .bb_mult = 64, }, | ||
2076 | { .gm = 7, .pga = 23, .pad = 90, .dac = 0, .bb_mult = 64, }, | ||
2077 | { .gm = 7, .pga = 22, .pad = 90, .dac = 0, .bb_mult = 64, }, | ||
2078 | { .gm = 7, .pga = 22, .pad = 88, .dac = 0, .bb_mult = 64, }, | ||
2079 | { .gm = 7, .pga = 21, .pad = 88, .dac = 0, .bb_mult = 64, }, | ||
2080 | { .gm = 7, .pga = 21, .pad = 85, .dac = 0, .bb_mult = 64, }, | ||
2081 | { .gm = 7, .pga = 21, .pad = 85, .dac = 0, .bb_mult = 64, }, | ||
2082 | { .gm = 7, .pga = 21, .pad = 83, .dac = 0, .bb_mult = 64, }, | ||
2083 | { .gm = 7, .pga = 20, .pad = 83, .dac = 0, .bb_mult = 64, }, | ||
2084 | { .gm = 7, .pga = 20, .pad = 81, .dac = 0, .bb_mult = 64, }, | ||
2085 | { .gm = 7, .pga = 20, .pad = 81, .dac = 0, .bb_mult = 64, }, | ||
2086 | { .gm = 7, .pga = 20, .pad = 78, .dac = 0, .bb_mult = 64, }, | ||
2087 | { .gm = 7, .pga = 19, .pad = 78, .dac = 0, .bb_mult = 64, }, | ||
2088 | { .gm = 7, .pga = 19, .pad = 76, .dac = 0, .bb_mult = 64, }, | ||
2089 | { .gm = 7, .pga = 19, .pad = 76, .dac = 0, .bb_mult = 64, }, | ||
2090 | { .gm = 7, .pga = 19, .pad = 74, .dac = 0, .bb_mult = 64, }, | ||
2091 | { .gm = 7, .pga = 18, .pad = 74, .dac = 0, .bb_mult = 64, }, | ||
2092 | { .gm = 7, .pga = 18, .pad = 72, .dac = 0, .bb_mult = 64, }, | ||
2093 | { .gm = 7, .pga = 18, .pad = 72, .dac = 0, .bb_mult = 64, }, | ||
2094 | { .gm = 7, .pga = 18, .pad = 70, .dac = 0, .bb_mult = 64, }, | ||
2095 | { .gm = 7, .pga = 17, .pad = 70, .dac = 0, .bb_mult = 64, }, | ||
2096 | { .gm = 7, .pga = 17, .pad = 68, .dac = 0, .bb_mult = 64, }, | ||
2097 | { .gm = 7, .pga = 17, .pad = 68, .dac = 0, .bb_mult = 64, }, | ||
2098 | { .gm = 7, .pga = 17, .pad = 66, .dac = 0, .bb_mult = 64, }, | ||
2099 | { .gm = 7, .pga = 16, .pad = 66, .dac = 0, .bb_mult = 64, }, | ||
2100 | { .gm = 7, .pga = 16, .pad = 64, .dac = 0, .bb_mult = 64, }, | ||
2101 | { .gm = 7, .pga = 16, .pad = 64, .dac = 0, .bb_mult = 64, }, | ||
2102 | { .gm = 7, .pga = 16, .pad = 62, .dac = 0, .bb_mult = 64, }, | ||
2103 | { .gm = 7, .pga = 15, .pad = 62, .dac = 0, .bb_mult = 64, }, | ||
2104 | { .gm = 7, .pga = 15, .pad = 60, .dac = 0, .bb_mult = 64, }, | ||
2105 | { .gm = 7, .pga = 15, .pad = 60, .dac = 0, .bb_mult = 64, }, | ||
2106 | { .gm = 7, .pga = 15, .pad = 59, .dac = 0, .bb_mult = 64, }, | ||
2107 | { .gm = 7, .pga = 14, .pad = 59, .dac = 0, .bb_mult = 64, }, | ||
2108 | { .gm = 7, .pga = 14, .pad = 57, .dac = 0, .bb_mult = 64, }, | ||
2109 | { .gm = 7, .pga = 14, .pad = 57, .dac = 0, .bb_mult = 64, }, | ||
2110 | { .gm = 7, .pga = 14, .pad = 55, .dac = 0, .bb_mult = 64, }, | ||
2111 | { .gm = 7, .pga = 14, .pad = 55, .dac = 0, .bb_mult = 64, }, | ||
2112 | { .gm = 7, .pga = 14, .pad = 54, .dac = 0, .bb_mult = 64, }, | ||
2113 | { .gm = 7, .pga = 13, .pad = 54, .dac = 0, .bb_mult = 64, }, | ||
2114 | { .gm = 7, .pga = 13, .pad = 52, .dac = 0, .bb_mult = 64, }, | ||
2115 | { .gm = 7, .pga = 13, .pad = 52, .dac = 0, .bb_mult = 64, }, | ||
2116 | }; | ||
2117 | |||
2118 | static struct lpphy_tx_gain_table_entry lpphy_rev2_5ghz_tx_gain_table[] = { | ||
2119 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 152, }, | ||
2120 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 147, }, | ||
2121 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 143, }, | ||
2122 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 139, }, | ||
2123 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 135, }, | ||
2124 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 131, }, | ||
2125 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 128, }, | ||
2126 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 124, }, | ||
2127 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 121, }, | ||
2128 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 117, }, | ||
2129 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 114, }, | ||
2130 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 111, }, | ||
2131 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 107, }, | ||
2132 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 104, }, | ||
2133 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 101, }, | ||
2134 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 99, }, | ||
2135 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 96, }, | ||
2136 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 93, }, | ||
2137 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 90, }, | ||
2138 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 88, }, | ||
2139 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 85, }, | ||
2140 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 83, }, | ||
2141 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 81, }, | ||
2142 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 78, }, | ||
2143 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 76, }, | ||
2144 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 74, }, | ||
2145 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 72, }, | ||
2146 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 70, }, | ||
2147 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 68, }, | ||
2148 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 66, }, | ||
2149 | { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2150 | { .gm = 255, .pga = 248, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2151 | { .gm = 255, .pga = 241, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2152 | { .gm = 255, .pga = 234, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2153 | { .gm = 255, .pga = 227, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2154 | { .gm = 255, .pga = 221, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2155 | { .gm = 255, .pga = 215, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2156 | { .gm = 255, .pga = 208, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2157 | { .gm = 255, .pga = 203, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2158 | { .gm = 255, .pga = 197, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2159 | { .gm = 255, .pga = 191, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2160 | { .gm = 255, .pga = 186, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2161 | { .gm = 255, .pga = 181, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2162 | { .gm = 255, .pga = 175, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2163 | { .gm = 255, .pga = 170, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2164 | { .gm = 255, .pga = 166, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2165 | { .gm = 255, .pga = 161, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2166 | { .gm = 255, .pga = 156, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2167 | { .gm = 255, .pga = 152, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2168 | { .gm = 255, .pga = 148, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2169 | { .gm = 255, .pga = 143, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2170 | { .gm = 255, .pga = 139, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2171 | { .gm = 255, .pga = 135, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2172 | { .gm = 255, .pga = 132, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2173 | { .gm = 255, .pga = 128, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2174 | { .gm = 255, .pga = 124, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2175 | { .gm = 255, .pga = 121, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2176 | { .gm = 255, .pga = 117, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2177 | { .gm = 255, .pga = 114, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2178 | { .gm = 255, .pga = 111, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2179 | { .gm = 255, .pga = 108, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2180 | { .gm = 255, .pga = 104, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2181 | { .gm = 255, .pga = 102, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2182 | { .gm = 255, .pga = 99, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2183 | { .gm = 255, .pga = 96, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2184 | { .gm = 255, .pga = 93, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2185 | { .gm = 255, .pga = 90, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2186 | { .gm = 255, .pga = 88, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2187 | { .gm = 255, .pga = 85, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2188 | { .gm = 255, .pga = 83, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2189 | { .gm = 255, .pga = 81, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2190 | { .gm = 255, .pga = 78, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2191 | { .gm = 255, .pga = 76, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2192 | { .gm = 255, .pga = 74, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2193 | { .gm = 255, .pga = 72, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2194 | { .gm = 255, .pga = 70, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2195 | { .gm = 255, .pga = 68, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2196 | { .gm = 255, .pga = 66, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2197 | { .gm = 255, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2198 | { .gm = 255, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2199 | { .gm = 255, .pga = 62, .pad = 255, .dac = 0, .bb_mult = 64, }, | ||
2200 | { .gm = 255, .pga = 62, .pad = 248, .dac = 0, .bb_mult = 64, }, | ||
2201 | { .gm = 255, .pga = 60, .pad = 248, .dac = 0, .bb_mult = 64, }, | ||
2202 | { .gm = 255, .pga = 60, .pad = 241, .dac = 0, .bb_mult = 64, }, | ||
2203 | { .gm = 255, .pga = 59, .pad = 241, .dac = 0, .bb_mult = 64, }, | ||
2204 | { .gm = 255, .pga = 59, .pad = 234, .dac = 0, .bb_mult = 64, }, | ||
2205 | { .gm = 255, .pga = 57, .pad = 234, .dac = 0, .bb_mult = 64, }, | ||
2206 | { .gm = 255, .pga = 57, .pad = 227, .dac = 0, .bb_mult = 64, }, | ||
2207 | { .gm = 255, .pga = 55, .pad = 227, .dac = 0, .bb_mult = 64, }, | ||
2208 | { .gm = 255, .pga = 55, .pad = 221, .dac = 0, .bb_mult = 64, }, | ||
2209 | { .gm = 255, .pga = 54, .pad = 221, .dac = 0, .bb_mult = 64, }, | ||
2210 | { .gm = 255, .pga = 54, .pad = 215, .dac = 0, .bb_mult = 64, }, | ||
2211 | { .gm = 255, .pga = 52, .pad = 215, .dac = 0, .bb_mult = 64, }, | ||
2212 | { .gm = 255, .pga = 52, .pad = 208, .dac = 0, .bb_mult = 64, }, | ||
2213 | { .gm = 255, .pga = 51, .pad = 208, .dac = 0, .bb_mult = 64, }, | ||
2214 | { .gm = 255, .pga = 51, .pad = 203, .dac = 0, .bb_mult = 64, }, | ||
2215 | { .gm = 255, .pga = 49, .pad = 203, .dac = 0, .bb_mult = 64, }, | ||
2216 | { .gm = 255, .pga = 49, .pad = 197, .dac = 0, .bb_mult = 64, }, | ||
2217 | { .gm = 255, .pga = 48, .pad = 197, .dac = 0, .bb_mult = 64, }, | ||
2218 | { .gm = 255, .pga = 48, .pad = 191, .dac = 0, .bb_mult = 64, }, | ||
2219 | { .gm = 255, .pga = 47, .pad = 191, .dac = 0, .bb_mult = 64, }, | ||
2220 | { .gm = 255, .pga = 47, .pad = 186, .dac = 0, .bb_mult = 64, }, | ||
2221 | { .gm = 255, .pga = 45, .pad = 186, .dac = 0, .bb_mult = 64, }, | ||
2222 | { .gm = 255, .pga = 45, .pad = 181, .dac = 0, .bb_mult = 64, }, | ||
2223 | { .gm = 255, .pga = 44, .pad = 181, .dac = 0, .bb_mult = 64, }, | ||
2224 | { .gm = 255, .pga = 44, .pad = 175, .dac = 0, .bb_mult = 64, }, | ||
2225 | { .gm = 255, .pga = 43, .pad = 175, .dac = 0, .bb_mult = 64, }, | ||
2226 | { .gm = 255, .pga = 43, .pad = 170, .dac = 0, .bb_mult = 64, }, | ||
2227 | { .gm = 255, .pga = 42, .pad = 170, .dac = 0, .bb_mult = 64, }, | ||
2228 | { .gm = 255, .pga = 42, .pad = 166, .dac = 0, .bb_mult = 64, }, | ||
2229 | { .gm = 255, .pga = 40, .pad = 166, .dac = 0, .bb_mult = 64, }, | ||
2230 | { .gm = 255, .pga = 40, .pad = 161, .dac = 0, .bb_mult = 64, }, | ||
2231 | { .gm = 255, .pga = 39, .pad = 161, .dac = 0, .bb_mult = 64, }, | ||
2232 | { .gm = 255, .pga = 39, .pad = 156, .dac = 0, .bb_mult = 64, }, | ||
2233 | { .gm = 255, .pga = 38, .pad = 156, .dac = 0, .bb_mult = 64, }, | ||
2234 | { .gm = 255, .pga = 38, .pad = 152, .dac = 0, .bb_mult = 64, }, | ||
2235 | { .gm = 255, .pga = 37, .pad = 152, .dac = 0, .bb_mult = 64, }, | ||
2236 | { .gm = 255, .pga = 37, .pad = 148, .dac = 0, .bb_mult = 64, }, | ||
2237 | { .gm = 255, .pga = 36, .pad = 148, .dac = 0, .bb_mult = 64, }, | ||
2238 | { .gm = 255, .pga = 36, .pad = 143, .dac = 0, .bb_mult = 64, }, | ||
2239 | { .gm = 255, .pga = 35, .pad = 143, .dac = 0, .bb_mult = 64, }, | ||
2240 | { .gm = 255, .pga = 35, .pad = 139, .dac = 0, .bb_mult = 64, }, | ||
2241 | { .gm = 255, .pga = 34, .pad = 139, .dac = 0, .bb_mult = 64, }, | ||
2242 | { .gm = 255, .pga = 34, .pad = 135, .dac = 0, .bb_mult = 64, }, | ||
2243 | { .gm = 255, .pga = 33, .pad = 135, .dac = 0, .bb_mult = 64, }, | ||
2244 | { .gm = 255, .pga = 33, .pad = 132, .dac = 0, .bb_mult = 64, }, | ||
2245 | { .gm = 255, .pga = 32, .pad = 132, .dac = 0, .bb_mult = 64, }, | ||
2246 | { .gm = 255, .pga = 32, .pad = 128, .dac = 0, .bb_mult = 64, }, | ||
2247 | }; | ||
2248 | |||
2249 | void lpphy_rev0_1_table_init(struct b43_wldev *dev) | ||
2250 | { | ||
2251 | B43_WARN_ON(dev->phy.rev >= 2); | ||
2252 | |||
2253 | b43_lptab_write_bulk(dev, B43_LPTAB8(2, 0), | ||
2254 | ARRAY_SIZE(lpphy_min_sig_sq_table), lpphy_min_sig_sq_table); | ||
2255 | b43_lptab_write_bulk(dev, B43_LPTAB16(1, 0), | ||
2256 | ARRAY_SIZE(lpphy_rev01_noise_scale_table), lpphy_rev01_noise_scale_table); | ||
2257 | b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0), | ||
2258 | ARRAY_SIZE(lpphy_crs_gain_nft_table), lpphy_crs_gain_nft_table); | ||
2259 | b43_lptab_write_bulk(dev, B43_LPTAB16(8, 0), | ||
2260 | ARRAY_SIZE(lpphy_rev01_filter_control_table), lpphy_rev01_filter_control_table); | ||
2261 | b43_lptab_write_bulk(dev, B43_LPTAB32(9, 0), | ||
2262 | ARRAY_SIZE(lpphy_rev01_ps_control_table), lpphy_rev01_ps_control_table); | ||
2263 | b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0), | ||
2264 | ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table); | ||
2265 | b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0), | ||
2266 | ARRAY_SIZE(lpphy_iq_local_table), lpphy_iq_local_table); | ||
2267 | b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), | ||
2268 | ARRAY_SIZE(lpphy_ofdm_cck_gain_table), lpphy_ofdm_cck_gain_table); | ||
2269 | b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), | ||
2270 | ARRAY_SIZE(lpphy_ofdm_cck_gain_table), lpphy_ofdm_cck_gain_table); | ||
2271 | b43_lptab_write_bulk(dev, B43_LPTAB16(15, 0), | ||
2272 | ARRAY_SIZE(lpphy_gain_delta_table), lpphy_gain_delta_table); | ||
2273 | b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0), | ||
2274 | ARRAY_SIZE(lpphy_tx_power_control_table), lpphy_tx_power_control_table); | ||
2275 | } | ||
2276 | |||
2277 | void lpphy_rev2plus_table_init(struct b43_wldev *dev) | ||
2278 | { | ||
2279 | struct ssb_bus *bus = dev->dev->bus; | ||
2280 | int i; | ||
2281 | |||
2282 | B43_WARN_ON(dev->phy.rev < 2); | ||
2283 | |||
2284 | /* | ||
2285 | * FIXME This code follows the specs, but it looks wrong: | ||
2286 | * In each pass, it writes 4 bytes to an offset in table ID 7, | ||
2287 | * then increments the offset by 1 for the next pass. This results | ||
2288 | * in the first 3 bytes of each pass except the first one getting | ||
2289 | * written to a location that has already been zeroed in the previous | ||
2290 | * pass. | ||
2291 | * This is what the vendor driver does, but it still looks suspicious. | ||
2292 | * | ||
2293 | * This should probably suffice: | ||
2294 | * | ||
2295 | * for (i = 0; i < 704; i+=4) | ||
2296 | * b43_lptab_write(dev, B43_LPTAB32(7, i), 0) | ||
2297 | * | ||
2298 | * This should be tested once the code is functional. | ||
2299 | */ | ||
2300 | for (i = 0; i < 704; i++) | ||
2301 | b43_lptab_write(dev, B43_LPTAB32(7, i), 0); | ||
2302 | |||
2303 | b43_lptab_write_bulk(dev, B43_LPTAB8(2, 0), | ||
2304 | ARRAY_SIZE(lpphy_min_sig_sq_table), lpphy_min_sig_sq_table); | ||
2305 | b43_lptab_write_bulk(dev, B43_LPTAB16(1, 0), | ||
2306 | ARRAY_SIZE(lpphy_rev2plus_noise_scale_table), lpphy_rev2plus_noise_scale_table); | ||
2307 | b43_lptab_write_bulk(dev, B43_LPTAB32(11, 0), | ||
2308 | ARRAY_SIZE(lpphy_rev2plus_filter_control_table), lpphy_rev2plus_filter_control_table); | ||
2309 | b43_lptab_write_bulk(dev, B43_LPTAB32(12, 0), | ||
2310 | ARRAY_SIZE(lpphy_rev2plus_ps_control_table), lpphy_rev2plus_ps_control_table); | ||
2311 | b43_lptab_write_bulk(dev, B43_LPTAB32(13, 0), | ||
2312 | ARRAY_SIZE(lpphy_gain_idx_table), lpphy_gain_idx_table); | ||
2313 | b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0), | ||
2314 | ARRAY_SIZE(lpphy_aux_gain_idx_table), lpphy_aux_gain_idx_table); | ||
2315 | b43_lptab_write_bulk(dev, B43_LPTAB16(15, 0), | ||
2316 | ARRAY_SIZE(lpphy_sw_control_table), lpphy_sw_control_table); | ||
2317 | b43_lptab_write_bulk(dev, B43_LPTAB8(16, 0), | ||
2318 | ARRAY_SIZE(lpphy_hf_table), lpphy_hf_table); | ||
2319 | b43_lptab_write_bulk(dev, B43_LPTAB32(17, 0), | ||
2320 | ARRAY_SIZE(lpphy_gain_value_table), lpphy_gain_value_table); | ||
2321 | b43_lptab_write_bulk(dev, B43_LPTAB16(18, 0), | ||
2322 | ARRAY_SIZE(lpphy_gain_table), lpphy_gain_table); | ||
2323 | b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0), | ||
2324 | ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table); | ||
2325 | b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0), | ||
2326 | ARRAY_SIZE(lpphy_iq_local_table), lpphy_iq_local_table); | ||
2327 | b43_lptab_write_bulk(dev, B43_LPTAB32(9, 0), | ||
2328 | ARRAY_SIZE(lpphy_papd_eps_table), lpphy_papd_eps_table); | ||
2329 | b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0), | ||
2330 | ARRAY_SIZE(lpphy_papd_mult_table), lpphy_papd_mult_table); | ||
2331 | |||
2332 | if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { | ||
2333 | b43_lptab_write_bulk(dev, B43_LPTAB32(13, 0), | ||
2334 | ARRAY_SIZE(lpphy_a0_gain_idx_table), lpphy_a0_gain_idx_table); | ||
2335 | b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0), | ||
2336 | ARRAY_SIZE(lpphy_a0_aux_gain_idx_table), lpphy_a0_aux_gain_idx_table); | ||
2337 | b43_lptab_write_bulk(dev, B43_LPTAB32(17, 0), | ||
2338 | ARRAY_SIZE(lpphy_a0_gain_value_table), lpphy_a0_gain_value_table); | ||
2339 | b43_lptab_write_bulk(dev, B43_LPTAB16(18, 0), | ||
2340 | ARRAY_SIZE(lpphy_a0_gain_table), lpphy_a0_gain_table); | ||
2341 | } | ||
2342 | } | ||
2343 | |||
2344 | static void lpphy_rev0_1_write_gain_table(struct b43_wldev *dev, int offset, | ||
2345 | struct lpphy_tx_gain_table_entry data) | ||
2346 | { | ||
2347 | u32 tmp; | ||
2348 | |||
2349 | B43_WARN_ON(dev->phy.rev >= 2); | ||
2350 | |||
2351 | tmp = data.pad << 11; | ||
2352 | tmp |= data.pga << 7; | ||
2353 | tmp |= data.gm << 4; | ||
2354 | tmp |= data.dac; | ||
2355 | b43_lptab_write(dev, B43_LPTAB32(10, 0xC0 + offset), tmp); | ||
2356 | tmp = data.bb_mult << 20; | ||
2357 | b43_lptab_write(dev, B43_LPTAB32(10, 0x140 + offset), tmp); | ||
2358 | } | ||
2359 | |||
2360 | static void lpphy_rev2plus_write_gain_table(struct b43_wldev *dev, int offset, | ||
2361 | struct lpphy_tx_gain_table_entry data) | ||
2362 | { | ||
2363 | u32 tmp; | ||
2364 | |||
2365 | B43_WARN_ON(dev->phy.rev < 2); | ||
2366 | |||
2367 | tmp = data.pad << 16; | ||
2368 | tmp |= data.pga << 8; | ||
2369 | tmp |= data.gm; | ||
2370 | tmp |= 0x7f000000; | ||
2371 | b43_lptab_write(dev, B43_LPTAB32(7, 0xC0 + offset), tmp); | ||
2372 | tmp = data.bb_mult << 20; | ||
2373 | tmp |= data.dac << 28; | ||
2374 | b43_lptab_write(dev, B43_LPTAB32(7, 0x140 + offset), tmp); | ||
2375 | } | ||
2376 | |||
2377 | void lpphy_write_gain_table(struct b43_wldev *dev, int offset, | ||
2378 | struct lpphy_tx_gain_table_entry data) | ||
2379 | { | ||
2380 | if (dev->phy.rev >= 2) | ||
2381 | lpphy_rev2plus_write_gain_table(dev, offset, data); | ||
2382 | else | ||
2383 | lpphy_rev0_1_write_gain_table(dev, offset, data); | ||
2384 | } | ||
2385 | |||
2386 | void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count, | ||
2387 | struct lpphy_tx_gain_table_entry *table) | ||
2388 | { | ||
2389 | int i; | ||
2390 | |||
2391 | for (i = offset; i < count; i++) | ||
2392 | lpphy_write_gain_table(dev, i, table[i]); | ||
2393 | } | ||
2394 | |||
2395 | void lpphy_init_tx_gain_table(struct b43_wldev *dev) | ||
2396 | { | ||
2397 | struct ssb_bus *bus = dev->dev->bus; | ||
2398 | |||
2399 | switch (dev->phy.rev) { | ||
2400 | case 0: | ||
2401 | if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) || | ||
2402 | (bus->sprom.boardflags_lo & B43_BFL_HGPA)) | ||
2403 | lpphy_write_gain_table_bulk(dev, 0, 128, | ||
2404 | lpphy_rev0_nopa_tx_gain_table); | ||
2405 | else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) | ||
2406 | lpphy_write_gain_table_bulk(dev, 0, 128, | ||
2407 | lpphy_rev0_2ghz_tx_gain_table); | ||
2408 | else | ||
2409 | lpphy_write_gain_table_bulk(dev, 0, 128, | ||
2410 | lpphy_rev0_5ghz_tx_gain_table); | ||
2411 | break; | ||
2412 | case 1: | ||
2413 | if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) || | ||
2414 | (bus->sprom.boardflags_lo & B43_BFL_HGPA)) | ||
2415 | lpphy_write_gain_table_bulk(dev, 0, 128, | ||
2416 | lpphy_rev1_nopa_tx_gain_table); | ||
2417 | else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) | ||
2418 | lpphy_write_gain_table_bulk(dev, 0, 128, | ||
2419 | lpphy_rev1_2ghz_tx_gain_table); | ||
2420 | else | ||
2421 | lpphy_write_gain_table_bulk(dev, 0, 128, | ||
2422 | lpphy_rev1_5ghz_tx_gain_table); | ||
2423 | break; | ||
2424 | default: | ||
2425 | if (bus->sprom.boardflags_hi & B43_BFH_NOPA) | ||
2426 | lpphy_write_gain_table_bulk(dev, 0, 128, | ||
2427 | lpphy_rev2_nopa_tx_gain_table); | ||
2428 | else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) | ||
2429 | lpphy_write_gain_table_bulk(dev, 0, 128, | ||
2430 | lpphy_rev2_2ghz_tx_gain_table); | ||
2431 | else | ||
2432 | lpphy_write_gain_table_bulk(dev, 0, 128, | ||
2433 | lpphy_rev2_5ghz_tx_gain_table); | ||
2434 | } | ||
2435 | } | ||
diff --git a/drivers/net/wireless/b43/tables_lpphy.h b/drivers/net/wireless/b43/tables_lpphy.h index 0b8d02895a5d..84f1d265f657 100644 --- a/drivers/net/wireless/b43/tables_lpphy.h +++ b/drivers/net/wireless/b43/tables_lpphy.h | |||
@@ -26,6 +26,19 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, | |||
26 | unsigned int nr_elements, const void *data); | 26 | unsigned int nr_elements, const void *data); |
27 | 27 | ||
28 | void b2062_upload_init_table(struct b43_wldev *dev); | 28 | void b2062_upload_init_table(struct b43_wldev *dev); |
29 | void b2063_upload_init_table(struct b43_wldev *dev); | ||
29 | 30 | ||
31 | struct lpphy_tx_gain_table_entry { | ||
32 | u8 gm, pga, pad, dac, bb_mult; | ||
33 | }; | ||
34 | |||
35 | void lpphy_write_gain_table(struct b43_wldev *dev, int offset, | ||
36 | struct lpphy_tx_gain_table_entry data); | ||
37 | void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count, | ||
38 | struct lpphy_tx_gain_table_entry *table); | ||
39 | |||
40 | void lpphy_rev0_1_table_init(struct b43_wldev *dev); | ||
41 | void lpphy_rev2plus_table_init(struct b43_wldev *dev); | ||
42 | void lpphy_init_tx_gain_table(struct b43_wldev *dev); | ||
30 | 43 | ||
31 | #endif /* B43_TABLES_LPPHY_H_ */ | 44 | #endif /* B43_TABLES_LPPHY_H_ */ |
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 5b85e7d73592..5280ebc8c6e9 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c | |||
@@ -237,7 +237,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, | |||
237 | int wlhdr_len; | 237 | int wlhdr_len; |
238 | size_t iv_len; | 238 | size_t iv_len; |
239 | 239 | ||
240 | B43_WARN_ON(key_idx >= dev->max_nr_keys); | 240 | B43_WARN_ON(key_idx >= ARRAY_SIZE(dev->key)); |
241 | key = &(dev->key[key_idx]); | 241 | key = &(dev->key[key_idx]); |
242 | 242 | ||
243 | if (unlikely(!key->keyconf)) { | 243 | if (unlikely(!key->keyconf)) { |
@@ -578,7 +578,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) | |||
578 | * key index, but the ucode passed it slightly different. | 578 | * key index, but the ucode passed it slightly different. |
579 | */ | 579 | */ |
580 | keyidx = b43_kidx_to_raw(dev, keyidx); | 580 | keyidx = b43_kidx_to_raw(dev, keyidx); |
581 | B43_WARN_ON(keyidx >= dev->max_nr_keys); | 581 | B43_WARN_ON(keyidx >= ARRAY_SIZE(dev->key)); |
582 | 582 | ||
583 | if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) { | 583 | if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) { |
584 | wlhdr_len = ieee80211_hdrlen(fctl); | 584 | wlhdr_len = ieee80211_hdrlen(fctl); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index cf3fbc6b98ef..191718a0c545 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c | |||
@@ -117,8 +117,8 @@ static struct iwl_lib_ops iwl1000_lib = { | |||
117 | EEPROM_5000_REG_BAND_3_CHANNELS, | 117 | EEPROM_5000_REG_BAND_3_CHANNELS, |
118 | EEPROM_5000_REG_BAND_4_CHANNELS, | 118 | EEPROM_5000_REG_BAND_4_CHANNELS, |
119 | EEPROM_5000_REG_BAND_5_CHANNELS, | 119 | EEPROM_5000_REG_BAND_5_CHANNELS, |
120 | EEPROM_5000_REG_BAND_24_FAT_CHANNELS, | 120 | EEPROM_5000_REG_BAND_24_HT40_CHANNELS, |
121 | EEPROM_5000_REG_BAND_52_FAT_CHANNELS | 121 | EEPROM_5000_REG_BAND_52_HT40_CHANNELS |
122 | }, | 122 | }, |
123 | .verify_signature = iwlcore_eeprom_verify_signature, | 123 | .verify_signature = iwlcore_eeprom_verify_signature, |
124 | .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, | 124 | .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index b569c6f38e5c..16772780c5b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h | |||
@@ -176,7 +176,7 @@ struct iwl3945_eeprom { | |||
176 | * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory | 176 | * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory |
177 | * txpower (MSB). | 177 | * txpower (MSB). |
178 | * | 178 | * |
179 | * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) | 179 | * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) |
180 | * channels (only for 4965, not supported by 3945) appear later in the EEPROM. | 180 | * channels (only for 4965, not supported by 3945) appear later in the EEPROM. |
181 | * | 181 | * |
182 | * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 | 182 | * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index e1b0ef3c56a3..ba5ef832d770 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -502,14 +502,14 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv, | |||
502 | } | 502 | } |
503 | } | 503 | } |
504 | if (print_dump) | 504 | if (print_dump) |
505 | iwl_print_hex_dump(IWL_DL_RX, data, length); | 505 | iwl_print_hex_dump(priv, IWL_DL_RX, data, length); |
506 | } | 506 | } |
507 | 507 | ||
508 | static void iwl3945_dbg_report_frame(struct iwl_priv *priv, | 508 | static void iwl3945_dbg_report_frame(struct iwl_priv *priv, |
509 | struct iwl_rx_packet *pkt, | 509 | struct iwl_rx_packet *pkt, |
510 | struct ieee80211_hdr *header, int group100) | 510 | struct ieee80211_hdr *header, int group100) |
511 | { | 511 | { |
512 | if (iwl_debug_level & IWL_DL_RX) | 512 | if (iwl_get_debug_level(priv) & IWL_DL_RX) |
513 | _iwl3945_dbg_report_frame(priv, pkt, header, group100); | 513 | _iwl3945_dbg_report_frame(priv, pkt, header, group100); |
514 | } | 514 | } |
515 | 515 | ||
@@ -544,9 +544,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
544 | struct ieee80211_rx_status *stats) | 544 | struct ieee80211_rx_status *stats) |
545 | { | 545 | { |
546 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | 546 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; |
547 | #ifdef CONFIG_IWLWIFI_LEDS | ||
548 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); | 547 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); |
549 | #endif | ||
550 | struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); | 548 | struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); |
551 | struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); | 549 | struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); |
552 | short len = le16_to_cpu(rx_hdr->len); | 550 | short len = le16_to_cpu(rx_hdr->len); |
@@ -577,6 +575,8 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
577 | if (ieee80211_is_data(hdr->frame_control)) | 575 | if (ieee80211_is_data(hdr->frame_control)) |
578 | priv->rxtxpackets += len; | 576 | priv->rxtxpackets += len; |
579 | #endif | 577 | #endif |
578 | iwl_update_stats(priv, false, hdr->frame_control, len); | ||
579 | |||
580 | memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); | 580 | memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); |
581 | ieee80211_rx_irqsafe(priv->hw, rxb->skb); | 581 | ieee80211_rx_irqsafe(priv->hw, rxb->skb); |
582 | rxb->skb = NULL; | 582 | rxb->skb = NULL; |
@@ -679,6 +679,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, | |||
679 | 679 | ||
680 | /* Set "1" to report good data frames in groups of 100 */ | 680 | /* Set "1" to report good data frames in groups of 100 */ |
681 | iwl3945_dbg_report_frame(priv, pkt, header, 1); | 681 | iwl3945_dbg_report_frame(priv, pkt, header, 1); |
682 | iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header); | ||
682 | 683 | ||
683 | if (network_packet) { | 684 | if (network_packet) { |
684 | priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); | 685 | priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); |
@@ -2851,8 +2852,8 @@ static struct iwl_lib_ops iwl3945_lib = { | |||
2851 | EEPROM_REGULATORY_BAND_3_CHANNELS, | 2852 | EEPROM_REGULATORY_BAND_3_CHANNELS, |
2852 | EEPROM_REGULATORY_BAND_4_CHANNELS, | 2853 | EEPROM_REGULATORY_BAND_4_CHANNELS, |
2853 | EEPROM_REGULATORY_BAND_5_CHANNELS, | 2854 | EEPROM_REGULATORY_BAND_5_CHANNELS, |
2854 | EEPROM_REGULATORY_BAND_NO_FAT, | 2855 | EEPROM_REGULATORY_BAND_NO_HT40, |
2855 | EEPROM_REGULATORY_BAND_NO_FAT, | 2856 | EEPROM_REGULATORY_BAND_NO_HT40, |
2856 | }, | 2857 | }, |
2857 | .verify_signature = iwlcore_eeprom_verify_signature, | 2858 | .verify_signature = iwlcore_eeprom_verify_signature, |
2858 | .acquire_semaphore = iwl3945_eeprom_acquire_semaphore, | 2859 | .acquire_semaphore = iwl3945_eeprom_acquire_semaphore, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index a71a489096ff..b34322a32458 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h | |||
@@ -188,7 +188,7 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) | |||
188 | * | 188 | * |
189 | * 1) Regulatory information (max txpower and channel usage flags) is provided | 189 | * 1) Regulatory information (max txpower and channel usage flags) is provided |
190 | * separately for each channel that can possibly supported by 4965. | 190 | * separately for each channel that can possibly supported by 4965. |
191 | * 40 MHz wide (.11n fat) channels are listed separately from 20 MHz | 191 | * 40 MHz wide (.11n HT40) channels are listed separately from 20 MHz |
192 | * (legacy) channels. | 192 | * (legacy) channels. |
193 | * | 193 | * |
194 | * See struct iwl4965_eeprom_channel for format, and struct iwl4965_eeprom | 194 | * See struct iwl4965_eeprom_channel for format, and struct iwl4965_eeprom |
@@ -251,8 +251,8 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) | |||
251 | * no reduction (such as with regulatory txpower limits) is required. | 251 | * no reduction (such as with regulatory txpower limits) is required. |
252 | * | 252 | * |
253 | * Saturation and Backoff values apply equally to 20 Mhz (legacy) channel | 253 | * Saturation and Backoff values apply equally to 20 Mhz (legacy) channel |
254 | * widths and 40 Mhz (.11n fat) channel widths; there is no separate | 254 | * widths and 40 Mhz (.11n HT40) channel widths; there is no separate |
255 | * factory measurement for fat channels. | 255 | * factory measurement for ht40 channels. |
256 | * | 256 | * |
257 | * The result of this step is the final target txpower. The rest of | 257 | * The result of this step is the final target txpower. The rest of |
258 | * the steps figure out the proper settings for the device to achieve | 258 | * the steps figure out the proper settings for the device to achieve |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 670214823cb9..e427a8937ed8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -46,7 +46,7 @@ | |||
46 | #include "iwl-sta.h" | 46 | #include "iwl-sta.h" |
47 | 47 | ||
48 | static int iwl4965_send_tx_power(struct iwl_priv *priv); | 48 | static int iwl4965_send_tx_power(struct iwl_priv *priv); |
49 | static int iwl4965_hw_get_temperature(const struct iwl_priv *priv); | 49 | static int iwl4965_hw_get_temperature(struct iwl_priv *priv); |
50 | 50 | ||
51 | /* Highest firmware API version supported */ | 51 | /* Highest firmware API version supported */ |
52 | #define IWL4965_UCODE_API_MAX 2 | 52 | #define IWL4965_UCODE_API_MAX 2 |
@@ -146,7 +146,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) | |||
146 | 146 | ||
147 | IWL_DEBUG_INFO(priv, "Begin load bsm\n"); | 147 | IWL_DEBUG_INFO(priv, "Begin load bsm\n"); |
148 | 148 | ||
149 | priv->ucode_type = UCODE_INIT; | 149 | priv->ucode_type = UCODE_RT; |
150 | 150 | ||
151 | /* make sure bootstrap program is no larger than BSM's SRAM size */ | 151 | /* make sure bootstrap program is no larger than BSM's SRAM size */ |
152 | if (len > IWL49_MAX_BSM_SIZE) | 152 | if (len > IWL49_MAX_BSM_SIZE) |
@@ -256,8 +256,6 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) | |||
256 | */ | 256 | */ |
257 | static void iwl4965_init_alive_start(struct iwl_priv *priv) | 257 | static void iwl4965_init_alive_start(struct iwl_priv *priv) |
258 | { | 258 | { |
259 | int ret; | ||
260 | |||
261 | /* Check alive response for "valid" sign from uCode */ | 259 | /* Check alive response for "valid" sign from uCode */ |
262 | if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { | 260 | if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { |
263 | /* We had an error bringing up the hardware, so take it | 261 | /* We had an error bringing up the hardware, so take it |
@@ -289,35 +287,13 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv) | |||
289 | IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n"); | 287 | IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n"); |
290 | goto restart; | 288 | goto restart; |
291 | } | 289 | } |
292 | priv->ucode_type = UCODE_RT; | ||
293 | if (test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) { | ||
294 | IWL_WARN(priv, "Runtime uCode already alive? " | ||
295 | "Waiting for alive anyway\n"); | ||
296 | clear_bit(STATUS_RT_UCODE_ALIVE, &priv->status); | ||
297 | } | ||
298 | ret = wait_event_interruptible_timeout( | ||
299 | priv->wait_command_queue, | ||
300 | test_bit(STATUS_RT_UCODE_ALIVE, &priv->status), | ||
301 | UCODE_ALIVE_TIMEOUT); | ||
302 | if (!ret) { | ||
303 | /* FIXME: if STATUS_RT_UCODE_ALIVE timeout | ||
304 | * go back to restart the download Init uCode again | ||
305 | * this might cause to trap in the restart loop | ||
306 | */ | ||
307 | priv->ucode_type = UCODE_NONE; | ||
308 | if (!test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) { | ||
309 | IWL_ERR(priv, "Runtime timeout after %dms\n", | ||
310 | jiffies_to_msecs(UCODE_ALIVE_TIMEOUT)); | ||
311 | goto restart; | ||
312 | } | ||
313 | } | ||
314 | return; | 290 | return; |
315 | 291 | ||
316 | restart: | 292 | restart: |
317 | queue_work(priv->workqueue, &priv->restart); | 293 | queue_work(priv->workqueue, &priv->restart); |
318 | } | 294 | } |
319 | 295 | ||
320 | static bool is_fat_channel(__le32 rxon_flags) | 296 | static bool is_ht40_channel(__le32 rxon_flags) |
321 | { | 297 | { |
322 | int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK) | 298 | int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK) |
323 | >> RXON_FLG_CHANNEL_MODE_POS; | 299 | >> RXON_FLG_CHANNEL_MODE_POS; |
@@ -806,7 +782,7 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) | |||
806 | priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; | 782 | priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; |
807 | priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE; | 783 | priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE; |
808 | priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; | 784 | priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; |
809 | priv->hw_params.fat_channel = BIT(IEEE80211_BAND_5GHZ); | 785 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_5GHZ); |
810 | 786 | ||
811 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; | 787 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; |
812 | 788 | ||
@@ -1266,7 +1242,7 @@ static const struct gain_entry gain_table[2][108] = { | |||
1266 | }; | 1242 | }; |
1267 | 1243 | ||
1268 | static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, | 1244 | static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, |
1269 | u8 is_fat, u8 ctrl_chan_high, | 1245 | u8 is_ht40, u8 ctrl_chan_high, |
1270 | struct iwl4965_tx_power_db *tx_power_tbl) | 1246 | struct iwl4965_tx_power_db *tx_power_tbl) |
1271 | { | 1247 | { |
1272 | u8 saturation_power; | 1248 | u8 saturation_power; |
@@ -1298,8 +1274,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, | |||
1298 | user_target_power = 2 * priv->tx_power_user_lmt; | 1274 | user_target_power = 2 * priv->tx_power_user_lmt; |
1299 | 1275 | ||
1300 | /* Get current (RXON) channel, band, width */ | 1276 | /* Get current (RXON) channel, band, width */ |
1301 | IWL_DEBUG_TXPOWER(priv, "chan %d band %d is_fat %d\n", channel, band, | 1277 | IWL_DEBUG_TXPOWER(priv, "chan %d band %d is_ht40 %d\n", channel, band, |
1302 | is_fat); | 1278 | is_ht40); |
1303 | 1279 | ||
1304 | ch_info = iwl_get_channel_info(priv, priv->band, channel); | 1280 | ch_info = iwl_get_channel_info(priv, priv->band, channel); |
1305 | 1281 | ||
@@ -1318,7 +1294,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, | |||
1318 | IWL_DEBUG_TXPOWER(priv, "channel %d belongs to txatten group %d\n", | 1294 | IWL_DEBUG_TXPOWER(priv, "channel %d belongs to txatten group %d\n", |
1319 | channel, txatten_grp); | 1295 | channel, txatten_grp); |
1320 | 1296 | ||
1321 | if (is_fat) { | 1297 | if (is_ht40) { |
1322 | if (ctrl_chan_high) | 1298 | if (ctrl_chan_high) |
1323 | channel -= 2; | 1299 | channel -= 2; |
1324 | else | 1300 | else |
@@ -1342,8 +1318,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, | |||
1342 | 1318 | ||
1343 | /* regulatory txpower limits ... reg_limit values are in half-dBm, | 1319 | /* regulatory txpower limits ... reg_limit values are in half-dBm, |
1344 | * max_power_avg values are in dBm, convert * 2 */ | 1320 | * max_power_avg values are in dBm, convert * 2 */ |
1345 | if (is_fat) | 1321 | if (is_ht40) |
1346 | reg_limit = ch_info->fat_max_power_avg * 2; | 1322 | reg_limit = ch_info->ht40_max_power_avg * 2; |
1347 | else | 1323 | else |
1348 | reg_limit = ch_info->max_power_avg * 2; | 1324 | reg_limit = ch_info->max_power_avg * 2; |
1349 | 1325 | ||
@@ -1509,7 +1485,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, | |||
1509 | /** | 1485 | /** |
1510 | * iwl4965_send_tx_power - Configure the TXPOWER level user limit | 1486 | * iwl4965_send_tx_power - Configure the TXPOWER level user limit |
1511 | * | 1487 | * |
1512 | * Uses the active RXON for channel, band, and characteristics (fat, high) | 1488 | * Uses the active RXON for channel, band, and characteristics (ht40, high) |
1513 | * The power limit is taken from priv->tx_power_user_lmt. | 1489 | * The power limit is taken from priv->tx_power_user_lmt. |
1514 | */ | 1490 | */ |
1515 | static int iwl4965_send_tx_power(struct iwl_priv *priv) | 1491 | static int iwl4965_send_tx_power(struct iwl_priv *priv) |
@@ -1517,7 +1493,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) | |||
1517 | struct iwl4965_txpowertable_cmd cmd = { 0 }; | 1493 | struct iwl4965_txpowertable_cmd cmd = { 0 }; |
1518 | int ret; | 1494 | int ret; |
1519 | u8 band = 0; | 1495 | u8 band = 0; |
1520 | bool is_fat = false; | 1496 | bool is_ht40 = false; |
1521 | u8 ctrl_chan_high = 0; | 1497 | u8 ctrl_chan_high = 0; |
1522 | 1498 | ||
1523 | if (test_bit(STATUS_SCANNING, &priv->status)) { | 1499 | if (test_bit(STATUS_SCANNING, &priv->status)) { |
@@ -1530,9 +1506,9 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) | |||
1530 | 1506 | ||
1531 | band = priv->band == IEEE80211_BAND_2GHZ; | 1507 | band = priv->band == IEEE80211_BAND_2GHZ; |
1532 | 1508 | ||
1533 | is_fat = is_fat_channel(priv->active_rxon.flags); | 1509 | is_ht40 = is_ht40_channel(priv->active_rxon.flags); |
1534 | 1510 | ||
1535 | if (is_fat && | 1511 | if (is_ht40 && |
1536 | (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) | 1512 | (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) |
1537 | ctrl_chan_high = 1; | 1513 | ctrl_chan_high = 1; |
1538 | 1514 | ||
@@ -1541,7 +1517,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) | |||
1541 | 1517 | ||
1542 | ret = iwl4965_fill_txpower_tbl(priv, band, | 1518 | ret = iwl4965_fill_txpower_tbl(priv, band, |
1543 | le16_to_cpu(priv->active_rxon.channel), | 1519 | le16_to_cpu(priv->active_rxon.channel), |
1544 | is_fat, ctrl_chan_high, &cmd.tx_power); | 1520 | is_ht40, ctrl_chan_high, &cmd.tx_power); |
1545 | if (ret) | 1521 | if (ret) |
1546 | goto out; | 1522 | goto out; |
1547 | 1523 | ||
@@ -1595,7 +1571,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) | |||
1595 | { | 1571 | { |
1596 | int rc; | 1572 | int rc; |
1597 | u8 band = 0; | 1573 | u8 band = 0; |
1598 | bool is_fat = false; | 1574 | bool is_ht40 = false; |
1599 | u8 ctrl_chan_high = 0; | 1575 | u8 ctrl_chan_high = 0; |
1600 | struct iwl4965_channel_switch_cmd cmd = { 0 }; | 1576 | struct iwl4965_channel_switch_cmd cmd = { 0 }; |
1601 | const struct iwl_channel_info *ch_info; | 1577 | const struct iwl_channel_info *ch_info; |
@@ -1604,9 +1580,9 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) | |||
1604 | 1580 | ||
1605 | ch_info = iwl_get_channel_info(priv, priv->band, channel); | 1581 | ch_info = iwl_get_channel_info(priv, priv->band, channel); |
1606 | 1582 | ||
1607 | is_fat = is_fat_channel(priv->staging_rxon.flags); | 1583 | is_ht40 = is_ht40_channel(priv->staging_rxon.flags); |
1608 | 1584 | ||
1609 | if (is_fat && | 1585 | if (is_ht40 && |
1610 | (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) | 1586 | (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) |
1611 | ctrl_chan_high = 1; | 1587 | ctrl_chan_high = 1; |
1612 | 1588 | ||
@@ -1621,7 +1597,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) | |||
1621 | else | 1597 | else |
1622 | cmd.expect_beacon = 1; | 1598 | cmd.expect_beacon = 1; |
1623 | 1599 | ||
1624 | rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_fat, | 1600 | rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40, |
1625 | ctrl_chan_high, &cmd.tx_power); | 1601 | ctrl_chan_high, &cmd.tx_power); |
1626 | if (rc) { | 1602 | if (rc) { |
1627 | IWL_DEBUG_11H(priv, "error:%d fill txpower_tbl\n", rc); | 1603 | IWL_DEBUG_11H(priv, "error:%d fill txpower_tbl\n", rc); |
@@ -1680,7 +1656,7 @@ static s32 sign_extend(u32 oper, int index) | |||
1680 | * | 1656 | * |
1681 | * A return of <0 indicates bogus data in the statistics | 1657 | * A return of <0 indicates bogus data in the statistics |
1682 | */ | 1658 | */ |
1683 | static int iwl4965_hw_get_temperature(const struct iwl_priv *priv) | 1659 | static int iwl4965_hw_get_temperature(struct iwl_priv *priv) |
1684 | { | 1660 | { |
1685 | s32 temperature; | 1661 | s32 temperature; |
1686 | s32 vt; | 1662 | s32 vt; |
@@ -1688,8 +1664,8 @@ static int iwl4965_hw_get_temperature(const struct iwl_priv *priv) | |||
1688 | u32 R4; | 1664 | u32 R4; |
1689 | 1665 | ||
1690 | if (test_bit(STATUS_TEMPERATURE, &priv->status) && | 1666 | if (test_bit(STATUS_TEMPERATURE, &priv->status) && |
1691 | (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)) { | 1667 | (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)) { |
1692 | IWL_DEBUG_TEMP(priv, "Running FAT temperature calibration\n"); | 1668 | IWL_DEBUG_TEMP(priv, "Running HT40 temperature calibration\n"); |
1693 | R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]); | 1669 | R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]); |
1694 | R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]); | 1670 | R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]); |
1695 | R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]); | 1671 | R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]); |
@@ -2330,8 +2306,8 @@ static struct iwl_lib_ops iwl4965_lib = { | |||
2330 | EEPROM_REGULATORY_BAND_3_CHANNELS, | 2306 | EEPROM_REGULATORY_BAND_3_CHANNELS, |
2331 | EEPROM_REGULATORY_BAND_4_CHANNELS, | 2307 | EEPROM_REGULATORY_BAND_4_CHANNELS, |
2332 | EEPROM_REGULATORY_BAND_5_CHANNELS, | 2308 | EEPROM_REGULATORY_BAND_5_CHANNELS, |
2333 | EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS, | 2309 | EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS, |
2334 | EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS | 2310 | EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS |
2335 | }, | 2311 | }, |
2336 | .verify_signature = iwlcore_eeprom_verify_signature, | 2312 | .verify_signature = iwlcore_eeprom_verify_signature, |
2337 | .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, | 2313 | .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 87957c052839..755c184b3ecb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -845,7 +845,7 @@ int iwl5000_hw_set_hw_params(struct iwl_priv *priv) | |||
845 | } | 845 | } |
846 | 846 | ||
847 | priv->hw_params.max_bsm_size = 0; | 847 | priv->hw_params.max_bsm_size = 0; |
848 | priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) | | 848 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | |
849 | BIT(IEEE80211_BAND_5GHZ); | 849 | BIT(IEEE80211_BAND_5GHZ); |
850 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; | 850 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; |
851 | 851 | ||
@@ -1547,8 +1547,8 @@ struct iwl_lib_ops iwl5000_lib = { | |||
1547 | EEPROM_5000_REG_BAND_3_CHANNELS, | 1547 | EEPROM_5000_REG_BAND_3_CHANNELS, |
1548 | EEPROM_5000_REG_BAND_4_CHANNELS, | 1548 | EEPROM_5000_REG_BAND_4_CHANNELS, |
1549 | EEPROM_5000_REG_BAND_5_CHANNELS, | 1549 | EEPROM_5000_REG_BAND_5_CHANNELS, |
1550 | EEPROM_5000_REG_BAND_24_FAT_CHANNELS, | 1550 | EEPROM_5000_REG_BAND_24_HT40_CHANNELS, |
1551 | EEPROM_5000_REG_BAND_52_FAT_CHANNELS | 1551 | EEPROM_5000_REG_BAND_52_HT40_CHANNELS |
1552 | }, | 1552 | }, |
1553 | .verify_signature = iwlcore_eeprom_verify_signature, | 1553 | .verify_signature = iwlcore_eeprom_verify_signature, |
1554 | .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, | 1554 | .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, |
@@ -1597,8 +1597,8 @@ static struct iwl_lib_ops iwl5150_lib = { | |||
1597 | EEPROM_5000_REG_BAND_3_CHANNELS, | 1597 | EEPROM_5000_REG_BAND_3_CHANNELS, |
1598 | EEPROM_5000_REG_BAND_4_CHANNELS, | 1598 | EEPROM_5000_REG_BAND_4_CHANNELS, |
1599 | EEPROM_5000_REG_BAND_5_CHANNELS, | 1599 | EEPROM_5000_REG_BAND_5_CHANNELS, |
1600 | EEPROM_5000_REG_BAND_24_FAT_CHANNELS, | 1600 | EEPROM_5000_REG_BAND_24_HT40_CHANNELS, |
1601 | EEPROM_5000_REG_BAND_52_FAT_CHANNELS | 1601 | EEPROM_5000_REG_BAND_52_HT40_CHANNELS |
1602 | }, | 1602 | }, |
1603 | .verify_signature = iwlcore_eeprom_verify_signature, | 1603 | .verify_signature = iwlcore_eeprom_verify_signature, |
1604 | .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, | 1604 | .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 4450943d3dac..c3ec6c20cc94 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c | |||
@@ -118,8 +118,8 @@ static struct iwl_lib_ops iwl6000_lib = { | |||
118 | EEPROM_5000_REG_BAND_3_CHANNELS, | 118 | EEPROM_5000_REG_BAND_3_CHANNELS, |
119 | EEPROM_5000_REG_BAND_4_CHANNELS, | 119 | EEPROM_5000_REG_BAND_4_CHANNELS, |
120 | EEPROM_5000_REG_BAND_5_CHANNELS, | 120 | EEPROM_5000_REG_BAND_5_CHANNELS, |
121 | EEPROM_5000_REG_BAND_24_FAT_CHANNELS, | 121 | EEPROM_5000_REG_BAND_24_HT40_CHANNELS, |
122 | EEPROM_5000_REG_BAND_52_FAT_CHANNELS | 122 | EEPROM_5000_REG_BAND_52_HT40_CHANNELS |
123 | }, | 123 | }, |
124 | .verify_signature = iwlcore_eeprom_verify_signature, | 124 | .verify_signature = iwlcore_eeprom_verify_signature, |
125 | .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, | 125 | .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 52a4810274e9..21331552ff2c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c | |||
@@ -97,7 +97,7 @@ struct iwl_scale_tbl_info { | |||
97 | enum iwl_table_type lq_type; | 97 | enum iwl_table_type lq_type; |
98 | u8 ant_type; | 98 | u8 ant_type; |
99 | u8 is_SGI; /* 1 = short guard interval */ | 99 | u8 is_SGI; /* 1 = short guard interval */ |
100 | u8 is_fat; /* 1 = 40 MHz channel width */ | 100 | u8 is_ht40; /* 1 = 40 MHz channel width */ |
101 | u8 is_dup; /* 1 = duplicated data streams */ | 101 | u8 is_dup; /* 1 = duplicated data streams */ |
102 | u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ | 102 | u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ |
103 | u8 max_search; /* maximun number of tables we can search */ | 103 | u8 max_search; /* maximun number of tables we can search */ |
@@ -539,11 +539,11 @@ static u32 rate_n_flags_from_tbl(struct iwl_priv *priv, | |||
539 | RATE_MCS_ANT_ABC_MSK); | 539 | RATE_MCS_ANT_ABC_MSK); |
540 | 540 | ||
541 | if (is_Ht(tbl->lq_type)) { | 541 | if (is_Ht(tbl->lq_type)) { |
542 | if (tbl->is_fat) { | 542 | if (tbl->is_ht40) { |
543 | if (tbl->is_dup) | 543 | if (tbl->is_dup) |
544 | rate_n_flags |= RATE_MCS_DUP_MSK; | 544 | rate_n_flags |= RATE_MCS_DUP_MSK; |
545 | else | 545 | else |
546 | rate_n_flags |= RATE_MCS_FAT_MSK; | 546 | rate_n_flags |= RATE_MCS_HT40_MSK; |
547 | } | 547 | } |
548 | if (tbl->is_SGI) | 548 | if (tbl->is_SGI) |
549 | rate_n_flags |= RATE_MCS_SGI_MSK; | 549 | rate_n_flags |= RATE_MCS_SGI_MSK; |
@@ -579,7 +579,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, | |||
579 | return -EINVAL; | 579 | return -EINVAL; |
580 | } | 580 | } |
581 | tbl->is_SGI = 0; /* default legacy setup */ | 581 | tbl->is_SGI = 0; /* default legacy setup */ |
582 | tbl->is_fat = 0; | 582 | tbl->is_ht40 = 0; |
583 | tbl->is_dup = 0; | 583 | tbl->is_dup = 0; |
584 | tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); | 584 | tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); |
585 | tbl->lq_type = LQ_NONE; | 585 | tbl->lq_type = LQ_NONE; |
@@ -598,9 +598,9 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, | |||
598 | if (rate_n_flags & RATE_MCS_SGI_MSK) | 598 | if (rate_n_flags & RATE_MCS_SGI_MSK) |
599 | tbl->is_SGI = 1; | 599 | tbl->is_SGI = 1; |
600 | 600 | ||
601 | if ((rate_n_flags & RATE_MCS_FAT_MSK) || | 601 | if ((rate_n_flags & RATE_MCS_HT40_MSK) || |
602 | (rate_n_flags & RATE_MCS_DUP_MSK)) | 602 | (rate_n_flags & RATE_MCS_DUP_MSK)) |
603 | tbl->is_fat = 1; | 603 | tbl->is_ht40 = 1; |
604 | 604 | ||
605 | if (rate_n_flags & RATE_MCS_DUP_MSK) | 605 | if (rate_n_flags & RATE_MCS_DUP_MSK) |
606 | tbl->is_dup = 1; | 606 | tbl->is_dup = 1; |
@@ -776,7 +776,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, | |||
776 | if (num_of_ant(tbl->ant_type) > 1) | 776 | if (num_of_ant(tbl->ant_type) > 1) |
777 | tbl->ant_type = ANT_A;/*FIXME:RS*/ | 777 | tbl->ant_type = ANT_A;/*FIXME:RS*/ |
778 | 778 | ||
779 | tbl->is_fat = 0; | 779 | tbl->is_ht40 = 0; |
780 | tbl->is_SGI = 0; | 780 | tbl->is_SGI = 0; |
781 | tbl->max_search = IWL_MAX_SEARCH; | 781 | tbl->max_search = IWL_MAX_SEARCH; |
782 | } | 782 | } |
@@ -880,7 +880,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, | |||
880 | 880 | ||
881 | if ((info->status.rates[0].idx < 0) || | 881 | if ((info->status.rates[0].idx < 0) || |
882 | (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) || | 882 | (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) || |
883 | (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || | 883 | (tbl_type.is_ht40 != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || |
884 | (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) || | 884 | (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) || |
885 | (tbl_type.ant_type != info->antenna_sel_tx) || | 885 | (tbl_type.ant_type != info->antenna_sel_tx) || |
886 | (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) || | 886 | (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) || |
@@ -1049,7 +1049,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | |||
1049 | else | 1049 | else |
1050 | tbl->expected_tpt = expected_tpt_A; | 1050 | tbl->expected_tpt = expected_tpt_A; |
1051 | } else if (is_siso(tbl->lq_type)) { | 1051 | } else if (is_siso(tbl->lq_type)) { |
1052 | if (tbl->is_fat && !lq_sta->is_dup) | 1052 | if (tbl->is_ht40 && !lq_sta->is_dup) |
1053 | if (tbl->is_SGI) | 1053 | if (tbl->is_SGI) |
1054 | tbl->expected_tpt = expected_tpt_siso40MHzSGI; | 1054 | tbl->expected_tpt = expected_tpt_siso40MHzSGI; |
1055 | else | 1055 | else |
@@ -1059,7 +1059,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | |||
1059 | else | 1059 | else |
1060 | tbl->expected_tpt = expected_tpt_siso20MHz; | 1060 | tbl->expected_tpt = expected_tpt_siso20MHz; |
1061 | } else if (is_mimo2(tbl->lq_type)) { | 1061 | } else if (is_mimo2(tbl->lq_type)) { |
1062 | if (tbl->is_fat && !lq_sta->is_dup) | 1062 | if (tbl->is_ht40 && !lq_sta->is_dup) |
1063 | if (tbl->is_SGI) | 1063 | if (tbl->is_SGI) |
1064 | tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI; | 1064 | tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI; |
1065 | else | 1065 | else |
@@ -1069,7 +1069,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | |||
1069 | else | 1069 | else |
1070 | tbl->expected_tpt = expected_tpt_mimo2_20MHz; | 1070 | tbl->expected_tpt = expected_tpt_mimo2_20MHz; |
1071 | } else if (is_mimo3(tbl->lq_type)) { | 1071 | } else if (is_mimo3(tbl->lq_type)) { |
1072 | if (tbl->is_fat && !lq_sta->is_dup) | 1072 | if (tbl->is_ht40 && !lq_sta->is_dup) |
1073 | if (tbl->is_SGI) | 1073 | if (tbl->is_SGI) |
1074 | tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI; | 1074 | tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI; |
1075 | else | 1075 | else |
@@ -1217,13 +1217,13 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, | |||
1217 | tbl->max_search = IWL_MAX_SEARCH; | 1217 | tbl->max_search = IWL_MAX_SEARCH; |
1218 | rate_mask = lq_sta->active_mimo2_rate; | 1218 | rate_mask = lq_sta->active_mimo2_rate; |
1219 | 1219 | ||
1220 | if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) | 1220 | if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap)) |
1221 | tbl->is_fat = 1; | 1221 | tbl->is_ht40 = 1; |
1222 | else | 1222 | else |
1223 | tbl->is_fat = 0; | 1223 | tbl->is_ht40 = 0; |
1224 | 1224 | ||
1225 | /* FIXME: - don't toggle SGI here | 1225 | /* FIXME: - don't toggle SGI here |
1226 | if (tbl->is_fat) { | 1226 | if (tbl->is_ht40) { |
1227 | if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) | 1227 | if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) |
1228 | tbl->is_SGI = 1; | 1228 | tbl->is_SGI = 1; |
1229 | else | 1229 | else |
@@ -1283,13 +1283,13 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, | |||
1283 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | 1283 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; |
1284 | rate_mask = lq_sta->active_mimo3_rate; | 1284 | rate_mask = lq_sta->active_mimo3_rate; |
1285 | 1285 | ||
1286 | if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) | 1286 | if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap)) |
1287 | tbl->is_fat = 1; | 1287 | tbl->is_ht40 = 1; |
1288 | else | 1288 | else |
1289 | tbl->is_fat = 0; | 1289 | tbl->is_ht40 = 0; |
1290 | 1290 | ||
1291 | /* FIXME: - don't toggle SGI here | 1291 | /* FIXME: - don't toggle SGI here |
1292 | if (tbl->is_fat) { | 1292 | if (tbl->is_ht40) { |
1293 | if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) | 1293 | if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) |
1294 | tbl->is_SGI = 1; | 1294 | tbl->is_SGI = 1; |
1295 | else | 1295 | else |
@@ -1342,13 +1342,13 @@ static int rs_switch_to_siso(struct iwl_priv *priv, | |||
1342 | tbl->max_search = IWL_MAX_SEARCH; | 1342 | tbl->max_search = IWL_MAX_SEARCH; |
1343 | rate_mask = lq_sta->active_siso_rate; | 1343 | rate_mask = lq_sta->active_siso_rate; |
1344 | 1344 | ||
1345 | if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) | 1345 | if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap)) |
1346 | tbl->is_fat = 1; | 1346 | tbl->is_ht40 = 1; |
1347 | else | 1347 | else |
1348 | tbl->is_fat = 0; | 1348 | tbl->is_ht40 = 0; |
1349 | 1349 | ||
1350 | /* FIXME: - don't toggle SGI here | 1350 | /* FIXME: - don't toggle SGI here |
1351 | if (tbl->is_fat) { | 1351 | if (tbl->is_ht40) { |
1352 | if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) | 1352 | if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) |
1353 | tbl->is_SGI = 1; | 1353 | tbl->is_SGI = 1; |
1354 | else | 1354 | else |
@@ -1401,7 +1401,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, | |||
1401 | if (!iwl_ht_enabled(priv)) | 1401 | if (!iwl_ht_enabled(priv)) |
1402 | /* stay in Legacy */ | 1402 | /* stay in Legacy */ |
1403 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; | 1403 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; |
1404 | else if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && | 1404 | else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE && |
1405 | tbl->action > IWL_LEGACY_SWITCH_SISO) | 1405 | tbl->action > IWL_LEGACY_SWITCH_SISO) |
1406 | tbl->action = IWL_LEGACY_SWITCH_SISO; | 1406 | tbl->action = IWL_LEGACY_SWITCH_SISO; |
1407 | for (; ;) { | 1407 | for (; ;) { |
@@ -1535,7 +1535,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, | |||
1535 | u8 update_search_tbl_counter = 0; | 1535 | u8 update_search_tbl_counter = 0; |
1536 | int ret; | 1536 | int ret; |
1537 | 1537 | ||
1538 | if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && | 1538 | if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE && |
1539 | tbl->action > IWL_SISO_SWITCH_ANTENNA2) { | 1539 | tbl->action > IWL_SISO_SWITCH_ANTENNA2) { |
1540 | /* stay in SISO */ | 1540 | /* stay in SISO */ |
1541 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; | 1541 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; |
@@ -1586,11 +1586,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, | |||
1586 | goto out; | 1586 | goto out; |
1587 | break; | 1587 | break; |
1588 | case IWL_SISO_SWITCH_GI: | 1588 | case IWL_SISO_SWITCH_GI: |
1589 | if (!tbl->is_fat && | 1589 | if (!tbl->is_ht40 && |
1590 | !(priv->current_ht_config.sgf & | 1590 | !(priv->current_ht_config.sgf & |
1591 | HT_SHORT_GI_20MHZ)) | 1591 | HT_SHORT_GI_20MHZ)) |
1592 | break; | 1592 | break; |
1593 | if (tbl->is_fat && | 1593 | if (tbl->is_ht40 && |
1594 | !(priv->current_ht_config.sgf & | 1594 | !(priv->current_ht_config.sgf & |
1595 | HT_SHORT_GI_40MHZ)) | 1595 | HT_SHORT_GI_40MHZ)) |
1596 | break; | 1596 | break; |
@@ -1674,7 +1674,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, | |||
1674 | u8 update_search_tbl_counter = 0; | 1674 | u8 update_search_tbl_counter = 0; |
1675 | int ret; | 1675 | int ret; |
1676 | 1676 | ||
1677 | if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && | 1677 | if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) && |
1678 | (tbl->action < IWL_MIMO2_SWITCH_SISO_A || | 1678 | (tbl->action < IWL_MIMO2_SWITCH_SISO_A || |
1679 | tbl->action > IWL_MIMO2_SWITCH_SISO_C)) { | 1679 | tbl->action > IWL_MIMO2_SWITCH_SISO_C)) { |
1680 | /* switch in SISO */ | 1680 | /* switch in SISO */ |
@@ -1726,11 +1726,11 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, | |||
1726 | break; | 1726 | break; |
1727 | 1727 | ||
1728 | case IWL_MIMO2_SWITCH_GI: | 1728 | case IWL_MIMO2_SWITCH_GI: |
1729 | if (!tbl->is_fat && | 1729 | if (!tbl->is_ht40 && |
1730 | !(priv->current_ht_config.sgf & | 1730 | !(priv->current_ht_config.sgf & |
1731 | HT_SHORT_GI_20MHZ)) | 1731 | HT_SHORT_GI_20MHZ)) |
1732 | break; | 1732 | break; |
1733 | if (tbl->is_fat && | 1733 | if (tbl->is_ht40 && |
1734 | !(priv->current_ht_config.sgf & | 1734 | !(priv->current_ht_config.sgf & |
1735 | HT_SHORT_GI_40MHZ)) | 1735 | HT_SHORT_GI_40MHZ)) |
1736 | break; | 1736 | break; |
@@ -1816,7 +1816,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, | |||
1816 | int ret; | 1816 | int ret; |
1817 | u8 update_search_tbl_counter = 0; | 1817 | u8 update_search_tbl_counter = 0; |
1818 | 1818 | ||
1819 | if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && | 1819 | if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) && |
1820 | (tbl->action < IWL_MIMO3_SWITCH_SISO_A || | 1820 | (tbl->action < IWL_MIMO3_SWITCH_SISO_A || |
1821 | tbl->action > IWL_MIMO3_SWITCH_SISO_C)) { | 1821 | tbl->action > IWL_MIMO3_SWITCH_SISO_C)) { |
1822 | /* switch in SISO */ | 1822 | /* switch in SISO */ |
@@ -1890,11 +1890,11 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, | |||
1890 | break; | 1890 | break; |
1891 | 1891 | ||
1892 | case IWL_MIMO3_SWITCH_GI: | 1892 | case IWL_MIMO3_SWITCH_GI: |
1893 | if (!tbl->is_fat && | 1893 | if (!tbl->is_ht40 && |
1894 | !(priv->current_ht_config.sgf & | 1894 | !(priv->current_ht_config.sgf & |
1895 | HT_SHORT_GI_20MHZ)) | 1895 | HT_SHORT_GI_20MHZ)) |
1896 | break; | 1896 | break; |
1897 | if (tbl->is_fat && | 1897 | if (tbl->is_ht40 && |
1898 | !(priv->current_ht_config.sgf & | 1898 | !(priv->current_ht_config.sgf & |
1899 | HT_SHORT_GI_40MHZ)) | 1899 | HT_SHORT_GI_40MHZ)) |
1900 | break; | 1900 | break; |
@@ -2202,7 +2202,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, | |||
2202 | 2202 | ||
2203 | /* If we are searching for better modulation mode, check success. */ | 2203 | /* If we are searching for better modulation mode, check success. */ |
2204 | if (lq_sta->search_better_tbl && | 2204 | if (lq_sta->search_better_tbl && |
2205 | (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI)) { | 2205 | (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI)) { |
2206 | /* If good success, continue using the "search" mode; | 2206 | /* If good success, continue using the "search" mode; |
2207 | * no need to send new link quality command, since we're | 2207 | * no need to send new link quality command, since we're |
2208 | * continuing to use the setup that we've been trying. */ | 2208 | * continuing to use the setup that we've been trying. */ |
@@ -2332,7 +2332,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, | |||
2332 | scale_action = 0; | 2332 | scale_action = 0; |
2333 | if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type)) | 2333 | if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type)) |
2334 | scale_action = -1; | 2334 | scale_action = -1; |
2335 | if (iwl_tx_ant_restriction(priv) != IWL_TX_MULTI && | 2335 | if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI && |
2336 | (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) | 2336 | (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) |
2337 | scale_action = -1; | 2337 | scale_action = -1; |
2338 | switch (scale_action) { | 2338 | switch (scale_action) { |
@@ -2368,7 +2368,7 @@ lq_update: | |||
2368 | rate = rs_update_rate_tbl(priv, lq_sta, | 2368 | rate = rs_update_rate_tbl(priv, lq_sta, |
2369 | tbl, index, is_green); | 2369 | tbl, index, is_green); |
2370 | 2370 | ||
2371 | if (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI) { | 2371 | if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) { |
2372 | /* Should we stay with this modulation mode, | 2372 | /* Should we stay with this modulation mode, |
2373 | * or search for a new one? */ | 2373 | * or search for a new one? */ |
2374 | rs_stay_in_table(lq_sta); | 2374 | rs_stay_in_table(lq_sta); |
@@ -2576,7 +2576,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, | |||
2576 | info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI; | 2576 | info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI; |
2577 | if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK) | 2577 | if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK) |
2578 | info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA; | 2578 | info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA; |
2579 | if (lq_sta->last_rate_n_flags & RATE_MCS_FAT_MSK) | 2579 | if (lq_sta->last_rate_n_flags & RATE_MCS_HT40_MSK) |
2580 | info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | 2580 | info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; |
2581 | if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK) | 2581 | if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK) |
2582 | info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD; | 2582 | info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD; |
@@ -2963,7 +2963,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | |||
2963 | (is_siso(tbl->lq_type)) ? "SISO" : | 2963 | (is_siso(tbl->lq_type)) ? "SISO" : |
2964 | ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); | 2964 | ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); |
2965 | desc += sprintf(buff+desc, " %s", | 2965 | desc += sprintf(buff+desc, " %s", |
2966 | (tbl->is_fat) ? "40MHz" : "20MHz"); | 2966 | (tbl->is_ht40) ? "40MHz" : "20MHz"); |
2967 | desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "", | 2967 | desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "", |
2968 | (lq_sta->is_green) ? "GF enabled" : ""); | 2968 | (lq_sta->is_green) ? "GF enabled" : ""); |
2969 | } | 2969 | } |
@@ -3028,12 +3028,13 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, | |||
3028 | return -ENOMEM; | 3028 | return -ENOMEM; |
3029 | 3029 | ||
3030 | for (i = 0; i < LQ_SIZE; i++) { | 3030 | for (i = 0; i < LQ_SIZE; i++) { |
3031 | desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d GF=%d\n" | 3031 | desc += sprintf(buff+desc, |
3032 | "%s type=%d SGI=%d HT40=%d DUP=%d GF=%d\n" | ||
3032 | "rate=0x%X\n", | 3033 | "rate=0x%X\n", |
3033 | lq_sta->active_tbl == i ? "*" : "x", | 3034 | lq_sta->active_tbl == i ? "*" : "x", |
3034 | lq_sta->lq_info[i].lq_type, | 3035 | lq_sta->lq_info[i].lq_type, |
3035 | lq_sta->lq_info[i].is_SGI, | 3036 | lq_sta->lq_info[i].is_SGI, |
3036 | lq_sta->lq_info[i].is_fat, | 3037 | lq_sta->lq_info[i].is_ht40, |
3037 | lq_sta->lq_info[i].is_dup, | 3038 | lq_sta->lq_info[i].is_dup, |
3038 | lq_sta->is_green, | 3039 | lq_sta->is_green, |
3039 | lq_sta->lq_info[i].current_rate); | 3040 | lq_sta->lq_info[i].current_rate); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index db580cbf5982..2232b1794e76 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -533,16 +533,12 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, | |||
533 | 533 | ||
534 | if (palive->ver_subtype == INITIALIZE_SUBTYPE) { | 534 | if (palive->ver_subtype == INITIALIZE_SUBTYPE) { |
535 | IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); | 535 | IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); |
536 | set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status); | ||
537 | wake_up_interruptible(&priv->wait_command_queue); | ||
538 | memcpy(&priv->card_alive_init, | 536 | memcpy(&priv->card_alive_init, |
539 | &pkt->u.alive_frame, | 537 | &pkt->u.alive_frame, |
540 | sizeof(struct iwl_init_alive_resp)); | 538 | sizeof(struct iwl_init_alive_resp)); |
541 | pwork = &priv->init_alive_start; | 539 | pwork = &priv->init_alive_start; |
542 | } else { | 540 | } else { |
543 | IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); | 541 | IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); |
544 | set_bit(STATUS_RT_UCODE_ALIVE, &priv->status); | ||
545 | wake_up_interruptible(&priv->wait_command_queue); | ||
546 | memcpy(&priv->card_alive, &pkt->u.alive_frame, | 542 | memcpy(&priv->card_alive, &pkt->u.alive_frame, |
547 | sizeof(struct iwl_alive_resp)); | 543 | sizeof(struct iwl_alive_resp)); |
548 | pwork = &priv->alive_start; | 544 | pwork = &priv->alive_start; |
@@ -896,7 +892,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) | |||
896 | iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); | 892 | iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); |
897 | 893 | ||
898 | #ifdef CONFIG_IWLWIFI_DEBUG | 894 | #ifdef CONFIG_IWLWIFI_DEBUG |
899 | if (iwl_debug_level & IWL_DL_ISR) { | 895 | if (iwl_get_debug_level(priv) & IWL_DL_ISR) { |
900 | /* just for debug */ | 896 | /* just for debug */ |
901 | inta_mask = iwl_read32(priv, CSR_INT_MASK); | 897 | inta_mask = iwl_read32(priv, CSR_INT_MASK); |
902 | IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", | 898 | IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", |
@@ -931,7 +927,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) | |||
931 | } | 927 | } |
932 | 928 | ||
933 | #ifdef CONFIG_IWLWIFI_DEBUG | 929 | #ifdef CONFIG_IWLWIFI_DEBUG |
934 | if (iwl_debug_level & (IWL_DL_ISR)) { | 930 | if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { |
935 | /* NIC fires this, but we don't use it, redundant with WAKEUP */ | 931 | /* NIC fires this, but we don't use it, redundant with WAKEUP */ |
936 | if (inta & CSR_INT_BIT_SCD) { | 932 | if (inta & CSR_INT_BIT_SCD) { |
937 | IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " | 933 | IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " |
@@ -1045,7 +1041,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) | |||
1045 | iwl_enable_interrupts(priv); | 1041 | iwl_enable_interrupts(priv); |
1046 | 1042 | ||
1047 | #ifdef CONFIG_IWLWIFI_DEBUG | 1043 | #ifdef CONFIG_IWLWIFI_DEBUG |
1048 | if (iwl_debug_level & (IWL_DL_ISR)) { | 1044 | if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { |
1049 | inta = iwl_read32(priv, CSR_INT); | 1045 | inta = iwl_read32(priv, CSR_INT); |
1050 | inta_mask = iwl_read32(priv, CSR_INT_MASK); | 1046 | inta_mask = iwl_read32(priv, CSR_INT_MASK); |
1051 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | 1047 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); |
@@ -1076,7 +1072,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) | |||
1076 | inta = priv->inta; | 1072 | inta = priv->inta; |
1077 | 1073 | ||
1078 | #ifdef CONFIG_IWLWIFI_DEBUG | 1074 | #ifdef CONFIG_IWLWIFI_DEBUG |
1079 | if (iwl_debug_level & IWL_DL_ISR) { | 1075 | if (iwl_get_debug_level(priv) & IWL_DL_ISR) { |
1080 | /* just for debug */ | 1076 | /* just for debug */ |
1081 | inta_mask = iwl_read32(priv, CSR_INT_MASK); | 1077 | inta_mask = iwl_read32(priv, CSR_INT_MASK); |
1082 | IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ", | 1078 | IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ", |
@@ -1104,7 +1100,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) | |||
1104 | } | 1100 | } |
1105 | 1101 | ||
1106 | #ifdef CONFIG_IWLWIFI_DEBUG | 1102 | #ifdef CONFIG_IWLWIFI_DEBUG |
1107 | if (iwl_debug_level & (IWL_DL_ISR)) { | 1103 | if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { |
1108 | /* NIC fires this, but we don't use it, redundant with WAKEUP */ | 1104 | /* NIC fires this, but we don't use it, redundant with WAKEUP */ |
1109 | if (inta & CSR_INT_BIT_SCD) { | 1105 | if (inta & CSR_INT_BIT_SCD) { |
1110 | IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " | 1106 | IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " |
@@ -1610,7 +1606,7 @@ static void iwl_alive_start(struct iwl_priv *priv) | |||
1610 | set_bit(STATUS_READY, &priv->status); | 1606 | set_bit(STATUS_READY, &priv->status); |
1611 | wake_up_interruptible(&priv->wait_command_queue); | 1607 | wake_up_interruptible(&priv->wait_command_queue); |
1612 | 1608 | ||
1613 | iwl_power_update_mode(priv, 1); | 1609 | iwl_power_update_mode(priv, true); |
1614 | 1610 | ||
1615 | /* reassociate for ADHOC mode */ | 1611 | /* reassociate for ADHOC mode */ |
1616 | if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { | 1612 | if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { |
@@ -1784,7 +1780,6 @@ static int __iwl_up(struct iwl_priv *priv) | |||
1784 | { | 1780 | { |
1785 | int i; | 1781 | int i; |
1786 | int ret; | 1782 | int ret; |
1787 | unsigned long status; | ||
1788 | 1783 | ||
1789 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { | 1784 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { |
1790 | IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); | 1785 | IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); |
@@ -1862,51 +1857,6 @@ static int __iwl_up(struct iwl_priv *priv) | |||
1862 | /* start card; "initialize" will load runtime ucode */ | 1857 | /* start card; "initialize" will load runtime ucode */ |
1863 | iwl_nic_start(priv); | 1858 | iwl_nic_start(priv); |
1864 | 1859 | ||
1865 | /* Just finish download Init or Runtime uCode image to device | ||
1866 | * now we wait here for uCode send REPLY_ALIVE notification | ||
1867 | * to indicate uCode is ready. | ||
1868 | * 1) For Init uCode image, all iwlagn devices should wait here | ||
1869 | * on STATUS_INIT_UCODE_ALIVE status bit; if timeout before | ||
1870 | * receive the REPLY_ALIVE notification, go back and try to | ||
1871 | * download the Init uCode image again. | ||
1872 | * 2) For Runtime uCode image, all iwlagn devices except 4965 | ||
1873 | * wait here on STATUS_RT_UCODE_ALIVE status bit; if | ||
1874 | * timeout before receive the REPLY_ALIVE notification, go back | ||
1875 | * and download the Runtime uCode image again. | ||
1876 | * 3) For 4965 Runtime uCode, it will not go through this path, | ||
1877 | * need to wait for STATUS_RT_UCODE_ALIVE status bit in | ||
1878 | * iwl4965_init_alive_start() function; if timeout, need to | ||
1879 | * restart and download Init uCode image. | ||
1880 | */ | ||
1881 | if (priv->ucode_type == UCODE_INIT) | ||
1882 | status = STATUS_INIT_UCODE_ALIVE; | ||
1883 | else | ||
1884 | status = STATUS_RT_UCODE_ALIVE; | ||
1885 | if (test_bit(status, &priv->status)) { | ||
1886 | IWL_WARN(priv, | ||
1887 | "%s uCode already alive? " | ||
1888 | "Waiting for alive anyway\n", | ||
1889 | (status == STATUS_INIT_UCODE_ALIVE) | ||
1890 | ? "INIT" : "Runtime"); | ||
1891 | clear_bit(status, &priv->status); | ||
1892 | } | ||
1893 | ret = wait_event_interruptible_timeout( | ||
1894 | priv->wait_command_queue, | ||
1895 | test_bit(status, &priv->status), | ||
1896 | UCODE_ALIVE_TIMEOUT); | ||
1897 | if (!ret) { | ||
1898 | if (!test_bit(status, &priv->status)) { | ||
1899 | priv->ucode_type = | ||
1900 | (status == STATUS_INIT_UCODE_ALIVE) | ||
1901 | ? UCODE_NONE : UCODE_INIT; | ||
1902 | IWL_ERR(priv, | ||
1903 | "%s timeout after %dms\n", | ||
1904 | (status == STATUS_INIT_UCODE_ALIVE) | ||
1905 | ? "INIT" : "Runtime", | ||
1906 | jiffies_to_msecs(UCODE_ALIVE_TIMEOUT)); | ||
1907 | continue; | ||
1908 | } | ||
1909 | } | ||
1910 | IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); | 1860 | IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); |
1911 | 1861 | ||
1912 | return 0; | 1862 | return 0; |
@@ -2125,7 +2075,7 @@ void iwl_post_associate(struct iwl_priv *priv) | |||
2125 | * If chain noise has already been run, then we need to enable | 2075 | * If chain noise has already been run, then we need to enable |
2126 | * power management here */ | 2076 | * power management here */ |
2127 | if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) | 2077 | if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) |
2128 | iwl_power_update_mode(priv, 0); | 2078 | iwl_power_update_mode(priv, false); |
2129 | 2079 | ||
2130 | /* Enable Rx differential gain and sensitivity calibrations */ | 2080 | /* Enable Rx differential gain and sensitivity calibrations */ |
2131 | iwl_chain_noise_reset(priv); | 2081 | iwl_chain_noise_reset(priv); |
@@ -2455,15 +2405,15 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw, | |||
2455 | * | 2405 | * |
2456 | * See the level definitions in iwl for details. | 2406 | * See the level definitions in iwl for details. |
2457 | * | 2407 | * |
2458 | * FIXME This file can be deprecated as the module parameter is | 2408 | * The debug_level being managed using sysfs below is a per device debug |
2459 | * writable and users can thus also change the debug level | 2409 | * level that is used instead of the global debug level if it (the per |
2460 | * using the /sys/module/iwl3945/parameters/debug file. | 2410 | * device debug level) is set. |
2461 | */ | 2411 | */ |
2462 | |||
2463 | static ssize_t show_debug_level(struct device *d, | 2412 | static ssize_t show_debug_level(struct device *d, |
2464 | struct device_attribute *attr, char *buf) | 2413 | struct device_attribute *attr, char *buf) |
2465 | { | 2414 | { |
2466 | return sprintf(buf, "0x%08X\n", iwl_debug_level); | 2415 | struct iwl_priv *priv = dev_get_drvdata(d); |
2416 | return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); | ||
2467 | } | 2417 | } |
2468 | static ssize_t store_debug_level(struct device *d, | 2418 | static ssize_t store_debug_level(struct device *d, |
2469 | struct device_attribute *attr, | 2419 | struct device_attribute *attr, |
@@ -2476,9 +2426,12 @@ static ssize_t store_debug_level(struct device *d, | |||
2476 | ret = strict_strtoul(buf, 0, &val); | 2426 | ret = strict_strtoul(buf, 0, &val); |
2477 | if (ret) | 2427 | if (ret) |
2478 | IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); | 2428 | IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); |
2479 | else | 2429 | else { |
2480 | iwl_debug_level = val; | 2430 | priv->debug_level = val; |
2481 | 2431 | if (iwl_alloc_traffic_mem(priv)) | |
2432 | IWL_ERR(priv, | ||
2433 | "Not enough memory to generate traffic log\n"); | ||
2434 | } | ||
2482 | return strnlen(buf, count); | 2435 | return strnlen(buf, count); |
2483 | } | 2436 | } |
2484 | 2437 | ||
@@ -2612,47 +2565,6 @@ static ssize_t store_filter_flags(struct device *d, | |||
2612 | static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, | 2565 | static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, |
2613 | store_filter_flags); | 2566 | store_filter_flags); |
2614 | 2567 | ||
2615 | static ssize_t store_power_level(struct device *d, | ||
2616 | struct device_attribute *attr, | ||
2617 | const char *buf, size_t count) | ||
2618 | { | ||
2619 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
2620 | int ret; | ||
2621 | unsigned long mode; | ||
2622 | |||
2623 | |||
2624 | mutex_lock(&priv->mutex); | ||
2625 | |||
2626 | ret = strict_strtoul(buf, 10, &mode); | ||
2627 | if (ret) | ||
2628 | goto out; | ||
2629 | |||
2630 | ret = iwl_power_set_user_mode(priv, mode); | ||
2631 | if (ret) { | ||
2632 | IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n"); | ||
2633 | goto out; | ||
2634 | } | ||
2635 | ret = count; | ||
2636 | |||
2637 | out: | ||
2638 | mutex_unlock(&priv->mutex); | ||
2639 | return ret; | ||
2640 | } | ||
2641 | |||
2642 | static ssize_t show_power_level(struct device *d, | ||
2643 | struct device_attribute *attr, char *buf) | ||
2644 | { | ||
2645 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
2646 | int level = priv->power_data.power_mode; | ||
2647 | char *p = buf; | ||
2648 | |||
2649 | p += sprintf(p, "%d\n", level); | ||
2650 | return p - buf + 1; | ||
2651 | } | ||
2652 | |||
2653 | static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, | ||
2654 | store_power_level); | ||
2655 | |||
2656 | 2568 | ||
2657 | static ssize_t show_statistics(struct device *d, | 2569 | static ssize_t show_statistics(struct device *d, |
2658 | struct device_attribute *attr, char *buf) | 2570 | struct device_attribute *attr, char *buf) |
@@ -2745,7 +2657,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) | |||
2745 | static struct attribute *iwl_sysfs_entries[] = { | 2657 | static struct attribute *iwl_sysfs_entries[] = { |
2746 | &dev_attr_flags.attr, | 2658 | &dev_attr_flags.attr, |
2747 | &dev_attr_filter_flags.attr, | 2659 | &dev_attr_filter_flags.attr, |
2748 | &dev_attr_power_level.attr, | ||
2749 | &dev_attr_statistics.attr, | 2660 | &dev_attr_statistics.attr, |
2750 | &dev_attr_temperature.attr, | 2661 | &dev_attr_temperature.attr, |
2751 | &dev_attr_tx_power.attr, | 2662 | &dev_attr_tx_power.attr, |
@@ -2819,6 +2730,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2819 | #ifdef CONFIG_IWLWIFI_DEBUG | 2730 | #ifdef CONFIG_IWLWIFI_DEBUG |
2820 | atomic_set(&priv->restrict_refcnt, 0); | 2731 | atomic_set(&priv->restrict_refcnt, 0); |
2821 | #endif | 2732 | #endif |
2733 | if (iwl_alloc_traffic_mem(priv)) | ||
2734 | IWL_ERR(priv, "Not enough memory to generate traffic log\n"); | ||
2822 | 2735 | ||
2823 | /************************** | 2736 | /************************** |
2824 | * 2. Initializing PCI bus | 2737 | * 2. Initializing PCI bus |
@@ -3003,6 +2916,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3003 | pci_disable_device(pdev); | 2916 | pci_disable_device(pdev); |
3004 | out_ieee80211_free_hw: | 2917 | out_ieee80211_free_hw: |
3005 | ieee80211_free_hw(priv->hw); | 2918 | ieee80211_free_hw(priv->hw); |
2919 | iwl_free_traffic_mem(priv); | ||
3006 | out: | 2920 | out: |
3007 | return err; | 2921 | return err; |
3008 | } | 2922 | } |
@@ -3061,6 +2975,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) | |||
3061 | * until now... */ | 2975 | * until now... */ |
3062 | destroy_workqueue(priv->workqueue); | 2976 | destroy_workqueue(priv->workqueue); |
3063 | priv->workqueue = NULL; | 2977 | priv->workqueue = NULL; |
2978 | iwl_free_traffic_mem(priv); | ||
3064 | 2979 | ||
3065 | free_irq(priv->pci_dev->irq, priv); | 2980 | free_irq(priv->pci_dev->irq, priv); |
3066 | pci_disable_msi(priv->pci_dev); | 2981 | pci_disable_msi(priv->pci_dev); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 13180d6ee2f7..c4b565a2de94 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c | |||
@@ -852,7 +852,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, | |||
852 | priv->cfg->ops->lib->update_chain_flags(priv); | 852 | priv->cfg->ops->lib->update_chain_flags(priv); |
853 | 853 | ||
854 | data->state = IWL_CHAIN_NOISE_DONE; | 854 | data->state = IWL_CHAIN_NOISE_DONE; |
855 | iwl_power_update_mode(priv, 0); | 855 | iwl_power_update_mode(priv, false); |
856 | } | 856 | } |
857 | EXPORT_SYMBOL(iwl_chain_noise_calibration); | 857 | EXPORT_SYMBOL(iwl_chain_noise_calibration); |
858 | 858 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 39ede5727fe4..68d7719071f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -283,7 +283,7 @@ struct iwl3945_power_per_rate { | |||
283 | * 1) Dual stream (MIMO) | 283 | * 1) Dual stream (MIMO) |
284 | * 2) Triple stream (MIMO) | 284 | * 2) Triple stream (MIMO) |
285 | * | 285 | * |
286 | * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data | 286 | * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data |
287 | * | 287 | * |
288 | * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"): | 288 | * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"): |
289 | * 3-0: 0xD) 6 Mbps | 289 | * 3-0: 0xD) 6 Mbps |
@@ -320,11 +320,11 @@ struct iwl3945_power_per_rate { | |||
320 | #define RATE_MCS_GF_POS 10 | 320 | #define RATE_MCS_GF_POS 10 |
321 | #define RATE_MCS_GF_MSK 0x400 | 321 | #define RATE_MCS_GF_MSK 0x400 |
322 | 322 | ||
323 | /* Bit 11: (1) Use 40Mhz FAT chnl width, (0) use 20 MHz legacy chnl width */ | 323 | /* Bit 11: (1) Use 40Mhz HT40 chnl width, (0) use 20 MHz legacy chnl width */ |
324 | #define RATE_MCS_FAT_POS 11 | 324 | #define RATE_MCS_HT40_POS 11 |
325 | #define RATE_MCS_FAT_MSK 0x800 | 325 | #define RATE_MCS_HT40_MSK 0x800 |
326 | 326 | ||
327 | /* Bit 12: (1) Duplicate data on both 20MHz chnls. FAT (bit 11) must be set. */ | 327 | /* Bit 12: (1) Duplicate data on both 20MHz chnls. HT40 (bit 11) must be set. */ |
328 | #define RATE_MCS_DUP_POS 12 | 328 | #define RATE_MCS_DUP_POS 12 |
329 | #define RATE_MCS_DUP_MSK 0x1000 | 329 | #define RATE_MCS_DUP_MSK 0x1000 |
330 | 330 | ||
@@ -459,7 +459,7 @@ struct iwl_init_alive_resp { | |||
459 | 459 | ||
460 | /* calibration values from "initialize" uCode */ | 460 | /* calibration values from "initialize" uCode */ |
461 | __le32 voltage; /* signed, higher value is lower voltage */ | 461 | __le32 voltage; /* signed, higher value is lower voltage */ |
462 | __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for FAT channel*/ | 462 | __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for HT40 */ |
463 | __le32 therm_r2[2]; /* signed */ | 463 | __le32 therm_r2[2]; /* signed */ |
464 | __le32 therm_r3[2]; /* signed */ | 464 | __le32 therm_r3[2]; /* signed */ |
465 | __le32 therm_r4[2]; /* signed */ | 465 | __le32 therm_r4[2]; /* signed */ |
@@ -610,7 +610,7 @@ enum { | |||
610 | #define RXON_FLG_HT_OPERATING_MODE_POS (23) | 610 | #define RXON_FLG_HT_OPERATING_MODE_POS (23) |
611 | 611 | ||
612 | #define RXON_FLG_HT_PROT_MSK cpu_to_le32(0x1 << 23) | 612 | #define RXON_FLG_HT_PROT_MSK cpu_to_le32(0x1 << 23) |
613 | #define RXON_FLG_FAT_PROT_MSK cpu_to_le32(0x2 << 23) | 613 | #define RXON_FLG_HT40_PROT_MSK cpu_to_le32(0x2 << 23) |
614 | 614 | ||
615 | #define RXON_FLG_CHANNEL_MODE_POS (25) | 615 | #define RXON_FLG_CHANNEL_MODE_POS (25) |
616 | #define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) | 616 | #define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) |
@@ -891,7 +891,7 @@ struct iwl_qosparam_cmd { | |||
891 | #define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18) | 891 | #define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18) |
892 | #define STA_FLG_MAX_AGG_SIZE_POS (19) | 892 | #define STA_FLG_MAX_AGG_SIZE_POS (19) |
893 | #define STA_FLG_MAX_AGG_SIZE_MSK cpu_to_le32(3 << 19) | 893 | #define STA_FLG_MAX_AGG_SIZE_MSK cpu_to_le32(3 << 19) |
894 | #define STA_FLG_FAT_EN_MSK cpu_to_le32(1 << 21) | 894 | #define STA_FLG_HT40_EN_MSK cpu_to_le32(1 << 21) |
895 | #define STA_FLG_MIMO_DIS_MSK cpu_to_le32(1 << 22) | 895 | #define STA_FLG_MIMO_DIS_MSK cpu_to_le32(1 << 22) |
896 | #define STA_FLG_AGG_MPDU_DENSITY_POS (23) | 896 | #define STA_FLG_AGG_MPDU_DENSITY_POS (23) |
897 | #define STA_FLG_AGG_MPDU_DENSITY_MSK cpu_to_le32(7 << 23) | 897 | #define STA_FLG_AGG_MPDU_DENSITY_MSK cpu_to_le32(7 << 23) |
@@ -1984,10 +1984,10 @@ struct iwl_link_qual_agg_params { | |||
1984 | * a) Use this same initial rate for first 3 entries. | 1984 | * a) Use this same initial rate for first 3 entries. |
1985 | * b) Find next lower available rate using same mode (SISO or MIMO), | 1985 | * b) Find next lower available rate using same mode (SISO or MIMO), |
1986 | * use for next 3 entries. If no lower rate available, switch to | 1986 | * use for next 3 entries. If no lower rate available, switch to |
1987 | * legacy mode (no FAT channel, no MIMO, no short guard interval). | 1987 | * legacy mode (no HT40 channel, no MIMO, no short guard interval). |
1988 | * c) If using MIMO, set command's mimo_delimiter to number of entries | 1988 | * c) If using MIMO, set command's mimo_delimiter to number of entries |
1989 | * using MIMO (3 or 6). | 1989 | * using MIMO (3 or 6). |
1990 | * d) After trying 2 HT rates, switch to legacy mode (no FAT channel, | 1990 | * d) After trying 2 HT rates, switch to legacy mode (no HT40 channel, |
1991 | * no MIMO, no short guard interval), at the next lower bit rate | 1991 | * no MIMO, no short guard interval), at the next lower bit rate |
1992 | * (e.g. if second HT bit rate was 54, try 48 legacy), and follow | 1992 | * (e.g. if second HT bit rate was 54, try 48 legacy), and follow |
1993 | * legacy procedure for remaining table entries. | 1993 | * legacy procedure for remaining table entries. |
@@ -2313,15 +2313,22 @@ struct iwl_spectrum_notification { | |||
2313 | * PM allow: | 2313 | * PM allow: |
2314 | * bit 0 - '0' Driver not allow power management | 2314 | * bit 0 - '0' Driver not allow power management |
2315 | * '1' Driver allow PM (use rest of parameters) | 2315 | * '1' Driver allow PM (use rest of parameters) |
2316 | * | ||
2316 | * uCode send sleep notifications: | 2317 | * uCode send sleep notifications: |
2317 | * bit 1 - '0' Don't send sleep notification | 2318 | * bit 1 - '0' Don't send sleep notification |
2318 | * '1' send sleep notification (SEND_PM_NOTIFICATION) | 2319 | * '1' send sleep notification (SEND_PM_NOTIFICATION) |
2320 | * | ||
2319 | * Sleep over DTIM | 2321 | * Sleep over DTIM |
2320 | * bit 2 - '0' PM have to walk up every DTIM | 2322 | * bit 2 - '0' PM have to walk up every DTIM |
2321 | * '1' PM could sleep over DTIM till listen Interval. | 2323 | * '1' PM could sleep over DTIM till listen Interval. |
2324 | * | ||
2322 | * PCI power managed | 2325 | * PCI power managed |
2323 | * bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1) | 2326 | * bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1) |
2324 | * '1' !(PCI_CFG_LINK_CTRL & 0x1) | 2327 | * '1' !(PCI_CFG_LINK_CTRL & 0x1) |
2328 | * | ||
2329 | * Fast PD | ||
2330 | * bit 4 - '1' Put radio to sleep when receiving frame for others | ||
2331 | * | ||
2325 | * Force sleep Modes | 2332 | * Force sleep Modes |
2326 | * bit 31/30- '00' use both mac/xtal sleeps | 2333 | * bit 31/30- '00' use both mac/xtal sleeps |
2327 | * '01' force Mac sleep | 2334 | * '01' force Mac sleep |
@@ -3017,7 +3024,7 @@ struct iwl_statistics_cmd { | |||
3017 | * one channel that has just been scanned. | 3024 | * one channel that has just been scanned. |
3018 | */ | 3025 | */ |
3019 | #define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) | 3026 | #define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) |
3020 | #define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8) | 3027 | #define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8) |
3021 | 3028 | ||
3022 | struct iwl3945_notif_statistics { | 3029 | struct iwl3945_notif_statistics { |
3023 | __le32 flag; | 3030 | __le32 flag; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2ffbd27d01d2..af735128333a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -105,7 +105,7 @@ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, | |||
105 | r->flags |= IEEE80211_TX_RC_MCS; | 105 | r->flags |= IEEE80211_TX_RC_MCS; |
106 | if (rate_n_flags & RATE_MCS_GF_MSK) | 106 | if (rate_n_flags & RATE_MCS_GF_MSK) |
107 | r->flags |= IEEE80211_TX_RC_GREEN_FIELD; | 107 | r->flags |= IEEE80211_TX_RC_GREEN_FIELD; |
108 | if (rate_n_flags & RATE_MCS_FAT_MSK) | 108 | if (rate_n_flags & RATE_MCS_HT40_MSK) |
109 | r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | 109 | r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; |
110 | if (rate_n_flags & RATE_MCS_DUP_MSK) | 110 | if (rate_n_flags & RATE_MCS_DUP_MSK) |
111 | r->flags |= IEEE80211_TX_RC_DUP_DATA; | 111 | r->flags |= IEEE80211_TX_RC_DUP_DATA; |
@@ -400,7 +400,7 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, | |||
400 | (WLAN_HT_CAP_SM_PS_DISABLED << 2)); | 400 | (WLAN_HT_CAP_SM_PS_DISABLED << 2)); |
401 | 401 | ||
402 | max_bit_rate = MAX_BIT_RATE_20_MHZ; | 402 | max_bit_rate = MAX_BIT_RATE_20_MHZ; |
403 | if (priv->hw_params.fat_channel & BIT(band)) { | 403 | if (priv->hw_params.ht40_channel & BIT(band)) { |
404 | ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 404 | ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
405 | ht_info->cap |= IEEE80211_HT_CAP_SGI_40; | 405 | ht_info->cap |= IEEE80211_HT_CAP_SGI_40; |
406 | ht_info->mcs.rx_mask[4] = 0x01; | 406 | ht_info->mcs.rx_mask[4] = 0x01; |
@@ -540,7 +540,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) | |||
540 | if (ch->flags & EEPROM_CHANNEL_RADAR) | 540 | if (ch->flags & EEPROM_CHANNEL_RADAR) |
541 | geo_ch->flags |= IEEE80211_CHAN_RADAR; | 541 | geo_ch->flags |= IEEE80211_CHAN_RADAR; |
542 | 542 | ||
543 | geo_ch->flags |= ch->fat_extension_channel; | 543 | geo_ch->flags |= ch->ht40_extension_channel; |
544 | 544 | ||
545 | if (ch->max_power_avg > priv->tx_power_channel_lmt) | 545 | if (ch->max_power_avg > priv->tx_power_channel_lmt) |
546 | priv->tx_power_channel_lmt = ch->max_power_avg; | 546 | priv->tx_power_channel_lmt = ch->max_power_avg; |
@@ -604,16 +604,16 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, | |||
604 | return 0; | 604 | return 0; |
605 | 605 | ||
606 | if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) | 606 | if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) |
607 | return !(ch_info->fat_extension_channel & | 607 | return !(ch_info->ht40_extension_channel & |
608 | IEEE80211_CHAN_NO_HT40PLUS); | 608 | IEEE80211_CHAN_NO_HT40PLUS); |
609 | else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) | 609 | else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) |
610 | return !(ch_info->fat_extension_channel & | 610 | return !(ch_info->ht40_extension_channel & |
611 | IEEE80211_CHAN_NO_HT40MINUS); | 611 | IEEE80211_CHAN_NO_HT40MINUS); |
612 | 612 | ||
613 | return 0; | 613 | return 0; |
614 | } | 614 | } |
615 | 615 | ||
616 | u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, | 616 | u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, |
617 | struct ieee80211_sta_ht_cap *sta_ht_inf) | 617 | struct ieee80211_sta_ht_cap *sta_ht_inf) |
618 | { | 618 | { |
619 | struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; | 619 | struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; |
@@ -637,7 +637,7 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, | |||
637 | le16_to_cpu(priv->staging_rxon.channel), | 637 | le16_to_cpu(priv->staging_rxon.channel), |
638 | iwl_ht_conf->extension_chan_offset); | 638 | iwl_ht_conf->extension_chan_offset); |
639 | } | 639 | } |
640 | EXPORT_SYMBOL(iwl_is_fat_tx_allowed); | 640 | EXPORT_SYMBOL(iwl_is_ht40_tx_allowed); |
641 | 641 | ||
642 | static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) | 642 | static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) |
643 | { | 643 | { |
@@ -866,7 +866,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) | |||
866 | if (!ht_info->is_ht) { | 866 | if (!ht_info->is_ht) { |
867 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | | 867 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | |
868 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | | 868 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | |
869 | RXON_FLG_FAT_PROT_MSK | | 869 | RXON_FLG_HT40_PROT_MSK | |
870 | RXON_FLG_HT_PROT_MSK); | 870 | RXON_FLG_HT_PROT_MSK); |
871 | return; | 871 | return; |
872 | } | 872 | } |
@@ -877,12 +877,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) | |||
877 | rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS); | 877 | rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS); |
878 | 878 | ||
879 | /* Set up channel bandwidth: | 879 | /* Set up channel bandwidth: |
880 | * 20 MHz only, 20/40 mixed or pure 40 if fat ok */ | 880 | * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */ |
881 | /* clear the HT channel mode before set the mode */ | 881 | /* clear the HT channel mode before set the mode */ |
882 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | | 882 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | |
883 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); | 883 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); |
884 | if (iwl_is_fat_tx_allowed(priv, NULL)) { | 884 | if (iwl_is_ht40_tx_allowed(priv, NULL)) { |
885 | /* pure 40 fat */ | 885 | /* pure ht40 */ |
886 | if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { | 886 | if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { |
887 | rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; | 887 | rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; |
888 | /* Note: control channel is opposite of extension channel */ | 888 | /* Note: control channel is opposite of extension channel */ |
@@ -1278,7 +1278,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) | |||
1278 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; | 1278 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; |
1279 | 1279 | ||
1280 | IWL_DEBUG_RADIO(priv, "RX CONFIG:\n"); | 1280 | IWL_DEBUG_RADIO(priv, "RX CONFIG:\n"); |
1281 | iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); | 1281 | iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); |
1282 | IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); | 1282 | IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); |
1283 | IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); | 1283 | IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); |
1284 | IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n", | 1284 | IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n", |
@@ -1343,17 +1343,10 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) | |||
1343 | u32 desc, time, count, base, data1; | 1343 | u32 desc, time, count, base, data1; |
1344 | u32 blink1, blink2, ilink1, ilink2; | 1344 | u32 blink1, blink2, ilink1, ilink2; |
1345 | 1345 | ||
1346 | switch (priv->ucode_type) { | 1346 | if (priv->ucode_type == UCODE_INIT) |
1347 | case UCODE_RT: | ||
1348 | base = le32_to_cpu(priv->card_alive.error_event_table_ptr); | ||
1349 | break; | ||
1350 | case UCODE_INIT: | ||
1351 | base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); | 1347 | base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); |
1352 | break; | 1348 | else |
1353 | default: | 1349 | base = le32_to_cpu(priv->card_alive.error_event_table_ptr); |
1354 | IWL_ERR(priv, "uCode image not available\n"); | ||
1355 | return; | ||
1356 | } | ||
1357 | 1350 | ||
1358 | if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { | 1351 | if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { |
1359 | IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); | 1352 | IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); |
@@ -1405,17 +1398,10 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | |||
1405 | 1398 | ||
1406 | if (num_events == 0) | 1399 | if (num_events == 0) |
1407 | return; | 1400 | return; |
1408 | switch (priv->ucode_type) { | 1401 | if (priv->ucode_type == UCODE_INIT) |
1409 | case UCODE_RT: | ||
1410 | base = le32_to_cpu(priv->card_alive.log_event_table_ptr); | ||
1411 | break; | ||
1412 | case UCODE_INIT: | ||
1413 | base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); | 1402 | base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); |
1414 | break; | 1403 | else |
1415 | default: | 1404 | base = le32_to_cpu(priv->card_alive.log_event_table_ptr); |
1416 | IWL_ERR(priv, "uCode image not available\n"); | ||
1417 | return; | ||
1418 | } | ||
1419 | 1405 | ||
1420 | if (mode == 0) | 1406 | if (mode == 0) |
1421 | event_size = 2 * sizeof(u32); | 1407 | event_size = 2 * sizeof(u32); |
@@ -1452,17 +1438,10 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) | |||
1452 | u32 next_entry; /* index of next entry to be written by uCode */ | 1438 | u32 next_entry; /* index of next entry to be written by uCode */ |
1453 | u32 size; /* # entries that we'll print */ | 1439 | u32 size; /* # entries that we'll print */ |
1454 | 1440 | ||
1455 | switch (priv->ucode_type) { | 1441 | if (priv->ucode_type == UCODE_INIT) |
1456 | case UCODE_RT: | ||
1457 | base = le32_to_cpu(priv->card_alive.log_event_table_ptr); | ||
1458 | break; | ||
1459 | case UCODE_INIT: | ||
1460 | base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); | 1442 | base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); |
1461 | break; | 1443 | else |
1462 | default: | 1444 | base = le32_to_cpu(priv->card_alive.log_event_table_ptr); |
1463 | IWL_ERR(priv, "uCode image not available\n"); | ||
1464 | return; | ||
1465 | } | ||
1466 | 1445 | ||
1467 | if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { | 1446 | if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { |
1468 | IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); | 1447 | IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); |
@@ -1508,7 +1487,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv) | |||
1508 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); | 1487 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); |
1509 | 1488 | ||
1510 | #ifdef CONFIG_IWLWIFI_DEBUG | 1489 | #ifdef CONFIG_IWLWIFI_DEBUG |
1511 | if (iwl_debug_level & IWL_DL_FW_ERRORS) { | 1490 | if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) { |
1512 | iwl_dump_nic_error_log(priv); | 1491 | iwl_dump_nic_error_log(priv); |
1513 | iwl_dump_nic_event_log(priv); | 1492 | iwl_dump_nic_event_log(priv); |
1514 | iwl_print_rx_config_cmd(priv); | 1493 | iwl_print_rx_config_cmd(priv); |
@@ -1589,7 +1568,8 @@ int iwl_setup_mac(struct iwl_priv *priv) | |||
1589 | IEEE80211_HW_NOISE_DBM | | 1568 | IEEE80211_HW_NOISE_DBM | |
1590 | IEEE80211_HW_AMPDU_AGGREGATION | | 1569 | IEEE80211_HW_AMPDU_AGGREGATION | |
1591 | IEEE80211_HW_SPECTRUM_MGMT | | 1570 | IEEE80211_HW_SPECTRUM_MGMT | |
1592 | IEEE80211_HW_SUPPORTS_PS; | 1571 | IEEE80211_HW_SUPPORTS_PS | |
1572 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; | ||
1593 | hw->wiphy->interface_modes = | 1573 | hw->wiphy->interface_modes = |
1594 | BIT(NL80211_IFTYPE_STATION) | | 1574 | BIT(NL80211_IFTYPE_STATION) | |
1595 | BIT(NL80211_IFTYPE_ADHOC); | 1575 | BIT(NL80211_IFTYPE_ADHOC); |
@@ -1684,8 +1664,6 @@ int iwl_init_drv(struct iwl_priv *priv) | |||
1684 | priv->qos_data.qos_cap.val = 0; | 1664 | priv->qos_data.qos_cap.val = 0; |
1685 | 1665 | ||
1686 | priv->rates_mask = IWL_RATES_MASK; | 1666 | priv->rates_mask = IWL_RATES_MASK; |
1687 | /* If power management is turned on, default to CAM mode */ | ||
1688 | priv->power_mode = IWL_POWER_MODE_CAM; | ||
1689 | priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX; | 1667 | priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX; |
1690 | 1668 | ||
1691 | ret = iwl_init_channel_map(priv); | 1669 | ret = iwl_init_channel_map(priv); |
@@ -1985,7 +1963,7 @@ static irqreturn_t iwl_isr(int irq, void *data) | |||
1985 | } | 1963 | } |
1986 | 1964 | ||
1987 | #ifdef CONFIG_IWLWIFI_DEBUG | 1965 | #ifdef CONFIG_IWLWIFI_DEBUG |
1988 | if (iwl_debug_level & (IWL_DL_ISR)) { | 1966 | if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { |
1989 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | 1967 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); |
1990 | IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, " | 1968 | IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, " |
1991 | "fh 0x%08x\n", inta, inta_mask, inta_fh); | 1969 | "fh 0x%08x\n", inta, inta_mask, inta_fh); |
@@ -2235,7 +2213,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) | |||
2235 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, | 2213 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, |
2236 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); | 2214 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); |
2237 | spin_unlock_irqrestore(&priv->lock, flags); | 2215 | spin_unlock_irqrestore(&priv->lock, flags); |
2238 | priv->power_data.ct_kill_toggle = false; | 2216 | priv->thermal_throttle.ct_kill_toggle = false; |
2239 | 2217 | ||
2240 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { | 2218 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { |
2241 | case CSR_HW_REV_TYPE_1000: | 2219 | case CSR_HW_REV_TYPE_1000: |
@@ -2248,6 +2226,15 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) | |||
2248 | 2226 | ||
2249 | ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, | 2227 | ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, |
2250 | sizeof(adv_cmd), &adv_cmd); | 2228 | sizeof(adv_cmd), &adv_cmd); |
2229 | if (ret) | ||
2230 | IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); | ||
2231 | else | ||
2232 | IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " | ||
2233 | "succeeded, " | ||
2234 | "critical temperature enter is %d," | ||
2235 | "exit is %d\n", | ||
2236 | priv->hw_params.ct_kill_threshold, | ||
2237 | priv->hw_params.ct_kill_exit_threshold); | ||
2251 | break; | 2238 | break; |
2252 | default: | 2239 | default: |
2253 | cmd.critical_temperature_R = | 2240 | cmd.critical_temperature_R = |
@@ -2255,16 +2242,15 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) | |||
2255 | 2242 | ||
2256 | ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, | 2243 | ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, |
2257 | sizeof(cmd), &cmd); | 2244 | sizeof(cmd), &cmd); |
2245 | if (ret) | ||
2246 | IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); | ||
2247 | else | ||
2248 | IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " | ||
2249 | "succeeded, " | ||
2250 | "critical temperature is %d\n", | ||
2251 | priv->hw_params.ct_kill_threshold); | ||
2258 | break; | 2252 | break; |
2259 | } | 2253 | } |
2260 | ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, | ||
2261 | sizeof(cmd), &cmd); | ||
2262 | if (ret) | ||
2263 | IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); | ||
2264 | else | ||
2265 | IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD succeeded, " | ||
2266 | "critical temperature is %d\n", | ||
2267 | cmd.critical_temperature_R); | ||
2268 | } | 2254 | } |
2269 | EXPORT_SYMBOL(iwl_rf_kill_ct_config); | 2255 | EXPORT_SYMBOL(iwl_rf_kill_ct_config); |
2270 | 2256 | ||
@@ -2310,7 +2296,7 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, | |||
2310 | IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " | 2296 | IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " |
2311 | "notification for %s:\n", | 2297 | "notification for %s:\n", |
2312 | le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); | 2298 | le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); |
2313 | iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); | 2299 | iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); |
2314 | } | 2300 | } |
2315 | EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); | 2301 | EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); |
2316 | 2302 | ||
@@ -2428,7 +2414,7 @@ static void iwl_ht_conf(struct iwl_priv *priv, | |||
2428 | else if (conf_is_ht40_plus(&priv->hw->conf)) | 2414 | else if (conf_is_ht40_plus(&priv->hw->conf)) |
2429 | iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | 2415 | iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; |
2430 | 2416 | ||
2431 | /* If no above or below channel supplied disable FAT channel */ | 2417 | /* If no above or below channel supplied disable HT40 channel */ |
2432 | if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && | 2418 | if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && |
2433 | iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) | 2419 | iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) |
2434 | iwl_conf->supported_chan_width = 0; | 2420 | iwl_conf->supported_chan_width = 0; |
@@ -2564,7 +2550,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, | |||
2564 | if (bss_conf->assoc) { | 2550 | if (bss_conf->assoc) { |
2565 | priv->assoc_id = bss_conf->aid; | 2551 | priv->assoc_id = bss_conf->aid; |
2566 | priv->beacon_int = bss_conf->beacon_int; | 2552 | priv->beacon_int = bss_conf->beacon_int; |
2567 | priv->power_data.dtim_period = bss_conf->dtim_period; | ||
2568 | priv->timestamp = bss_conf->timestamp; | 2553 | priv->timestamp = bss_conf->timestamp; |
2569 | priv->assoc_capability = bss_conf->assoc_capability; | 2554 | priv->assoc_capability = bss_conf->assoc_capability; |
2570 | 2555 | ||
@@ -2814,13 +2799,10 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) | |||
2814 | iwl_set_rate(priv); | 2799 | iwl_set_rate(priv); |
2815 | } | 2800 | } |
2816 | 2801 | ||
2817 | if (changed & IEEE80211_CONF_CHANGE_PS && | 2802 | if (changed & IEEE80211_CONF_CHANGE_PS) { |
2818 | priv->iw_mode == NL80211_IFTYPE_STATION) { | 2803 | ret = iwl_power_update_mode(priv, false); |
2819 | priv->power_data.power_disabled = | ||
2820 | !(conf->flags & IEEE80211_CONF_PS); | ||
2821 | ret = iwl_power_update_mode(priv, 0); | ||
2822 | if (ret) | 2804 | if (ret) |
2823 | IWL_DEBUG_MAC80211(priv, "Error setting power level\n"); | 2805 | IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); |
2824 | } | 2806 | } |
2825 | 2807 | ||
2826 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | 2808 | if (changed & IEEE80211_CONF_CHANGE_POWER) { |
@@ -2953,6 +2935,248 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw) | |||
2953 | } | 2935 | } |
2954 | EXPORT_SYMBOL(iwl_mac_reset_tsf); | 2936 | EXPORT_SYMBOL(iwl_mac_reset_tsf); |
2955 | 2937 | ||
2938 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
2939 | |||
2940 | #define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES) | ||
2941 | |||
2942 | void iwl_reset_traffic_log(struct iwl_priv *priv) | ||
2943 | { | ||
2944 | priv->tx_traffic_idx = 0; | ||
2945 | priv->rx_traffic_idx = 0; | ||
2946 | if (priv->tx_traffic) | ||
2947 | memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE); | ||
2948 | if (priv->rx_traffic) | ||
2949 | memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE); | ||
2950 | } | ||
2951 | |||
2952 | int iwl_alloc_traffic_mem(struct iwl_priv *priv) | ||
2953 | { | ||
2954 | u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE; | ||
2955 | |||
2956 | if (iwl_debug_level & IWL_DL_TX) { | ||
2957 | if (!priv->tx_traffic) { | ||
2958 | priv->tx_traffic = | ||
2959 | kzalloc(traffic_size, GFP_KERNEL); | ||
2960 | if (!priv->tx_traffic) | ||
2961 | return -ENOMEM; | ||
2962 | } | ||
2963 | } | ||
2964 | if (iwl_debug_level & IWL_DL_RX) { | ||
2965 | if (!priv->rx_traffic) { | ||
2966 | priv->rx_traffic = | ||
2967 | kzalloc(traffic_size, GFP_KERNEL); | ||
2968 | if (!priv->rx_traffic) | ||
2969 | return -ENOMEM; | ||
2970 | } | ||
2971 | } | ||
2972 | iwl_reset_traffic_log(priv); | ||
2973 | return 0; | ||
2974 | } | ||
2975 | EXPORT_SYMBOL(iwl_alloc_traffic_mem); | ||
2976 | |||
2977 | void iwl_free_traffic_mem(struct iwl_priv *priv) | ||
2978 | { | ||
2979 | kfree(priv->tx_traffic); | ||
2980 | priv->tx_traffic = NULL; | ||
2981 | |||
2982 | kfree(priv->rx_traffic); | ||
2983 | priv->rx_traffic = NULL; | ||
2984 | } | ||
2985 | EXPORT_SYMBOL(iwl_free_traffic_mem); | ||
2986 | |||
2987 | void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, | ||
2988 | u16 length, struct ieee80211_hdr *header) | ||
2989 | { | ||
2990 | __le16 fc; | ||
2991 | u16 len; | ||
2992 | |||
2993 | if (likely(!(iwl_debug_level & IWL_DL_TX))) | ||
2994 | return; | ||
2995 | |||
2996 | if (!priv->tx_traffic) | ||
2997 | return; | ||
2998 | |||
2999 | fc = header->frame_control; | ||
3000 | if (ieee80211_is_data(fc)) { | ||
3001 | len = (length > IWL_TRAFFIC_ENTRY_SIZE) | ||
3002 | ? IWL_TRAFFIC_ENTRY_SIZE : length; | ||
3003 | memcpy((priv->tx_traffic + | ||
3004 | (priv->tx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)), | ||
3005 | header, len); | ||
3006 | priv->tx_traffic_idx = | ||
3007 | (priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; | ||
3008 | } | ||
3009 | } | ||
3010 | EXPORT_SYMBOL(iwl_dbg_log_tx_data_frame); | ||
3011 | |||
3012 | void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, | ||
3013 | u16 length, struct ieee80211_hdr *header) | ||
3014 | { | ||
3015 | __le16 fc; | ||
3016 | u16 len; | ||
3017 | |||
3018 | if (likely(!(iwl_debug_level & IWL_DL_RX))) | ||
3019 | return; | ||
3020 | |||
3021 | if (!priv->rx_traffic) | ||
3022 | return; | ||
3023 | |||
3024 | fc = header->frame_control; | ||
3025 | if (ieee80211_is_data(fc)) { | ||
3026 | len = (length > IWL_TRAFFIC_ENTRY_SIZE) | ||
3027 | ? IWL_TRAFFIC_ENTRY_SIZE : length; | ||
3028 | memcpy((priv->rx_traffic + | ||
3029 | (priv->rx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)), | ||
3030 | header, len); | ||
3031 | priv->rx_traffic_idx = | ||
3032 | (priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; | ||
3033 | } | ||
3034 | } | ||
3035 | EXPORT_SYMBOL(iwl_dbg_log_rx_data_frame); | ||
3036 | |||
3037 | const char *get_mgmt_string(int cmd) | ||
3038 | { | ||
3039 | switch (cmd) { | ||
3040 | IWL_CMD(MANAGEMENT_ASSOC_REQ); | ||
3041 | IWL_CMD(MANAGEMENT_ASSOC_RESP); | ||
3042 | IWL_CMD(MANAGEMENT_REASSOC_REQ); | ||
3043 | IWL_CMD(MANAGEMENT_REASSOC_RESP); | ||
3044 | IWL_CMD(MANAGEMENT_PROBE_REQ); | ||
3045 | IWL_CMD(MANAGEMENT_PROBE_RESP); | ||
3046 | IWL_CMD(MANAGEMENT_BEACON); | ||
3047 | IWL_CMD(MANAGEMENT_ATIM); | ||
3048 | IWL_CMD(MANAGEMENT_DISASSOC); | ||
3049 | IWL_CMD(MANAGEMENT_AUTH); | ||
3050 | IWL_CMD(MANAGEMENT_DEAUTH); | ||
3051 | IWL_CMD(MANAGEMENT_ACTION); | ||
3052 | default: | ||
3053 | return "UNKNOWN"; | ||
3054 | |||
3055 | } | ||
3056 | } | ||
3057 | |||
3058 | const char *get_ctrl_string(int cmd) | ||
3059 | { | ||
3060 | switch (cmd) { | ||
3061 | IWL_CMD(CONTROL_BACK_REQ); | ||
3062 | IWL_CMD(CONTROL_BACK); | ||
3063 | IWL_CMD(CONTROL_PSPOLL); | ||
3064 | IWL_CMD(CONTROL_RTS); | ||
3065 | IWL_CMD(CONTROL_CTS); | ||
3066 | IWL_CMD(CONTROL_ACK); | ||
3067 | IWL_CMD(CONTROL_CFEND); | ||
3068 | IWL_CMD(CONTROL_CFENDACK); | ||
3069 | default: | ||
3070 | return "UNKNOWN"; | ||
3071 | |||
3072 | } | ||
3073 | } | ||
3074 | |||
3075 | void iwl_clear_tx_stats(struct iwl_priv *priv) | ||
3076 | { | ||
3077 | memset(&priv->tx_stats, 0, sizeof(struct traffic_stats)); | ||
3078 | |||
3079 | } | ||
3080 | |||
3081 | void iwl_clear_rx_stats(struct iwl_priv *priv) | ||
3082 | { | ||
3083 | memset(&priv->rx_stats, 0, sizeof(struct traffic_stats)); | ||
3084 | } | ||
3085 | |||
3086 | /* | ||
3087 | * if CONFIG_IWLWIFI_DEBUGFS defined, iwl_update_stats function will | ||
3088 | * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass. | ||
3089 | * Use debugFs to display the rx/rx_statistics | ||
3090 | * if CONFIG_IWLWIFI_DEBUGFS not being defined, then no MGMT and CTRL | ||
3091 | * information will be recorded, but DATA pkt still will be recorded | ||
3092 | * for the reason of iwl_led.c need to control the led blinking based on | ||
3093 | * number of tx and rx data. | ||
3094 | * | ||
3095 | */ | ||
3096 | void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) | ||
3097 | { | ||
3098 | struct traffic_stats *stats; | ||
3099 | |||
3100 | if (is_tx) | ||
3101 | stats = &priv->tx_stats; | ||
3102 | else | ||
3103 | stats = &priv->rx_stats; | ||
3104 | |||
3105 | if (ieee80211_is_mgmt(fc)) { | ||
3106 | switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { | ||
3107 | case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): | ||
3108 | stats->mgmt[MANAGEMENT_ASSOC_REQ]++; | ||
3109 | break; | ||
3110 | case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): | ||
3111 | stats->mgmt[MANAGEMENT_ASSOC_RESP]++; | ||
3112 | break; | ||
3113 | case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): | ||
3114 | stats->mgmt[MANAGEMENT_REASSOC_REQ]++; | ||
3115 | break; | ||
3116 | case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): | ||
3117 | stats->mgmt[MANAGEMENT_REASSOC_RESP]++; | ||
3118 | break; | ||
3119 | case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): | ||
3120 | stats->mgmt[MANAGEMENT_PROBE_REQ]++; | ||
3121 | break; | ||
3122 | case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): | ||
3123 | stats->mgmt[MANAGEMENT_PROBE_RESP]++; | ||
3124 | break; | ||
3125 | case cpu_to_le16(IEEE80211_STYPE_BEACON): | ||
3126 | stats->mgmt[MANAGEMENT_BEACON]++; | ||
3127 | break; | ||
3128 | case cpu_to_le16(IEEE80211_STYPE_ATIM): | ||
3129 | stats->mgmt[MANAGEMENT_ATIM]++; | ||
3130 | break; | ||
3131 | case cpu_to_le16(IEEE80211_STYPE_DISASSOC): | ||
3132 | stats->mgmt[MANAGEMENT_DISASSOC]++; | ||
3133 | break; | ||
3134 | case cpu_to_le16(IEEE80211_STYPE_AUTH): | ||
3135 | stats->mgmt[MANAGEMENT_AUTH]++; | ||
3136 | break; | ||
3137 | case cpu_to_le16(IEEE80211_STYPE_DEAUTH): | ||
3138 | stats->mgmt[MANAGEMENT_DEAUTH]++; | ||
3139 | break; | ||
3140 | case cpu_to_le16(IEEE80211_STYPE_ACTION): | ||
3141 | stats->mgmt[MANAGEMENT_ACTION]++; | ||
3142 | break; | ||
3143 | } | ||
3144 | } else if (ieee80211_is_ctl(fc)) { | ||
3145 | switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { | ||
3146 | case cpu_to_le16(IEEE80211_STYPE_BACK_REQ): | ||
3147 | stats->ctrl[CONTROL_BACK_REQ]++; | ||
3148 | break; | ||
3149 | case cpu_to_le16(IEEE80211_STYPE_BACK): | ||
3150 | stats->ctrl[CONTROL_BACK]++; | ||
3151 | break; | ||
3152 | case cpu_to_le16(IEEE80211_STYPE_PSPOLL): | ||
3153 | stats->ctrl[CONTROL_PSPOLL]++; | ||
3154 | break; | ||
3155 | case cpu_to_le16(IEEE80211_STYPE_RTS): | ||
3156 | stats->ctrl[CONTROL_RTS]++; | ||
3157 | break; | ||
3158 | case cpu_to_le16(IEEE80211_STYPE_CTS): | ||
3159 | stats->ctrl[CONTROL_CTS]++; | ||
3160 | break; | ||
3161 | case cpu_to_le16(IEEE80211_STYPE_ACK): | ||
3162 | stats->ctrl[CONTROL_ACK]++; | ||
3163 | break; | ||
3164 | case cpu_to_le16(IEEE80211_STYPE_CFEND): | ||
3165 | stats->ctrl[CONTROL_CFEND]++; | ||
3166 | break; | ||
3167 | case cpu_to_le16(IEEE80211_STYPE_CFENDACK): | ||
3168 | stats->ctrl[CONTROL_CFENDACK]++; | ||
3169 | break; | ||
3170 | } | ||
3171 | } else { | ||
3172 | /* data */ | ||
3173 | stats->data_cnt++; | ||
3174 | stats->data_bytes += len; | ||
3175 | } | ||
3176 | } | ||
3177 | EXPORT_SYMBOL(iwl_update_stats); | ||
3178 | #endif | ||
3179 | |||
2956 | #ifdef CONFIG_PM | 3180 | #ifdef CONFIG_PM |
2957 | 3181 | ||
2958 | int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) | 3182 | int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 10ddcdda1041..32750f4f1ce1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -83,6 +83,8 @@ struct iwl_cmd; | |||
83 | #define IWL_SKU_A 0x2 | 83 | #define IWL_SKU_A 0x2 |
84 | #define IWL_SKU_N 0x8 | 84 | #define IWL_SKU_N 0x8 |
85 | 85 | ||
86 | #define IWL_CMD(x) case x: return #x | ||
87 | |||
86 | struct iwl_hcmd_ops { | 88 | struct iwl_hcmd_ops { |
87 | int (*rxon_assoc)(struct iwl_priv *priv); | 89 | int (*rxon_assoc)(struct iwl_priv *priv); |
88 | int (*commit_rxon)(struct iwl_priv *priv); | 90 | int (*commit_rxon)(struct iwl_priv *priv); |
@@ -264,7 +266,7 @@ int iwl_full_rxon_required(struct iwl_priv *priv); | |||
264 | void iwl_set_rxon_chain(struct iwl_priv *priv); | 266 | void iwl_set_rxon_chain(struct iwl_priv *priv); |
265 | int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); | 267 | int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); |
266 | void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); | 268 | void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); |
267 | u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, | 269 | u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, |
268 | struct ieee80211_sta_ht_cap *sta_ht_inf); | 270 | struct ieee80211_sta_ht_cap *sta_ht_inf); |
269 | void iwl_set_flags_for_band(struct iwl_priv *priv, enum ieee80211_band band); | 271 | void iwl_set_flags_for_band(struct iwl_priv *priv, enum ieee80211_band band); |
270 | void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode); | 272 | void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode); |
@@ -300,7 +302,55 @@ void iwl_config_ap(struct iwl_priv *priv); | |||
300 | int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, | 302 | int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, |
301 | struct ieee80211_tx_queue_stats *stats); | 303 | struct ieee80211_tx_queue_stats *stats); |
302 | void iwl_mac_reset_tsf(struct ieee80211_hw *hw); | 304 | void iwl_mac_reset_tsf(struct ieee80211_hw *hw); |
305 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
306 | int iwl_alloc_traffic_mem(struct iwl_priv *priv); | ||
307 | void iwl_free_traffic_mem(struct iwl_priv *priv); | ||
308 | void iwl_reset_traffic_log(struct iwl_priv *priv); | ||
309 | void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, | ||
310 | u16 length, struct ieee80211_hdr *header); | ||
311 | void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, | ||
312 | u16 length, struct ieee80211_hdr *header); | ||
313 | const char *get_mgmt_string(int cmd); | ||
314 | const char *get_ctrl_string(int cmd); | ||
315 | void iwl_clear_tx_stats(struct iwl_priv *priv); | ||
316 | void iwl_clear_rx_stats(struct iwl_priv *priv); | ||
317 | void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, | ||
318 | u16 len); | ||
319 | #else | ||
320 | static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv) | ||
321 | { | ||
322 | return 0; | ||
323 | } | ||
324 | static inline void iwl_free_traffic_mem(struct iwl_priv *priv) | ||
325 | { | ||
326 | } | ||
327 | static inline void iwl_reset_traffic_log(struct iwl_priv *priv) | ||
328 | { | ||
329 | } | ||
330 | static inline void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, | ||
331 | u16 length, struct ieee80211_hdr *header) | ||
332 | { | ||
333 | } | ||
334 | static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, | ||
335 | u16 length, struct ieee80211_hdr *header) | ||
336 | { | ||
337 | } | ||
338 | static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx, | ||
339 | __le16 fc, u16 len) | ||
340 | { | ||
341 | struct traffic_stats *stats; | ||
342 | |||
343 | if (is_tx) | ||
344 | stats = &priv->tx_stats; | ||
345 | else | ||
346 | stats = &priv->rx_stats; | ||
303 | 347 | ||
348 | if (ieee80211_is_data(fc)) { | ||
349 | /* data */ | ||
350 | stats->data_bytes += len; | ||
351 | } | ||
352 | } | ||
353 | #endif | ||
304 | /***************************************************** | 354 | /***************************************************** |
305 | * RX handlers. | 355 | * RX handlers. |
306 | * **************************************************/ | 356 | * **************************************************/ |
@@ -512,8 +562,6 @@ void iwlcore_free_geos(struct iwl_priv *priv); | |||
512 | #define STATUS_POWER_PMI 16 | 562 | #define STATUS_POWER_PMI 16 |
513 | #define STATUS_FW_ERROR 17 | 563 | #define STATUS_FW_ERROR 17 |
514 | #define STATUS_MODE_PENDING 18 | 564 | #define STATUS_MODE_PENDING 18 |
515 | #define STATUS_INIT_UCODE_ALIVE 19 | ||
516 | #define STATUS_RT_UCODE_ALIVE 20 | ||
517 | 565 | ||
518 | 566 | ||
519 | static inline int iwl_is_ready(struct iwl_priv *priv) | 567 | static inline int iwl_is_ready(struct iwl_priv *priv) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index fbe177608bc7..723f38a023ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h | |||
@@ -46,7 +46,7 @@ do { \ | |||
46 | #ifdef CONFIG_IWLWIFI_DEBUG | 46 | #ifdef CONFIG_IWLWIFI_DEBUG |
47 | #define IWL_DEBUG(__priv, level, fmt, args...) \ | 47 | #define IWL_DEBUG(__priv, level, fmt, args...) \ |
48 | do { \ | 48 | do { \ |
49 | if (iwl_debug_level & (level)) \ | 49 | if (iwl_get_debug_level(__priv) & (level)) \ |
50 | dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ | 50 | dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ |
51 | "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ | 51 | "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ |
52 | __func__ , ## args); \ | 52 | __func__ , ## args); \ |
@@ -54,15 +54,15 @@ do { \ | |||
54 | 54 | ||
55 | #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \ | 55 | #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \ |
56 | do { \ | 56 | do { \ |
57 | if ((iwl_debug_level & (level)) && net_ratelimit()) \ | 57 | if ((iwl_get_debug_level(__priv) & (level)) && net_ratelimit()) \ |
58 | dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ | 58 | dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ |
59 | "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ | 59 | "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ |
60 | __func__ , ## args); \ | 60 | __func__ , ## args); \ |
61 | } while (0) | 61 | } while (0) |
62 | 62 | ||
63 | #define iwl_print_hex_dump(level, p, len) \ | 63 | #define iwl_print_hex_dump(priv, level, p, len) \ |
64 | do { \ | 64 | do { \ |
65 | if (iwl_debug_level & level) \ | 65 | if (iwl_get_debug_level(priv) & level) \ |
66 | print_hex_dump(KERN_DEBUG, "iwl data: ", \ | 66 | print_hex_dump(KERN_DEBUG, "iwl data: ", \ |
67 | DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ | 67 | DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ |
68 | } while (0) | 68 | } while (0) |
@@ -72,13 +72,12 @@ struct iwl_debugfs { | |||
72 | const char *name; | 72 | const char *name; |
73 | struct dentry *dir_drv; | 73 | struct dentry *dir_drv; |
74 | struct dentry *dir_data; | 74 | struct dentry *dir_data; |
75 | struct dentry *dir_debug; | ||
75 | struct dentry *dir_rf; | 76 | struct dentry *dir_rf; |
76 | struct dir_data_files { | 77 | struct dir_data_files { |
77 | struct dentry *file_sram; | 78 | struct dentry *file_sram; |
78 | struct dentry *file_nvm; | 79 | struct dentry *file_nvm; |
79 | struct dentry *file_stations; | 80 | struct dentry *file_stations; |
80 | struct dentry *file_rx_statistics; | ||
81 | struct dentry *file_tx_statistics; | ||
82 | struct dentry *file_log_event; | 81 | struct dentry *file_log_event; |
83 | struct dentry *file_channels; | 82 | struct dentry *file_channels; |
84 | struct dentry *file_status; | 83 | struct dentry *file_status; |
@@ -89,12 +88,26 @@ struct iwl_debugfs { | |||
89 | struct dentry *file_led; | 88 | struct dentry *file_led; |
90 | #endif | 89 | #endif |
91 | struct dentry *file_disable_ht40; | 90 | struct dentry *file_disable_ht40; |
91 | struct dentry *file_sleep_level_override; | ||
92 | struct dentry *file_current_sleep_command; | ||
92 | } dbgfs_data_files; | 93 | } dbgfs_data_files; |
93 | struct dir_rf_files { | 94 | struct dir_rf_files { |
94 | struct dentry *file_disable_sensitivity; | 95 | struct dentry *file_disable_sensitivity; |
95 | struct dentry *file_disable_chain_noise; | 96 | struct dentry *file_disable_chain_noise; |
96 | struct dentry *file_disable_tx_power; | 97 | struct dentry *file_disable_tx_power; |
97 | } dbgfs_rf_files; | 98 | } dbgfs_rf_files; |
99 | struct dir_debug_files { | ||
100 | struct dentry *file_rx_statistics; | ||
101 | struct dentry *file_tx_statistics; | ||
102 | struct dentry *file_traffic_log; | ||
103 | struct dentry *file_rx_queue; | ||
104 | struct dentry *file_tx_queue; | ||
105 | struct dentry *file_ucode_rx_stats; | ||
106 | struct dentry *file_ucode_tx_stats; | ||
107 | struct dentry *file_ucode_general_stats; | ||
108 | struct dentry *file_sensitivity; | ||
109 | struct dentry *file_chain_noise; | ||
110 | } dbgfs_debug_files; | ||
98 | u32 sram_offset; | 111 | u32 sram_offset; |
99 | u32 sram_len; | 112 | u32 sram_len; |
100 | }; | 113 | }; |
@@ -106,7 +119,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv); | |||
106 | #else | 119 | #else |
107 | #define IWL_DEBUG(__priv, level, fmt, args...) | 120 | #define IWL_DEBUG(__priv, level, fmt, args...) |
108 | #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) | 121 | #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) |
109 | static inline void iwl_print_hex_dump(int level, void *p, u32 len) | 122 | static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, |
123 | void *p, u32 len) | ||
110 | {} | 124 | {} |
111 | #endif /* CONFIG_IWLWIFI_DEBUG */ | 125 | #endif /* CONFIG_IWLWIFI_DEBUG */ |
112 | 126 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 6748a3fb9669..f68fb4711da2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c | |||
@@ -38,7 +38,7 @@ | |||
38 | #include "iwl-debug.h" | 38 | #include "iwl-debug.h" |
39 | #include "iwl-core.h" | 39 | #include "iwl-core.h" |
40 | #include "iwl-io.h" | 40 | #include "iwl-io.h" |
41 | 41 | #include "iwl-calib.h" | |
42 | 42 | ||
43 | /* create and remove of files */ | 43 | /* create and remove of files */ |
44 | #define DEBUGFS_ADD_DIR(name, parent) do { \ | 44 | #define DEBUGFS_ADD_DIR(name, parent) do { \ |
@@ -126,18 +126,58 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, | |||
126 | size_t count, loff_t *ppos) { | 126 | size_t count, loff_t *ppos) { |
127 | 127 | ||
128 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 128 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; |
129 | char buf[256]; | 129 | char *buf; |
130 | int pos = 0; | 130 | int pos = 0; |
131 | const size_t bufsz = sizeof(buf); | ||
132 | 131 | ||
133 | pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n", | 132 | int cnt; |
134 | priv->tx_stats[0].cnt); | 133 | ssize_t ret; |
135 | pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n", | 134 | const size_t bufsz = 100 + sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX); |
136 | priv->tx_stats[1].cnt); | 135 | buf = kzalloc(bufsz, GFP_KERNEL); |
137 | pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n", | 136 | if (!buf) |
138 | priv->tx_stats[2].cnt); | 137 | return -ENOMEM; |
138 | pos += scnprintf(buf + pos, bufsz - pos, "Management:\n"); | ||
139 | for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { | ||
140 | pos += scnprintf(buf + pos, bufsz - pos, | ||
141 | "\t%s\t\t: %u\n", | ||
142 | get_mgmt_string(cnt), | ||
143 | priv->tx_stats.mgmt[cnt]); | ||
144 | } | ||
145 | pos += scnprintf(buf + pos, bufsz - pos, "Control\n"); | ||
146 | for (cnt = 0; cnt < CONTROL_MAX; cnt++) { | ||
147 | pos += scnprintf(buf + pos, bufsz - pos, | ||
148 | "\t%s\t\t: %u\n", | ||
149 | get_ctrl_string(cnt), | ||
150 | priv->tx_stats.ctrl[cnt]); | ||
151 | } | ||
152 | pos += scnprintf(buf + pos, bufsz - pos, "Data:\n"); | ||
153 | pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n", | ||
154 | priv->tx_stats.data_cnt); | ||
155 | pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n", | ||
156 | priv->tx_stats.data_bytes); | ||
157 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
158 | kfree(buf); | ||
159 | return ret; | ||
160 | } | ||
139 | 161 | ||
140 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 162 | static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file, |
163 | const char __user *user_buf, | ||
164 | size_t count, loff_t *ppos) | ||
165 | { | ||
166 | struct iwl_priv *priv = file->private_data; | ||
167 | u32 clear_flag; | ||
168 | char buf[8]; | ||
169 | int buf_size; | ||
170 | |||
171 | memset(buf, 0, sizeof(buf)); | ||
172 | buf_size = min(count, sizeof(buf) - 1); | ||
173 | if (copy_from_user(buf, user_buf, buf_size)) | ||
174 | return -EFAULT; | ||
175 | if (sscanf(buf, "%x", &clear_flag) != 1) | ||
176 | return -EFAULT; | ||
177 | if (clear_flag == 1) | ||
178 | iwl_clear_tx_stats(priv); | ||
179 | |||
180 | return count; | ||
141 | } | 181 | } |
142 | 182 | ||
143 | static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, | 183 | static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, |
@@ -145,18 +185,59 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, | |||
145 | size_t count, loff_t *ppos) { | 185 | size_t count, loff_t *ppos) { |
146 | 186 | ||
147 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 187 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; |
148 | char buf[256]; | 188 | char *buf; |
149 | int pos = 0; | 189 | int pos = 0; |
150 | const size_t bufsz = sizeof(buf); | 190 | int cnt; |
191 | ssize_t ret; | ||
192 | const size_t bufsz = 100 + | ||
193 | sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX); | ||
194 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
195 | if (!buf) | ||
196 | return -ENOMEM; | ||
151 | 197 | ||
152 | pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n", | 198 | pos += scnprintf(buf + pos, bufsz - pos, "Management:\n"); |
153 | priv->rx_stats[0].cnt); | 199 | for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { |
154 | pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n", | 200 | pos += scnprintf(buf + pos, bufsz - pos, |
155 | priv->rx_stats[1].cnt); | 201 | "\t%s\t\t: %u\n", |
156 | pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n", | 202 | get_mgmt_string(cnt), |
157 | priv->rx_stats[2].cnt); | 203 | priv->rx_stats.mgmt[cnt]); |
204 | } | ||
205 | pos += scnprintf(buf + pos, bufsz - pos, "Control:\n"); | ||
206 | for (cnt = 0; cnt < CONTROL_MAX; cnt++) { | ||
207 | pos += scnprintf(buf + pos, bufsz - pos, | ||
208 | "\t%s\t\t: %u\n", | ||
209 | get_ctrl_string(cnt), | ||
210 | priv->rx_stats.ctrl[cnt]); | ||
211 | } | ||
212 | pos += scnprintf(buf + pos, bufsz - pos, "Data:\n"); | ||
213 | pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n", | ||
214 | priv->rx_stats.data_cnt); | ||
215 | pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n", | ||
216 | priv->rx_stats.data_bytes); | ||
158 | 217 | ||
159 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 218 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
219 | kfree(buf); | ||
220 | return ret; | ||
221 | } | ||
222 | |||
223 | static ssize_t iwl_dbgfs_rx_statistics_write(struct file *file, | ||
224 | const char __user *user_buf, | ||
225 | size_t count, loff_t *ppos) | ||
226 | { | ||
227 | struct iwl_priv *priv = file->private_data; | ||
228 | u32 clear_flag; | ||
229 | char buf[8]; | ||
230 | int buf_size; | ||
231 | |||
232 | memset(buf, 0, sizeof(buf)); | ||
233 | buf_size = min(count, sizeof(buf) - 1); | ||
234 | if (copy_from_user(buf, user_buf, buf_size)) | ||
235 | return -EFAULT; | ||
236 | if (sscanf(buf, "%x", &clear_flag) != 1) | ||
237 | return -EFAULT; | ||
238 | if (clear_flag == 1) | ||
239 | iwl_clear_rx_stats(priv); | ||
240 | return count; | ||
160 | } | 241 | } |
161 | 242 | ||
162 | #define BYTE1_MASK 0x000000ff; | 243 | #define BYTE1_MASK 0x000000ff; |
@@ -623,7 +704,7 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, | |||
623 | size_t count, loff_t *ppos) | 704 | size_t count, loff_t *ppos) |
624 | { | 705 | { |
625 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 706 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; |
626 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | 707 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
627 | struct iwl_tt_restriction *restriction; | 708 | struct iwl_tt_restriction *restriction; |
628 | char buf[100]; | 709 | char buf[100]; |
629 | int pos = 0; | 710 | int pos = 0; |
@@ -632,12 +713,11 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, | |||
632 | 713 | ||
633 | pos += scnprintf(buf + pos, bufsz - pos, | 714 | pos += scnprintf(buf + pos, bufsz - pos, |
634 | "Thermal Throttling Mode: %s\n", | 715 | "Thermal Throttling Mode: %s\n", |
635 | (priv->power_data.adv_tt) | 716 | tt->advanced_tt ? "Advance" : "Legacy"); |
636 | ? "Advance" : "Legacy"); | ||
637 | pos += scnprintf(buf + pos, bufsz - pos, | 717 | pos += scnprintf(buf + pos, bufsz - pos, |
638 | "Thermal Throttling State: %d\n", | 718 | "Thermal Throttling State: %d\n", |
639 | tt->state); | 719 | tt->state); |
640 | if (priv->power_data.adv_tt) { | 720 | if (tt->advanced_tt) { |
641 | restriction = tt->restriction + tt->state; | 721 | restriction = tt->restriction + tt->state; |
642 | pos += scnprintf(buf + pos, bufsz - pos, | 722 | pos += scnprintf(buf + pos, bufsz - pos, |
643 | "Tx mode: %d\n", | 723 | "Tx mode: %d\n", |
@@ -696,12 +776,87 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file, | |||
696 | return ret; | 776 | return ret; |
697 | } | 777 | } |
698 | 778 | ||
779 | static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file, | ||
780 | const char __user *user_buf, | ||
781 | size_t count, loff_t *ppos) | ||
782 | { | ||
783 | struct iwl_priv *priv = file->private_data; | ||
784 | char buf[8]; | ||
785 | int buf_size; | ||
786 | int value; | ||
787 | |||
788 | memset(buf, 0, sizeof(buf)); | ||
789 | buf_size = min(count, sizeof(buf) - 1); | ||
790 | if (copy_from_user(buf, user_buf, buf_size)) | ||
791 | return -EFAULT; | ||
792 | |||
793 | if (sscanf(buf, "%d", &value) != 1) | ||
794 | return -EINVAL; | ||
795 | |||
796 | /* | ||
797 | * Our users expect 0 to be "CAM", but 0 isn't actually | ||
798 | * valid here. However, let's not confuse them and present | ||
799 | * IWL_POWER_INDEX_1 as "1", not "0". | ||
800 | */ | ||
801 | if (value > 0) | ||
802 | value -= 1; | ||
803 | |||
804 | if (value != -1 && (value < 0 || value >= IWL_POWER_NUM)) | ||
805 | return -EINVAL; | ||
806 | |||
807 | priv->power_data.debug_sleep_level_override = value; | ||
808 | |||
809 | iwl_power_update_mode(priv, false); | ||
810 | |||
811 | return count; | ||
812 | } | ||
813 | |||
814 | static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file, | ||
815 | char __user *user_buf, | ||
816 | size_t count, loff_t *ppos) | ||
817 | { | ||
818 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | ||
819 | char buf[10]; | ||
820 | int pos, value; | ||
821 | const size_t bufsz = sizeof(buf); | ||
822 | |||
823 | /* see the write function */ | ||
824 | value = priv->power_data.debug_sleep_level_override; | ||
825 | if (value >= 0) | ||
826 | value += 1; | ||
827 | |||
828 | pos = scnprintf(buf, bufsz, "%d\n", value); | ||
829 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
830 | } | ||
831 | |||
832 | static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file, | ||
833 | char __user *user_buf, | ||
834 | size_t count, loff_t *ppos) | ||
835 | { | ||
836 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | ||
837 | char buf[200]; | ||
838 | int pos = 0, i; | ||
839 | const size_t bufsz = sizeof(buf); | ||
840 | struct iwl_powertable_cmd *cmd = &priv->power_data.sleep_cmd; | ||
841 | |||
842 | pos += scnprintf(buf + pos, bufsz - pos, | ||
843 | "flags: %#.2x\n", le16_to_cpu(cmd->flags)); | ||
844 | pos += scnprintf(buf + pos, bufsz - pos, | ||
845 | "RX/TX timeout: %d/%d usec\n", | ||
846 | le32_to_cpu(cmd->rx_data_timeout), | ||
847 | le32_to_cpu(cmd->tx_data_timeout)); | ||
848 | for (i = 0; i < IWL_POWER_VEC_SIZE; i++) | ||
849 | pos += scnprintf(buf + pos, bufsz - pos, | ||
850 | "sleep_interval[%d]: %d\n", i, | ||
851 | le32_to_cpu(cmd->sleep_interval[i])); | ||
852 | |||
853 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
854 | } | ||
855 | |||
699 | DEBUGFS_READ_WRITE_FILE_OPS(sram); | 856 | DEBUGFS_READ_WRITE_FILE_OPS(sram); |
700 | DEBUGFS_WRITE_FILE_OPS(log_event); | 857 | DEBUGFS_WRITE_FILE_OPS(log_event); |
701 | DEBUGFS_READ_FILE_OPS(nvm); | 858 | DEBUGFS_READ_FILE_OPS(nvm); |
702 | DEBUGFS_READ_FILE_OPS(stations); | 859 | DEBUGFS_READ_FILE_OPS(stations); |
703 | DEBUGFS_READ_FILE_OPS(rx_statistics); | ||
704 | DEBUGFS_READ_FILE_OPS(tx_statistics); | ||
705 | DEBUGFS_READ_FILE_OPS(channels); | 860 | DEBUGFS_READ_FILE_OPS(channels); |
706 | DEBUGFS_READ_FILE_OPS(status); | 861 | DEBUGFS_READ_FILE_OPS(status); |
707 | DEBUGFS_READ_WRITE_FILE_OPS(interrupt); | 862 | DEBUGFS_READ_WRITE_FILE_OPS(interrupt); |
@@ -711,6 +866,713 @@ DEBUGFS_READ_FILE_OPS(led); | |||
711 | #endif | 866 | #endif |
712 | DEBUGFS_READ_FILE_OPS(thermal_throttling); | 867 | DEBUGFS_READ_FILE_OPS(thermal_throttling); |
713 | DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); | 868 | DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); |
869 | DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override); | ||
870 | DEBUGFS_READ_FILE_OPS(current_sleep_command); | ||
871 | |||
872 | static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, | ||
873 | char __user *user_buf, | ||
874 | size_t count, loff_t *ppos) | ||
875 | { | ||
876 | struct iwl_priv *priv = file->private_data; | ||
877 | int pos = 0, ofs = 0; | ||
878 | int cnt = 0, entry; | ||
879 | struct iwl_tx_queue *txq; | ||
880 | struct iwl_queue *q; | ||
881 | struct iwl_rx_queue *rxq = &priv->rxq; | ||
882 | char *buf; | ||
883 | int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) + | ||
884 | (IWL_MAX_NUM_QUEUES * 32 * 8) + 400; | ||
885 | const u8 *ptr; | ||
886 | ssize_t ret; | ||
887 | |||
888 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
889 | if (!buf) { | ||
890 | IWL_ERR(priv, "Can not allocate buffer\n"); | ||
891 | return -ENOMEM; | ||
892 | } | ||
893 | pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n"); | ||
894 | for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { | ||
895 | txq = &priv->txq[cnt]; | ||
896 | q = &txq->q; | ||
897 | pos += scnprintf(buf + pos, bufsz - pos, | ||
898 | "q[%d]: read_ptr: %u, write_ptr: %u\n", | ||
899 | cnt, q->read_ptr, q->write_ptr); | ||
900 | } | ||
901 | if (priv->tx_traffic && (iwl_debug_level & IWL_DL_TX)) { | ||
902 | ptr = priv->tx_traffic; | ||
903 | pos += scnprintf(buf + pos, bufsz - pos, | ||
904 | "Tx Traffic idx: %u\n", priv->tx_traffic_idx); | ||
905 | for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) { | ||
906 | for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16; | ||
907 | entry++, ofs += 16) { | ||
908 | pos += scnprintf(buf + pos, bufsz - pos, | ||
909 | "0x%.4x ", ofs); | ||
910 | hex_dump_to_buffer(ptr + ofs, 16, 16, 2, | ||
911 | buf + pos, bufsz - pos, 0); | ||
912 | pos += strlen(buf); | ||
913 | if (bufsz - pos > 0) | ||
914 | buf[pos++] = '\n'; | ||
915 | } | ||
916 | } | ||
917 | } | ||
918 | |||
919 | pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n"); | ||
920 | pos += scnprintf(buf + pos, bufsz - pos, | ||
921 | "read: %u, write: %u\n", | ||
922 | rxq->read, rxq->write); | ||
923 | |||
924 | if (priv->rx_traffic && (iwl_debug_level & IWL_DL_RX)) { | ||
925 | ptr = priv->rx_traffic; | ||
926 | pos += scnprintf(buf + pos, bufsz - pos, | ||
927 | "Rx Traffic idx: %u\n", priv->rx_traffic_idx); | ||
928 | for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) { | ||
929 | for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16; | ||
930 | entry++, ofs += 16) { | ||
931 | pos += scnprintf(buf + pos, bufsz - pos, | ||
932 | "0x%.4x ", ofs); | ||
933 | hex_dump_to_buffer(ptr + ofs, 16, 16, 2, | ||
934 | buf + pos, bufsz - pos, 0); | ||
935 | pos += strlen(buf); | ||
936 | if (bufsz - pos > 0) | ||
937 | buf[pos++] = '\n'; | ||
938 | } | ||
939 | } | ||
940 | } | ||
941 | |||
942 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
943 | kfree(buf); | ||
944 | return ret; | ||
945 | } | ||
946 | |||
947 | static ssize_t iwl_dbgfs_traffic_log_write(struct file *file, | ||
948 | const char __user *user_buf, | ||
949 | size_t count, loff_t *ppos) | ||
950 | { | ||
951 | struct iwl_priv *priv = file->private_data; | ||
952 | char buf[8]; | ||
953 | int buf_size; | ||
954 | int traffic_log; | ||
955 | |||
956 | memset(buf, 0, sizeof(buf)); | ||
957 | buf_size = min(count, sizeof(buf) - 1); | ||
958 | if (copy_from_user(buf, user_buf, buf_size)) | ||
959 | return -EFAULT; | ||
960 | if (sscanf(buf, "%d", &traffic_log) != 1) | ||
961 | return -EFAULT; | ||
962 | if (traffic_log == 0) | ||
963 | iwl_reset_traffic_log(priv); | ||
964 | |||
965 | return count; | ||
966 | } | ||
967 | |||
968 | static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, | ||
969 | char __user *user_buf, | ||
970 | size_t count, loff_t *ppos) { | ||
971 | |||
972 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | ||
973 | struct iwl_tx_queue *txq; | ||
974 | struct iwl_queue *q; | ||
975 | char *buf; | ||
976 | int pos = 0; | ||
977 | int cnt; | ||
978 | int ret; | ||
979 | const size_t bufsz = sizeof(char) * 60 * IWL_MAX_NUM_QUEUES; | ||
980 | |||
981 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
982 | if (!buf) | ||
983 | return -ENOMEM; | ||
984 | |||
985 | for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { | ||
986 | txq = &priv->txq[cnt]; | ||
987 | q = &txq->q; | ||
988 | pos += scnprintf(buf + pos, bufsz - pos, | ||
989 | "hwq %.2d: read=%u write=%u stop=%d" | ||
990 | " swq_id=%#.2x (ac %d/hwq %d)\n", | ||
991 | cnt, q->read_ptr, q->write_ptr, | ||
992 | !!test_bit(cnt, priv->queue_stopped), | ||
993 | txq->swq_id, | ||
994 | txq->swq_id & 0x80 ? txq->swq_id & 3 : | ||
995 | txq->swq_id, | ||
996 | txq->swq_id & 0x80 ? (txq->swq_id >> 2) & | ||
997 | 0x1f : txq->swq_id); | ||
998 | if (cnt >= 4) | ||
999 | continue; | ||
1000 | /* for the ACs, display the stop count too */ | ||
1001 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1002 | " stop-count: %d\n", | ||
1003 | atomic_read(&priv->queue_stop_count[cnt])); | ||
1004 | } | ||
1005 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
1006 | kfree(buf); | ||
1007 | return ret; | ||
1008 | } | ||
1009 | |||
1010 | static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, | ||
1011 | char __user *user_buf, | ||
1012 | size_t count, loff_t *ppos) { | ||
1013 | |||
1014 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | ||
1015 | struct iwl_rx_queue *rxq = &priv->rxq; | ||
1016 | char buf[256]; | ||
1017 | int pos = 0; | ||
1018 | const size_t bufsz = sizeof(buf); | ||
1019 | |||
1020 | pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n", | ||
1021 | rxq->read); | ||
1022 | pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n", | ||
1023 | rxq->write); | ||
1024 | pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n", | ||
1025 | rxq->free_count); | ||
1026 | pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n", | ||
1027 | le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF); | ||
1028 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
1029 | } | ||
1030 | |||
1031 | #define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0) | ||
1032 | #define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1) | ||
1033 | #define UCODE_STATISTICS_NARROW_BAND_MSK (0x1 << 2) | ||
1034 | |||
1035 | static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf, | ||
1036 | int bufsz) | ||
1037 | { | ||
1038 | int p = 0; | ||
1039 | |||
1040 | p += scnprintf(buf + p, bufsz - p, | ||
1041 | "Statistics Flag(0x%X):\n", | ||
1042 | le32_to_cpu(priv->statistics.flag)); | ||
1043 | if (le32_to_cpu(priv->statistics.flag) & UCODE_STATISTICS_CLEAR_MSK) | ||
1044 | p += scnprintf(buf + p, bufsz - p, | ||
1045 | "\tStatistics have been cleared\n"); | ||
1046 | p += scnprintf(buf + p, bufsz - p, | ||
1047 | "\tOperational Frequency: %s\n", | ||
1048 | (le32_to_cpu(priv->statistics.flag) & | ||
1049 | UCODE_STATISTICS_FREQUENCY_MSK) | ||
1050 | ? "2.4 GHz" : "5.2 GHz"); | ||
1051 | p += scnprintf(buf + p, bufsz - p, | ||
1052 | "\tTGj Narrow Band: %s\n", | ||
1053 | (le32_to_cpu(priv->statistics.flag) & | ||
1054 | UCODE_STATISTICS_NARROW_BAND_MSK) | ||
1055 | ? "enabled" : "disabled"); | ||
1056 | return p; | ||
1057 | } | ||
1058 | |||
1059 | |||
1060 | static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, | ||
1061 | char __user *user_buf, | ||
1062 | size_t count, loff_t *ppos) | ||
1063 | { | ||
1064 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | ||
1065 | int pos = 0; | ||
1066 | char *buf; | ||
1067 | int bufsz = sizeof(struct statistics_rx_phy) * 20 + | ||
1068 | sizeof(struct statistics_rx_non_phy) * 20 + | ||
1069 | sizeof(struct statistics_rx_ht_phy) * 20 + 400; | ||
1070 | ssize_t ret; | ||
1071 | struct statistics_rx_phy *ofdm; | ||
1072 | struct statistics_rx_phy *cck; | ||
1073 | struct statistics_rx_non_phy *general; | ||
1074 | struct statistics_rx_ht_phy *ht; | ||
1075 | |||
1076 | if (!iwl_is_alive(priv)) | ||
1077 | return -EAGAIN; | ||
1078 | |||
1079 | /* make request to uCode to retrieve statistics information */ | ||
1080 | mutex_lock(&priv->mutex); | ||
1081 | ret = iwl_send_statistics_request(priv, 0); | ||
1082 | mutex_unlock(&priv->mutex); | ||
1083 | |||
1084 | if (ret) { | ||
1085 | IWL_ERR(priv, | ||
1086 | "Error sending statistics request: %zd\n", ret); | ||
1087 | return -EAGAIN; | ||
1088 | } | ||
1089 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
1090 | if (!buf) { | ||
1091 | IWL_ERR(priv, "Can not allocate Buffer\n"); | ||
1092 | return -ENOMEM; | ||
1093 | } | ||
1094 | |||
1095 | /* the statistic information display here is based on | ||
1096 | * the last statistics notification from uCode | ||
1097 | * might not reflect the current uCode activity | ||
1098 | */ | ||
1099 | ofdm = &priv->statistics.rx.ofdm; | ||
1100 | cck = &priv->statistics.rx.cck; | ||
1101 | general = &priv->statistics.rx.general; | ||
1102 | ht = &priv->statistics.rx.ofdm_ht; | ||
1103 | pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); | ||
1104 | pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n"); | ||
1105 | pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n", | ||
1106 | le32_to_cpu(ofdm->ina_cnt)); | ||
1107 | pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n", | ||
1108 | le32_to_cpu(ofdm->fina_cnt)); | ||
1109 | pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", | ||
1110 | le32_to_cpu(ofdm->plcp_err)); | ||
1111 | pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", | ||
1112 | le32_to_cpu(ofdm->crc32_err)); | ||
1113 | pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", | ||
1114 | le32_to_cpu(ofdm->overrun_err)); | ||
1115 | pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", | ||
1116 | le32_to_cpu(ofdm->early_overrun_err)); | ||
1117 | pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", | ||
1118 | le32_to_cpu(ofdm->crc32_good)); | ||
1119 | pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n", | ||
1120 | le32_to_cpu(ofdm->false_alarm_cnt)); | ||
1121 | pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n", | ||
1122 | le32_to_cpu(ofdm->fina_sync_err_cnt)); | ||
1123 | pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n", | ||
1124 | le32_to_cpu(ofdm->sfd_timeout)); | ||
1125 | pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n", | ||
1126 | le32_to_cpu(ofdm->fina_timeout)); | ||
1127 | pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n", | ||
1128 | le32_to_cpu(ofdm->unresponded_rts)); | ||
1129 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1130 | "rxe_frame_limit_overrun: %u\n", | ||
1131 | le32_to_cpu(ofdm->rxe_frame_limit_overrun)); | ||
1132 | pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n", | ||
1133 | le32_to_cpu(ofdm->sent_ack_cnt)); | ||
1134 | pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n", | ||
1135 | le32_to_cpu(ofdm->sent_cts_cnt)); | ||
1136 | pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n", | ||
1137 | le32_to_cpu(ofdm->sent_ba_rsp_cnt)); | ||
1138 | pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n", | ||
1139 | le32_to_cpu(ofdm->dsp_self_kill)); | ||
1140 | pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", | ||
1141 | le32_to_cpu(ofdm->mh_format_err)); | ||
1142 | pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n", | ||
1143 | le32_to_cpu(ofdm->re_acq_main_rssi_sum)); | ||
1144 | |||
1145 | pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n"); | ||
1146 | pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n", | ||
1147 | le32_to_cpu(cck->ina_cnt)); | ||
1148 | pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n", | ||
1149 | le32_to_cpu(cck->fina_cnt)); | ||
1150 | pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", | ||
1151 | le32_to_cpu(cck->plcp_err)); | ||
1152 | pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", | ||
1153 | le32_to_cpu(cck->crc32_err)); | ||
1154 | pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", | ||
1155 | le32_to_cpu(cck->overrun_err)); | ||
1156 | pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", | ||
1157 | le32_to_cpu(cck->early_overrun_err)); | ||
1158 | pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", | ||
1159 | le32_to_cpu(cck->crc32_good)); | ||
1160 | pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n", | ||
1161 | le32_to_cpu(cck->false_alarm_cnt)); | ||
1162 | pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n", | ||
1163 | le32_to_cpu(cck->fina_sync_err_cnt)); | ||
1164 | pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n", | ||
1165 | le32_to_cpu(cck->sfd_timeout)); | ||
1166 | pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n", | ||
1167 | le32_to_cpu(cck->fina_timeout)); | ||
1168 | pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n", | ||
1169 | le32_to_cpu(cck->unresponded_rts)); | ||
1170 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1171 | "rxe_frame_limit_overrun: %u\n", | ||
1172 | le32_to_cpu(cck->rxe_frame_limit_overrun)); | ||
1173 | pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n", | ||
1174 | le32_to_cpu(cck->sent_ack_cnt)); | ||
1175 | pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n", | ||
1176 | le32_to_cpu(cck->sent_cts_cnt)); | ||
1177 | pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n", | ||
1178 | le32_to_cpu(cck->sent_ba_rsp_cnt)); | ||
1179 | pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n", | ||
1180 | le32_to_cpu(cck->dsp_self_kill)); | ||
1181 | pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", | ||
1182 | le32_to_cpu(cck->mh_format_err)); | ||
1183 | pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n", | ||
1184 | le32_to_cpu(cck->re_acq_main_rssi_sum)); | ||
1185 | |||
1186 | pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n"); | ||
1187 | pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts: %u\n", | ||
1188 | le32_to_cpu(general->bogus_cts)); | ||
1189 | pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack: %u\n", | ||
1190 | le32_to_cpu(general->bogus_ack)); | ||
1191 | pos += scnprintf(buf + pos, bufsz - pos, "non_bssid_frames: %u\n", | ||
1192 | le32_to_cpu(general->non_bssid_frames)); | ||
1193 | pos += scnprintf(buf + pos, bufsz - pos, "filtered_frames: %u\n", | ||
1194 | le32_to_cpu(general->filtered_frames)); | ||
1195 | pos += scnprintf(buf + pos, bufsz - pos, "non_channel_beacons: %u\n", | ||
1196 | le32_to_cpu(general->non_channel_beacons)); | ||
1197 | pos += scnprintf(buf + pos, bufsz - pos, "channel_beacons: %u\n", | ||
1198 | le32_to_cpu(general->channel_beacons)); | ||
1199 | pos += scnprintf(buf + pos, bufsz - pos, "num_missed_bcon: %u\n", | ||
1200 | le32_to_cpu(general->num_missed_bcon)); | ||
1201 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1202 | "adc_rx_saturation_time: %u\n", | ||
1203 | le32_to_cpu(general->adc_rx_saturation_time)); | ||
1204 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1205 | "ina_detection_search_time: %u\n", | ||
1206 | le32_to_cpu(general->ina_detection_search_time)); | ||
1207 | pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_a: %u\n", | ||
1208 | le32_to_cpu(general->beacon_silence_rssi_a)); | ||
1209 | pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_b: %u\n", | ||
1210 | le32_to_cpu(general->beacon_silence_rssi_b)); | ||
1211 | pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_c: %u\n", | ||
1212 | le32_to_cpu(general->beacon_silence_rssi_c)); | ||
1213 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1214 | "interference_data_flag: %u\n", | ||
1215 | le32_to_cpu(general->interference_data_flag)); | ||
1216 | pos += scnprintf(buf + pos, bufsz - pos, "channel_load: %u\n", | ||
1217 | le32_to_cpu(general->channel_load)); | ||
1218 | pos += scnprintf(buf + pos, bufsz - pos, "dsp_false_alarms: %u\n", | ||
1219 | le32_to_cpu(general->dsp_false_alarms)); | ||
1220 | pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_a: %u\n", | ||
1221 | le32_to_cpu(general->beacon_rssi_a)); | ||
1222 | pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_b: %u\n", | ||
1223 | le32_to_cpu(general->beacon_rssi_b)); | ||
1224 | pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_c: %u\n", | ||
1225 | le32_to_cpu(general->beacon_rssi_c)); | ||
1226 | pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_a: %u\n", | ||
1227 | le32_to_cpu(general->beacon_energy_a)); | ||
1228 | pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_b: %u\n", | ||
1229 | le32_to_cpu(general->beacon_energy_b)); | ||
1230 | pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_c: %u\n", | ||
1231 | le32_to_cpu(general->beacon_energy_c)); | ||
1232 | |||
1233 | pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n"); | ||
1234 | pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", | ||
1235 | le32_to_cpu(ht->plcp_err)); | ||
1236 | pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", | ||
1237 | le32_to_cpu(ht->overrun_err)); | ||
1238 | pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", | ||
1239 | le32_to_cpu(ht->early_overrun_err)); | ||
1240 | pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", | ||
1241 | le32_to_cpu(ht->crc32_good)); | ||
1242 | pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", | ||
1243 | le32_to_cpu(ht->crc32_err)); | ||
1244 | pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", | ||
1245 | le32_to_cpu(ht->mh_format_err)); | ||
1246 | pos += scnprintf(buf + pos, bufsz - pos, "agg_crc32_good: %u\n", | ||
1247 | le32_to_cpu(ht->agg_crc32_good)); | ||
1248 | pos += scnprintf(buf + pos, bufsz - pos, "agg_mpdu_cnt: %u\n", | ||
1249 | le32_to_cpu(ht->agg_mpdu_cnt)); | ||
1250 | pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt: %u\n", | ||
1251 | le32_to_cpu(ht->agg_cnt)); | ||
1252 | |||
1253 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
1254 | kfree(buf); | ||
1255 | return ret; | ||
1256 | } | ||
1257 | |||
1258 | static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, | ||
1259 | char __user *user_buf, | ||
1260 | size_t count, loff_t *ppos) | ||
1261 | { | ||
1262 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | ||
1263 | int pos = 0; | ||
1264 | char *buf; | ||
1265 | int bufsz = (sizeof(struct statistics_tx) * 24) + 250; | ||
1266 | ssize_t ret; | ||
1267 | struct statistics_tx *tx; | ||
1268 | |||
1269 | if (!iwl_is_alive(priv)) | ||
1270 | return -EAGAIN; | ||
1271 | |||
1272 | /* make request to uCode to retrieve statistics information */ | ||
1273 | mutex_lock(&priv->mutex); | ||
1274 | ret = iwl_send_statistics_request(priv, 0); | ||
1275 | mutex_unlock(&priv->mutex); | ||
1276 | |||
1277 | if (ret) { | ||
1278 | IWL_ERR(priv, | ||
1279 | "Error sending statistics request: %zd\n", ret); | ||
1280 | return -EAGAIN; | ||
1281 | } | ||
1282 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
1283 | if (!buf) { | ||
1284 | IWL_ERR(priv, "Can not allocate Buffer\n"); | ||
1285 | return -ENOMEM; | ||
1286 | } | ||
1287 | |||
1288 | /* the statistic information display here is based on | ||
1289 | * the last statistics notification from uCode | ||
1290 | * might not reflect the current uCode activity | ||
1291 | */ | ||
1292 | tx = &priv->statistics.tx; | ||
1293 | pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); | ||
1294 | pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n"); | ||
1295 | pos += scnprintf(buf + pos, bufsz - pos, "preamble: %u\n", | ||
1296 | le32_to_cpu(tx->preamble_cnt)); | ||
1297 | pos += scnprintf(buf + pos, bufsz - pos, "rx_detected_cnt: %u\n", | ||
1298 | le32_to_cpu(tx->rx_detected_cnt)); | ||
1299 | pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_defer_cnt: %u\n", | ||
1300 | le32_to_cpu(tx->bt_prio_defer_cnt)); | ||
1301 | pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_kill_cnt: %u\n", | ||
1302 | le32_to_cpu(tx->bt_prio_kill_cnt)); | ||
1303 | pos += scnprintf(buf + pos, bufsz - pos, "few_bytes_cnt: %u\n", | ||
1304 | le32_to_cpu(tx->few_bytes_cnt)); | ||
1305 | pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout: %u\n", | ||
1306 | le32_to_cpu(tx->cts_timeout)); | ||
1307 | pos += scnprintf(buf + pos, bufsz - pos, "ack_timeout: %u\n", | ||
1308 | le32_to_cpu(tx->ack_timeout)); | ||
1309 | pos += scnprintf(buf + pos, bufsz - pos, "expected_ack_cnt: %u\n", | ||
1310 | le32_to_cpu(tx->expected_ack_cnt)); | ||
1311 | pos += scnprintf(buf + pos, bufsz - pos, "actual_ack_cnt: %u\n", | ||
1312 | le32_to_cpu(tx->actual_ack_cnt)); | ||
1313 | pos += scnprintf(buf + pos, bufsz - pos, "dump_msdu_cnt: %u\n", | ||
1314 | le32_to_cpu(tx->dump_msdu_cnt)); | ||
1315 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1316 | "burst_abort_next_frame_mismatch_cnt: %u\n", | ||
1317 | le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt)); | ||
1318 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1319 | "burst_abort_missing_next_frame_cnt: %u\n", | ||
1320 | le32_to_cpu(tx->burst_abort_missing_next_frame_cnt)); | ||
1321 | pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout_collision: %u\n", | ||
1322 | le32_to_cpu(tx->cts_timeout_collision)); | ||
1323 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1324 | "ack_or_ba_timeout_collision: %u\n", | ||
1325 | le32_to_cpu(tx->ack_or_ba_timeout_collision)); | ||
1326 | pos += scnprintf(buf + pos, bufsz - pos, "agg ba_timeout: %u\n", | ||
1327 | le32_to_cpu(tx->agg.ba_timeout)); | ||
1328 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1329 | "agg ba_reschedule_frames: %u\n", | ||
1330 | le32_to_cpu(tx->agg.ba_reschedule_frames)); | ||
1331 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1332 | "agg scd_query_agg_frame_cnt: %u\n", | ||
1333 | le32_to_cpu(tx->agg.scd_query_agg_frame_cnt)); | ||
1334 | pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_no_agg: %u\n", | ||
1335 | le32_to_cpu(tx->agg.scd_query_no_agg)); | ||
1336 | pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_agg: %u\n", | ||
1337 | le32_to_cpu(tx->agg.scd_query_agg)); | ||
1338 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1339 | "agg scd_query_mismatch: %u\n", | ||
1340 | le32_to_cpu(tx->agg.scd_query_mismatch)); | ||
1341 | pos += scnprintf(buf + pos, bufsz - pos, "agg frame_not_ready: %u\n", | ||
1342 | le32_to_cpu(tx->agg.frame_not_ready)); | ||
1343 | pos += scnprintf(buf + pos, bufsz - pos, "agg underrun: %u\n", | ||
1344 | le32_to_cpu(tx->agg.underrun)); | ||
1345 | pos += scnprintf(buf + pos, bufsz - pos, "agg bt_prio_kill: %u\n", | ||
1346 | le32_to_cpu(tx->agg.bt_prio_kill)); | ||
1347 | pos += scnprintf(buf + pos, bufsz - pos, "agg rx_ba_rsp_cnt: %u\n", | ||
1348 | le32_to_cpu(tx->agg.rx_ba_rsp_cnt)); | ||
1349 | |||
1350 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
1351 | kfree(buf); | ||
1352 | return ret; | ||
1353 | } | ||
1354 | |||
1355 | static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, | ||
1356 | char __user *user_buf, | ||
1357 | size_t count, loff_t *ppos) | ||
1358 | { | ||
1359 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | ||
1360 | int pos = 0; | ||
1361 | char *buf; | ||
1362 | int bufsz = sizeof(struct statistics_general) * 4 + 250; | ||
1363 | ssize_t ret; | ||
1364 | struct statistics_general *general; | ||
1365 | struct statistics_dbg *dbg; | ||
1366 | struct statistics_div *div; | ||
1367 | |||
1368 | if (!iwl_is_alive(priv)) | ||
1369 | return -EAGAIN; | ||
1370 | |||
1371 | /* make request to uCode to retrieve statistics information */ | ||
1372 | mutex_lock(&priv->mutex); | ||
1373 | ret = iwl_send_statistics_request(priv, 0); | ||
1374 | mutex_unlock(&priv->mutex); | ||
1375 | |||
1376 | if (ret) { | ||
1377 | IWL_ERR(priv, | ||
1378 | "Error sending statistics request: %zd\n", ret); | ||
1379 | return -EAGAIN; | ||
1380 | } | ||
1381 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
1382 | if (!buf) { | ||
1383 | IWL_ERR(priv, "Can not allocate Buffer\n"); | ||
1384 | return -ENOMEM; | ||
1385 | } | ||
1386 | |||
1387 | /* the statistic information display here is based on | ||
1388 | * the last statistics notification from uCode | ||
1389 | * might not reflect the current uCode activity | ||
1390 | */ | ||
1391 | general = &priv->statistics.general; | ||
1392 | dbg = &priv->statistics.general.dbg; | ||
1393 | div = &priv->statistics.general.div; | ||
1394 | pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); | ||
1395 | pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n"); | ||
1396 | pos += scnprintf(buf + pos, bufsz - pos, "temperature: %u\n", | ||
1397 | le32_to_cpu(general->temperature)); | ||
1398 | pos += scnprintf(buf + pos, bufsz - pos, "temperature_m: %u\n", | ||
1399 | le32_to_cpu(general->temperature_m)); | ||
1400 | pos += scnprintf(buf + pos, bufsz - pos, "burst_check: %u\n", | ||
1401 | le32_to_cpu(dbg->burst_check)); | ||
1402 | pos += scnprintf(buf + pos, bufsz - pos, "burst_count: %u\n", | ||
1403 | le32_to_cpu(dbg->burst_count)); | ||
1404 | pos += scnprintf(buf + pos, bufsz - pos, "sleep_time: %u\n", | ||
1405 | le32_to_cpu(general->sleep_time)); | ||
1406 | pos += scnprintf(buf + pos, bufsz - pos, "slots_out: %u\n", | ||
1407 | le32_to_cpu(general->slots_out)); | ||
1408 | pos += scnprintf(buf + pos, bufsz - pos, "slots_idle: %u\n", | ||
1409 | le32_to_cpu(general->slots_idle)); | ||
1410 | pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp: %u\n", | ||
1411 | le32_to_cpu(general->ttl_timestamp)); | ||
1412 | pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a: %u\n", | ||
1413 | le32_to_cpu(div->tx_on_a)); | ||
1414 | pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b: %u\n", | ||
1415 | le32_to_cpu(div->tx_on_b)); | ||
1416 | pos += scnprintf(buf + pos, bufsz - pos, "exec_time: %u\n", | ||
1417 | le32_to_cpu(div->exec_time)); | ||
1418 | pos += scnprintf(buf + pos, bufsz - pos, "probe_time: %u\n", | ||
1419 | le32_to_cpu(div->probe_time)); | ||
1420 | pos += scnprintf(buf + pos, bufsz - pos, "rx_enable_counter: %u\n", | ||
1421 | le32_to_cpu(general->rx_enable_counter)); | ||
1422 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
1423 | kfree(buf); | ||
1424 | return ret; | ||
1425 | } | ||
1426 | |||
1427 | static ssize_t iwl_dbgfs_sensitivity_read(struct file *file, | ||
1428 | char __user *user_buf, | ||
1429 | size_t count, loff_t *ppos) { | ||
1430 | |||
1431 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | ||
1432 | int pos = 0; | ||
1433 | int cnt = 0; | ||
1434 | char *buf; | ||
1435 | int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100; | ||
1436 | ssize_t ret; | ||
1437 | struct iwl_sensitivity_data *data; | ||
1438 | |||
1439 | data = &priv->sensitivity_data; | ||
1440 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
1441 | if (!buf) { | ||
1442 | IWL_ERR(priv, "Can not allocate Buffer\n"); | ||
1443 | return -ENOMEM; | ||
1444 | } | ||
1445 | |||
1446 | pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n", | ||
1447 | data->auto_corr_ofdm); | ||
1448 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1449 | "auto_corr_ofdm_mrc:\t\t %u\n", | ||
1450 | data->auto_corr_ofdm_mrc); | ||
1451 | pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n", | ||
1452 | data->auto_corr_ofdm_x1); | ||
1453 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1454 | "auto_corr_ofdm_mrc_x1:\t\t %u\n", | ||
1455 | data->auto_corr_ofdm_mrc_x1); | ||
1456 | pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n", | ||
1457 | data->auto_corr_cck); | ||
1458 | pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n", | ||
1459 | data->auto_corr_cck_mrc); | ||
1460 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1461 | "last_bad_plcp_cnt_ofdm:\t\t %u\n", | ||
1462 | data->last_bad_plcp_cnt_ofdm); | ||
1463 | pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n", | ||
1464 | data->last_fa_cnt_ofdm); | ||
1465 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1466 | "last_bad_plcp_cnt_cck:\t\t %u\n", | ||
1467 | data->last_bad_plcp_cnt_cck); | ||
1468 | pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n", | ||
1469 | data->last_fa_cnt_cck); | ||
1470 | pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n", | ||
1471 | data->nrg_curr_state); | ||
1472 | pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n", | ||
1473 | data->nrg_prev_state); | ||
1474 | pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t"); | ||
1475 | for (cnt = 0; cnt < 10; cnt++) { | ||
1476 | pos += scnprintf(buf + pos, bufsz - pos, " %u", | ||
1477 | data->nrg_value[cnt]); | ||
1478 | } | ||
1479 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | ||
1480 | pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t"); | ||
1481 | for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) { | ||
1482 | pos += scnprintf(buf + pos, bufsz - pos, " %u", | ||
1483 | data->nrg_silence_rssi[cnt]); | ||
1484 | } | ||
1485 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | ||
1486 | pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n", | ||
1487 | data->nrg_silence_ref); | ||
1488 | pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n", | ||
1489 | data->nrg_energy_idx); | ||
1490 | pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n", | ||
1491 | data->nrg_silence_idx); | ||
1492 | pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n", | ||
1493 | data->nrg_th_cck); | ||
1494 | pos += scnprintf(buf + pos, bufsz - pos, | ||
1495 | "nrg_auto_corr_silence_diff:\t %u\n", | ||
1496 | data->nrg_auto_corr_silence_diff); | ||
1497 | pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n", | ||
1498 | data->num_in_cck_no_fa); | ||
1499 | pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n", | ||
1500 | data->nrg_th_ofdm); | ||
1501 | |||
1502 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
1503 | kfree(buf); | ||
1504 | return ret; | ||
1505 | } | ||
1506 | |||
1507 | |||
1508 | static ssize_t iwl_dbgfs_chain_noise_read(struct file *file, | ||
1509 | char __user *user_buf, | ||
1510 | size_t count, loff_t *ppos) { | ||
1511 | |||
1512 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | ||
1513 | int pos = 0; | ||
1514 | int cnt = 0; | ||
1515 | char *buf; | ||
1516 | int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100; | ||
1517 | ssize_t ret; | ||
1518 | struct iwl_chain_noise_data *data; | ||
1519 | |||
1520 | data = &priv->chain_noise_data; | ||
1521 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
1522 | if (!buf) { | ||
1523 | IWL_ERR(priv, "Can not allocate Buffer\n"); | ||
1524 | return -ENOMEM; | ||
1525 | } | ||
1526 | |||
1527 | pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n", | ||
1528 | data->active_chains); | ||
1529 | pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n", | ||
1530 | data->chain_noise_a); | ||
1531 | pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n", | ||
1532 | data->chain_noise_b); | ||
1533 | pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n", | ||
1534 | data->chain_noise_c); | ||
1535 | pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n", | ||
1536 | data->chain_signal_a); | ||
1537 | pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n", | ||
1538 | data->chain_signal_b); | ||
1539 | pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n", | ||
1540 | data->chain_signal_c); | ||
1541 | pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n", | ||
1542 | data->beacon_count); | ||
1543 | |||
1544 | pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t"); | ||
1545 | for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) { | ||
1546 | pos += scnprintf(buf + pos, bufsz - pos, " %u", | ||
1547 | data->disconn_array[cnt]); | ||
1548 | } | ||
1549 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | ||
1550 | pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t"); | ||
1551 | for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) { | ||
1552 | pos += scnprintf(buf + pos, bufsz - pos, " %u", | ||
1553 | data->delta_gain_code[cnt]); | ||
1554 | } | ||
1555 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | ||
1556 | pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n", | ||
1557 | data->radio_write); | ||
1558 | pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n", | ||
1559 | data->state); | ||
1560 | |||
1561 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
1562 | kfree(buf); | ||
1563 | return ret; | ||
1564 | } | ||
1565 | |||
1566 | DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); | ||
1567 | DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); | ||
1568 | DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); | ||
1569 | DEBUGFS_READ_FILE_OPS(rx_queue); | ||
1570 | DEBUGFS_READ_FILE_OPS(tx_queue); | ||
1571 | DEBUGFS_READ_FILE_OPS(ucode_rx_stats); | ||
1572 | DEBUGFS_READ_FILE_OPS(ucode_tx_stats); | ||
1573 | DEBUGFS_READ_FILE_OPS(ucode_general_stats); | ||
1574 | DEBUGFS_READ_FILE_OPS(sensitivity); | ||
1575 | DEBUGFS_READ_FILE_OPS(chain_noise); | ||
714 | 1576 | ||
715 | /* | 1577 | /* |
716 | * Create the debugfs files and directories | 1578 | * Create the debugfs files and directories |
@@ -738,12 +1600,11 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) | |||
738 | 1600 | ||
739 | DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); | 1601 | DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); |
740 | DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); | 1602 | DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); |
1603 | DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv); | ||
741 | DEBUGFS_ADD_FILE(nvm, data); | 1604 | DEBUGFS_ADD_FILE(nvm, data); |
742 | DEBUGFS_ADD_FILE(sram, data); | 1605 | DEBUGFS_ADD_FILE(sram, data); |
743 | DEBUGFS_ADD_FILE(log_event, data); | 1606 | DEBUGFS_ADD_FILE(log_event, data); |
744 | DEBUGFS_ADD_FILE(stations, data); | 1607 | DEBUGFS_ADD_FILE(stations, data); |
745 | DEBUGFS_ADD_FILE(rx_statistics, data); | ||
746 | DEBUGFS_ADD_FILE(tx_statistics, data); | ||
747 | DEBUGFS_ADD_FILE(channels, data); | 1608 | DEBUGFS_ADD_FILE(channels, data); |
748 | DEBUGFS_ADD_FILE(status, data); | 1609 | DEBUGFS_ADD_FILE(status, data); |
749 | DEBUGFS_ADD_FILE(interrupt, data); | 1610 | DEBUGFS_ADD_FILE(interrupt, data); |
@@ -751,8 +1612,22 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) | |||
751 | #ifdef CONFIG_IWLWIFI_LEDS | 1612 | #ifdef CONFIG_IWLWIFI_LEDS |
752 | DEBUGFS_ADD_FILE(led, data); | 1613 | DEBUGFS_ADD_FILE(led, data); |
753 | #endif | 1614 | #endif |
1615 | DEBUGFS_ADD_FILE(sleep_level_override, data); | ||
1616 | DEBUGFS_ADD_FILE(current_sleep_command, data); | ||
754 | DEBUGFS_ADD_FILE(thermal_throttling, data); | 1617 | DEBUGFS_ADD_FILE(thermal_throttling, data); |
755 | DEBUGFS_ADD_FILE(disable_ht40, data); | 1618 | DEBUGFS_ADD_FILE(disable_ht40, data); |
1619 | DEBUGFS_ADD_FILE(rx_statistics, debug); | ||
1620 | DEBUGFS_ADD_FILE(tx_statistics, debug); | ||
1621 | DEBUGFS_ADD_FILE(traffic_log, debug); | ||
1622 | DEBUGFS_ADD_FILE(rx_queue, debug); | ||
1623 | DEBUGFS_ADD_FILE(tx_queue, debug); | ||
1624 | if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { | ||
1625 | DEBUGFS_ADD_FILE(ucode_rx_stats, debug); | ||
1626 | DEBUGFS_ADD_FILE(ucode_tx_stats, debug); | ||
1627 | DEBUGFS_ADD_FILE(ucode_general_stats, debug); | ||
1628 | DEBUGFS_ADD_FILE(sensitivity, debug); | ||
1629 | DEBUGFS_ADD_FILE(chain_noise, debug); | ||
1630 | } | ||
756 | DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); | 1631 | DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); |
757 | DEBUGFS_ADD_BOOL(disable_chain_noise, rf, | 1632 | DEBUGFS_ADD_BOOL(disable_chain_noise, rf, |
758 | &priv->disable_chain_noise_cal); | 1633 | &priv->disable_chain_noise_cal); |
@@ -778,9 +1653,9 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) | |||
778 | if (!priv->dbgfs) | 1653 | if (!priv->dbgfs) |
779 | return; | 1654 | return; |
780 | 1655 | ||
1656 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sleep_level_override); | ||
1657 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_current_sleep_command); | ||
781 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); | 1658 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); |
782 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); | ||
783 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); | ||
784 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); | 1659 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); |
785 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); | 1660 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); |
786 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); | 1661 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); |
@@ -794,6 +1669,24 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) | |||
794 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); | 1669 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); |
795 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40); | 1670 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40); |
796 | DEBUGFS_REMOVE(priv->dbgfs->dir_data); | 1671 | DEBUGFS_REMOVE(priv->dbgfs->dir_data); |
1672 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_statistics); | ||
1673 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_statistics); | ||
1674 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); | ||
1675 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue); | ||
1676 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); | ||
1677 | if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { | ||
1678 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. | ||
1679 | file_ucode_rx_stats); | ||
1680 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. | ||
1681 | file_ucode_tx_stats); | ||
1682 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. | ||
1683 | file_ucode_general_stats); | ||
1684 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. | ||
1685 | file_sensitivity); | ||
1686 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. | ||
1687 | file_chain_noise); | ||
1688 | } | ||
1689 | DEBUGFS_REMOVE(priv->dbgfs->dir_debug); | ||
797 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); | 1690 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); |
798 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); | 1691 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); |
799 | if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || | 1692 | if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cab6255210d5..b96c3c9e92a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -277,8 +277,8 @@ struct iwl_channel_info { | |||
277 | struct iwl4965_channel_tgd_info tgd; | 277 | struct iwl4965_channel_tgd_info tgd; |
278 | struct iwl4965_channel_tgh_info tgh; | 278 | struct iwl4965_channel_tgh_info tgh; |
279 | struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ | 279 | struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ |
280 | struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for | 280 | struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for |
281 | * FAT channel */ | 281 | * HT40 channel */ |
282 | 282 | ||
283 | u8 channel; /* channel number */ | 283 | u8 channel; /* channel number */ |
284 | u8 flags; /* flags copied from EEPROM */ | 284 | u8 flags; /* flags copied from EEPROM */ |
@@ -291,13 +291,13 @@ struct iwl_channel_info { | |||
291 | u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ | 291 | u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ |
292 | enum ieee80211_band band; | 292 | enum ieee80211_band band; |
293 | 293 | ||
294 | /* FAT channel info */ | 294 | /* HT40 channel info */ |
295 | s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ | 295 | s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ |
296 | s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ | 296 | s8 ht40_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ |
297 | s8 fat_min_power; /* always 0 */ | 297 | s8 ht40_min_power; /* always 0 */ |
298 | s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */ | 298 | s8 ht40_scan_power; /* (dBm) eeprom, direct scans, any rate */ |
299 | u8 fat_flags; /* flags copied from EEPROM */ | 299 | u8 ht40_flags; /* flags copied from EEPROM */ |
300 | u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */ | 300 | u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */ |
301 | 301 | ||
302 | /* Radio/DSP gain settings for each "normal" data Tx rate. | 302 | /* Radio/DSP gain settings for each "normal" data Tx rate. |
303 | * These include, in addition to RF and DSP gain, a few fields for | 303 | * These include, in addition to RF and DSP gain, a few fields for |
@@ -649,7 +649,7 @@ struct iwl_sensitivity_ranges { | |||
649 | * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR | 649 | * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR |
650 | * @max_stations: | 650 | * @max_stations: |
651 | * @bcast_sta_id: | 651 | * @bcast_sta_id: |
652 | * @fat_channel: is 40MHz width possible in band 2.4 | 652 | * @ht40_channel: is 40MHz width possible in band 2.4 |
653 | * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ) | 653 | * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ) |
654 | * @sw_crypto: 0 for hw, 1 for sw | 654 | * @sw_crypto: 0 for hw, 1 for sw |
655 | * @max_xxx_size: for ucode uses | 655 | * @max_xxx_size: for ucode uses |
@@ -673,7 +673,7 @@ struct iwl_hw_params { | |||
673 | u32 max_pkt_size; | 673 | u32 max_pkt_size; |
674 | u8 max_stations; | 674 | u8 max_stations; |
675 | u8 bcast_sta_id; | 675 | u8 bcast_sta_id; |
676 | u8 fat_channel; | 676 | u8 ht40_channel; |
677 | u8 max_beacon_itrvl; /* in 1024 ms */ | 677 | u8 max_beacon_itrvl; /* in 1024 ms */ |
678 | u32 max_inst_size; | 678 | u32 max_inst_size; |
679 | u32 max_data_size; | 679 | u32 max_data_size; |
@@ -823,8 +823,6 @@ struct iwl_calib_result { | |||
823 | size_t buf_len; | 823 | size_t buf_len; |
824 | }; | 824 | }; |
825 | 825 | ||
826 | #define UCODE_ALIVE_TIMEOUT (5 * HZ) | ||
827 | |||
828 | enum ucode_type { | 826 | enum ucode_type { |
829 | UCODE_NONE = 0, | 827 | UCODE_NONE = 0, |
830 | UCODE_INIT, | 828 | UCODE_INIT, |
@@ -877,6 +875,8 @@ struct iwl_chain_noise_data { | |||
877 | #define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ | 875 | #define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ |
878 | #define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ | 876 | #define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ |
879 | 877 | ||
878 | #define IWL_TRAFFIC_ENTRIES (256) | ||
879 | #define IWL_TRAFFIC_ENTRY_SIZE (64) | ||
880 | 880 | ||
881 | enum { | 881 | enum { |
882 | MEASUREMENT_READY = (1 << 0), | 882 | MEASUREMENT_READY = (1 << 0), |
@@ -917,6 +917,48 @@ struct isr_statistics { | |||
917 | u32 unhandled; | 917 | u32 unhandled; |
918 | }; | 918 | }; |
919 | 919 | ||
920 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
921 | /* management statistics */ | ||
922 | enum iwl_mgmt_stats { | ||
923 | MANAGEMENT_ASSOC_REQ = 0, | ||
924 | MANAGEMENT_ASSOC_RESP, | ||
925 | MANAGEMENT_REASSOC_REQ, | ||
926 | MANAGEMENT_REASSOC_RESP, | ||
927 | MANAGEMENT_PROBE_REQ, | ||
928 | MANAGEMENT_PROBE_RESP, | ||
929 | MANAGEMENT_BEACON, | ||
930 | MANAGEMENT_ATIM, | ||
931 | MANAGEMENT_DISASSOC, | ||
932 | MANAGEMENT_AUTH, | ||
933 | MANAGEMENT_DEAUTH, | ||
934 | MANAGEMENT_ACTION, | ||
935 | MANAGEMENT_MAX, | ||
936 | }; | ||
937 | /* control statistics */ | ||
938 | enum iwl_ctrl_stats { | ||
939 | CONTROL_BACK_REQ = 0, | ||
940 | CONTROL_BACK, | ||
941 | CONTROL_PSPOLL, | ||
942 | CONTROL_RTS, | ||
943 | CONTROL_CTS, | ||
944 | CONTROL_ACK, | ||
945 | CONTROL_CFEND, | ||
946 | CONTROL_CFENDACK, | ||
947 | CONTROL_MAX, | ||
948 | }; | ||
949 | |||
950 | struct traffic_stats { | ||
951 | u32 mgmt[MANAGEMENT_MAX]; | ||
952 | u32 ctrl[CONTROL_MAX]; | ||
953 | u32 data_cnt; | ||
954 | u64 data_bytes; | ||
955 | }; | ||
956 | #else | ||
957 | struct traffic_stats { | ||
958 | u64 data_bytes; | ||
959 | }; | ||
960 | #endif | ||
961 | |||
920 | #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ | 962 | #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ |
921 | 963 | ||
922 | struct iwl_priv { | 964 | struct iwl_priv { |
@@ -1062,15 +1104,14 @@ struct iwl_priv { | |||
1062 | int last_rx_noise; /* From beacon statistics */ | 1104 | int last_rx_noise; /* From beacon statistics */ |
1063 | 1105 | ||
1064 | /* counts mgmt, ctl, and data packets */ | 1106 | /* counts mgmt, ctl, and data packets */ |
1065 | struct traffic_stats { | 1107 | struct traffic_stats tx_stats; |
1066 | u32 cnt; | 1108 | struct traffic_stats rx_stats; |
1067 | u64 bytes; | ||
1068 | } tx_stats[3], rx_stats[3]; | ||
1069 | 1109 | ||
1070 | /* counts interrupts */ | 1110 | /* counts interrupts */ |
1071 | struct isr_statistics isr_stats; | 1111 | struct isr_statistics isr_stats; |
1072 | 1112 | ||
1073 | struct iwl_power_mgr power_data; | 1113 | struct iwl_power_mgr power_data; |
1114 | struct iwl_tt_mgmt thermal_throttle; | ||
1074 | 1115 | ||
1075 | struct iwl_notif_statistics statistics; | 1116 | struct iwl_notif_statistics statistics; |
1076 | unsigned long last_statistics_time; | 1117 | unsigned long last_statistics_time; |
@@ -1078,7 +1119,6 @@ struct iwl_priv { | |||
1078 | /* context information */ | 1119 | /* context information */ |
1079 | u16 rates_mask; | 1120 | u16 rates_mask; |
1080 | 1121 | ||
1081 | u32 power_mode; | ||
1082 | u8 bssid[ETH_ALEN]; | 1122 | u8 bssid[ETH_ALEN]; |
1083 | u16 rts_threshold; | 1123 | u16 rts_threshold; |
1084 | u8 mac_addr[ETH_ALEN]; | 1124 | u8 mac_addr[ETH_ALEN]; |
@@ -1157,6 +1197,9 @@ struct iwl_priv { | |||
1157 | struct work_struct report_work; | 1197 | struct work_struct report_work; |
1158 | struct work_struct request_scan; | 1198 | struct work_struct request_scan; |
1159 | struct work_struct beacon_update; | 1199 | struct work_struct beacon_update; |
1200 | struct work_struct tt_work; | ||
1201 | struct work_struct ct_enter; | ||
1202 | struct work_struct ct_exit; | ||
1160 | 1203 | ||
1161 | struct tasklet_struct irq_tasklet; | 1204 | struct tasklet_struct irq_tasklet; |
1162 | 1205 | ||
@@ -1175,11 +1218,17 @@ struct iwl_priv { | |||
1175 | 1218 | ||
1176 | #ifdef CONFIG_IWLWIFI_DEBUG | 1219 | #ifdef CONFIG_IWLWIFI_DEBUG |
1177 | /* debugging info */ | 1220 | /* debugging info */ |
1221 | u32 debug_level; /* per device debugging will override global | ||
1222 | iwl_debug_level if set */ | ||
1178 | u32 framecnt_to_us; | 1223 | u32 framecnt_to_us; |
1179 | atomic_t restrict_refcnt; | 1224 | atomic_t restrict_refcnt; |
1180 | bool disable_ht40; | 1225 | bool disable_ht40; |
1181 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1226 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
1182 | /* debugfs */ | 1227 | /* debugfs */ |
1228 | u16 tx_traffic_idx; | ||
1229 | u16 rx_traffic_idx; | ||
1230 | u8 *tx_traffic; | ||
1231 | u8 *rx_traffic; | ||
1183 | struct iwl_debugfs *dbgfs; | 1232 | struct iwl_debugfs *dbgfs; |
1184 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | 1233 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ |
1185 | #endif /* CONFIG_IWLWIFI_DEBUG */ | 1234 | #endif /* CONFIG_IWLWIFI_DEBUG */ |
@@ -1211,8 +1260,27 @@ static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) | |||
1211 | 1260 | ||
1212 | #ifdef CONFIG_IWLWIFI_DEBUG | 1261 | #ifdef CONFIG_IWLWIFI_DEBUG |
1213 | const char *iwl_get_tx_fail_reason(u32 status); | 1262 | const char *iwl_get_tx_fail_reason(u32 status); |
1263 | /* | ||
1264 | * iwl_get_debug_level: Return active debug level for device | ||
1265 | * | ||
1266 | * Using sysfs it is possible to set per device debug level. This debug | ||
1267 | * level will be used if set, otherwise the global debug level which can be | ||
1268 | * set via module parameter is used. | ||
1269 | */ | ||
1270 | static inline u32 iwl_get_debug_level(struct iwl_priv *priv) | ||
1271 | { | ||
1272 | if (priv->debug_level) | ||
1273 | return priv->debug_level; | ||
1274 | else | ||
1275 | return iwl_debug_level; | ||
1276 | } | ||
1214 | #else | 1277 | #else |
1215 | static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; } | 1278 | static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; } |
1279 | |||
1280 | static inline u32 iwl_get_debug_level(struct iwl_priv *priv) | ||
1281 | { | ||
1282 | return iwl_debug_level; | ||
1283 | } | ||
1216 | #endif | 1284 | #endif |
1217 | 1285 | ||
1218 | 1286 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 51eed7226669..78c4a324a3b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c | |||
@@ -127,11 +127,11 @@ static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */ | |||
127 | 145, 149, 153, 157, 161, 165 | 127 | 145, 149, 153, 157, 161, 165 |
128 | }; | 128 | }; |
129 | 129 | ||
130 | static const u8 iwl_eeprom_band_6[] = { /* 2.4 FAT channel */ | 130 | static const u8 iwl_eeprom_band_6[] = { /* 2.4 ht40 channel */ |
131 | 1, 2, 3, 4, 5, 6, 7 | 131 | 1, 2, 3, 4, 5, 6, 7 |
132 | }; | 132 | }; |
133 | 133 | ||
134 | static const u8 iwl_eeprom_band_7[] = { /* 5.2 FAT channel */ | 134 | static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ |
135 | 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 | 135 | 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 |
136 | }; | 136 | }; |
137 | 137 | ||
@@ -462,13 +462,13 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, | |||
462 | iwl_eeprom_query_addr(priv, offset); | 462 | iwl_eeprom_query_addr(priv, offset); |
463 | *eeprom_ch_index = iwl_eeprom_band_5; | 463 | *eeprom_ch_index = iwl_eeprom_band_5; |
464 | break; | 464 | break; |
465 | case 6: /* 2.4GHz FAT channels */ | 465 | case 6: /* 2.4GHz ht40 channels */ |
466 | *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); | 466 | *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); |
467 | *eeprom_ch_info = (struct iwl_eeprom_channel *) | 467 | *eeprom_ch_info = (struct iwl_eeprom_channel *) |
468 | iwl_eeprom_query_addr(priv, offset); | 468 | iwl_eeprom_query_addr(priv, offset); |
469 | *eeprom_ch_index = iwl_eeprom_band_6; | 469 | *eeprom_ch_index = iwl_eeprom_band_6; |
470 | break; | 470 | break; |
471 | case 7: /* 5 GHz FAT channels */ | 471 | case 7: /* 5 GHz ht40 channels */ |
472 | *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); | 472 | *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); |
473 | *eeprom_ch_info = (struct iwl_eeprom_channel *) | 473 | *eeprom_ch_info = (struct iwl_eeprom_channel *) |
474 | iwl_eeprom_query_addr(priv, offset); | 474 | iwl_eeprom_query_addr(priv, offset); |
@@ -484,14 +484,14 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, | |||
484 | ? # x " " : "") | 484 | ? # x " " : "") |
485 | 485 | ||
486 | /** | 486 | /** |
487 | * iwl_set_fat_chan_info - Copy fat channel info into driver's priv. | 487 | * iwl_set_ht40_chan_info - Copy ht40 channel info into driver's priv. |
488 | * | 488 | * |
489 | * Does not set up a command, or touch hardware. | 489 | * Does not set up a command, or touch hardware. |
490 | */ | 490 | */ |
491 | static int iwl_set_fat_chan_info(struct iwl_priv *priv, | 491 | static int iwl_set_ht40_chan_info(struct iwl_priv *priv, |
492 | enum ieee80211_band band, u16 channel, | 492 | enum ieee80211_band band, u16 channel, |
493 | const struct iwl_eeprom_channel *eeprom_ch, | 493 | const struct iwl_eeprom_channel *eeprom_ch, |
494 | u8 fat_extension_channel) | 494 | u8 ht40_extension_channel) |
495 | { | 495 | { |
496 | struct iwl_channel_info *ch_info; | 496 | struct iwl_channel_info *ch_info; |
497 | 497 | ||
@@ -501,7 +501,7 @@ static int iwl_set_fat_chan_info(struct iwl_priv *priv, | |||
501 | if (!is_channel_valid(ch_info)) | 501 | if (!is_channel_valid(ch_info)) |
502 | return -1; | 502 | return -1; |
503 | 503 | ||
504 | IWL_DEBUG_INFO(priv, "FAT Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):" | 504 | IWL_DEBUG_INFO(priv, "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):" |
505 | " Ad-Hoc %ssupported\n", | 505 | " Ad-Hoc %ssupported\n", |
506 | ch_info->channel, | 506 | ch_info->channel, |
507 | is_channel_a_band(ch_info) ? | 507 | is_channel_a_band(ch_info) ? |
@@ -517,13 +517,13 @@ static int iwl_set_fat_chan_info(struct iwl_priv *priv, | |||
517 | && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ? | 517 | && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ? |
518 | "" : "not "); | 518 | "" : "not "); |
519 | 519 | ||
520 | ch_info->fat_eeprom = *eeprom_ch; | 520 | ch_info->ht40_eeprom = *eeprom_ch; |
521 | ch_info->fat_max_power_avg = eeprom_ch->max_power_avg; | 521 | ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg; |
522 | ch_info->fat_curr_txpow = eeprom_ch->max_power_avg; | 522 | ch_info->ht40_curr_txpow = eeprom_ch->max_power_avg; |
523 | ch_info->fat_min_power = 0; | 523 | ch_info->ht40_min_power = 0; |
524 | ch_info->fat_scan_power = eeprom_ch->max_power_avg; | 524 | ch_info->ht40_scan_power = eeprom_ch->max_power_avg; |
525 | ch_info->fat_flags = eeprom_ch->flags; | 525 | ch_info->ht40_flags = eeprom_ch->flags; |
526 | ch_info->fat_extension_channel = fat_extension_channel; | 526 | ch_info->ht40_extension_channel = ht40_extension_channel; |
527 | 527 | ||
528 | return 0; | 528 | return 0; |
529 | } | 529 | } |
@@ -589,9 +589,9 @@ int iwl_init_channel_map(struct iwl_priv *priv) | |||
589 | /* Copy the run-time flags so they are there even on | 589 | /* Copy the run-time flags so they are there even on |
590 | * invalid channels */ | 590 | * invalid channels */ |
591 | ch_info->flags = eeprom_ch_info[ch].flags; | 591 | ch_info->flags = eeprom_ch_info[ch].flags; |
592 | /* First write that fat is not enabled, and then enable | 592 | /* First write that ht40 is not enabled, and then enable |
593 | * one by one */ | 593 | * one by one */ |
594 | ch_info->fat_extension_channel = | 594 | ch_info->ht40_extension_channel = |
595 | (IEEE80211_CHAN_NO_HT40PLUS | | 595 | (IEEE80211_CHAN_NO_HT40PLUS | |
596 | IEEE80211_CHAN_NO_HT40MINUS); | 596 | IEEE80211_CHAN_NO_HT40MINUS); |
597 | 597 | ||
@@ -642,17 +642,17 @@ int iwl_init_channel_map(struct iwl_priv *priv) | |||
642 | } | 642 | } |
643 | } | 643 | } |
644 | 644 | ||
645 | /* Check if we do have FAT channels */ | 645 | /* Check if we do have HT40 channels */ |
646 | if (priv->cfg->ops->lib->eeprom_ops.regulatory_bands[5] == | 646 | if (priv->cfg->ops->lib->eeprom_ops.regulatory_bands[5] == |
647 | EEPROM_REGULATORY_BAND_NO_FAT && | 647 | EEPROM_REGULATORY_BAND_NO_HT40 && |
648 | priv->cfg->ops->lib->eeprom_ops.regulatory_bands[6] == | 648 | priv->cfg->ops->lib->eeprom_ops.regulatory_bands[6] == |
649 | EEPROM_REGULATORY_BAND_NO_FAT) | 649 | EEPROM_REGULATORY_BAND_NO_HT40) |
650 | return 0; | 650 | return 0; |
651 | 651 | ||
652 | /* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */ | 652 | /* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */ |
653 | for (band = 6; band <= 7; band++) { | 653 | for (band = 6; band <= 7; band++) { |
654 | enum ieee80211_band ieeeband; | 654 | enum ieee80211_band ieeeband; |
655 | u8 fat_extension_chan; | 655 | u8 ht40_extension_chan; |
656 | 656 | ||
657 | iwl_init_band_reference(priv, band, &eeprom_ch_count, | 657 | iwl_init_band_reference(priv, band, &eeprom_ch_count, |
658 | &eeprom_ch_info, &eeprom_ch_index); | 658 | &eeprom_ch_info, &eeprom_ch_index); |
@@ -669,19 +669,19 @@ int iwl_init_channel_map(struct iwl_priv *priv) | |||
669 | (eeprom_ch_index[ch] == 6) || | 669 | (eeprom_ch_index[ch] == 6) || |
670 | (eeprom_ch_index[ch] == 7))) | 670 | (eeprom_ch_index[ch] == 7))) |
671 | /* both are allowed: above and below */ | 671 | /* both are allowed: above and below */ |
672 | fat_extension_chan = 0; | 672 | ht40_extension_chan = 0; |
673 | else | 673 | else |
674 | fat_extension_chan = | 674 | ht40_extension_chan = |
675 | IEEE80211_CHAN_NO_HT40MINUS; | 675 | IEEE80211_CHAN_NO_HT40MINUS; |
676 | 676 | ||
677 | /* Set up driver's info for lower half */ | 677 | /* Set up driver's info for lower half */ |
678 | iwl_set_fat_chan_info(priv, ieeeband, | 678 | iwl_set_ht40_chan_info(priv, ieeeband, |
679 | eeprom_ch_index[ch], | 679 | eeprom_ch_index[ch], |
680 | &(eeprom_ch_info[ch]), | 680 | &(eeprom_ch_info[ch]), |
681 | fat_extension_chan); | 681 | ht40_extension_chan); |
682 | 682 | ||
683 | /* Set up driver's info for upper half */ | 683 | /* Set up driver's info for upper half */ |
684 | iwl_set_fat_chan_info(priv, ieeeband, | 684 | iwl_set_ht40_chan_info(priv, ieeeband, |
685 | (eeprom_ch_index[ch] + 4), | 685 | (eeprom_ch_index[ch] + 4), |
686 | &(eeprom_ch_info[ch]), | 686 | &(eeprom_ch_info[ch]), |
687 | IEEE80211_CHAN_NO_HT40PLUS); | 687 | IEEE80211_CHAN_NO_HT40PLUS); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 195b4ef12c27..05d4fc4451dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h | |||
@@ -88,10 +88,10 @@ struct iwl_priv; | |||
88 | * requirement for establishing a new network for legal operation on channels | 88 | * requirement for establishing a new network for legal operation on channels |
89 | * requiring RADAR detection or restricting ACTIVE scanning. | 89 | * requiring RADAR detection or restricting ACTIVE scanning. |
90 | * | 90 | * |
91 | * NOTE: "WIDE" flag does not indicate anything about "FAT" 40 MHz channels. | 91 | * NOTE: "WIDE" flag does not indicate anything about "HT40" 40 MHz channels. |
92 | * It only indicates that 20 MHz channel use is supported; FAT channel | 92 | * It only indicates that 20 MHz channel use is supported; HT40 channel |
93 | * usage is indicated by a separate set of regulatory flags for each | 93 | * usage is indicated by a separate set of regulatory flags for each |
94 | * FAT channel pair. | 94 | * HT40 channel pair. |
95 | * | 95 | * |
96 | * NOTE: Using a channel inappropriately will result in a uCode error! | 96 | * NOTE: Using a channel inappropriately will result in a uCode error! |
97 | */ | 97 | */ |
@@ -112,7 +112,7 @@ enum { | |||
112 | #define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) | 112 | #define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) |
113 | 113 | ||
114 | /* *regulatory* channel data format in eeprom, one for each channel. | 114 | /* *regulatory* channel data format in eeprom, one for each channel. |
115 | * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */ | 115 | * There are separate entries for HT40 (40 MHz) vs. normal (20 MHz) channels. */ |
116 | struct iwl_eeprom_channel { | 116 | struct iwl_eeprom_channel { |
117 | u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */ | 117 | u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */ |
118 | s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ | 118 | s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ |
@@ -170,9 +170,9 @@ struct iwl_eeprom_channel { | |||
170 | | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ | 170 | | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ |
171 | #define EEPROM_5000_REG_BAND_5_CHANNELS ((0x74)\ | 171 | #define EEPROM_5000_REG_BAND_5_CHANNELS ((0x74)\ |
172 | | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 12 bytes */ | 172 | | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 12 bytes */ |
173 | #define EEPROM_5000_REG_BAND_24_FAT_CHANNELS ((0x82)\ | 173 | #define EEPROM_5000_REG_BAND_24_HT40_CHANNELS ((0x82)\ |
174 | | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */ | 174 | | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */ |
175 | #define EEPROM_5000_REG_BAND_52_FAT_CHANNELS ((0x92)\ | 175 | #define EEPROM_5000_REG_BAND_52_HT40_CHANNELS ((0x92)\ |
176 | | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ | 176 | | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ |
177 | 177 | ||
178 | /* 5050 Specific */ | 178 | /* 5050 Specific */ |
@@ -313,7 +313,7 @@ struct iwl_eeprom_calib_info { | |||
313 | * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory | 313 | * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory |
314 | * txpower (MSB). | 314 | * txpower (MSB). |
315 | * | 315 | * |
316 | * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) | 316 | * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) |
317 | * channels (only for 4965, not supported by 3945) appear later in the EEPROM. | 317 | * channels (only for 4965, not supported by 3945) appear later in the EEPROM. |
318 | * | 318 | * |
319 | * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 | 319 | * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 |
@@ -352,29 +352,29 @@ struct iwl_eeprom_calib_info { | |||
352 | #define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ | 352 | #define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ |
353 | 353 | ||
354 | /* | 354 | /* |
355 | * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) | 355 | * 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) |
356 | * | 356 | * |
357 | * The channel listed is the center of the lower 20 MHz half of the channel. | 357 | * The channel listed is the center of the lower 20 MHz half of the channel. |
358 | * The overall center frequency is actually 2 channels (10 MHz) above that, | 358 | * The overall center frequency is actually 2 channels (10 MHz) above that, |
359 | * and the upper half of each FAT channel is centered 4 channels (20 MHz) away | 359 | * and the upper half of each HT40 channel is centered 4 channels (20 MHz) away |
360 | * from the lower half; e.g. the upper half of FAT channel 1 is channel 5, | 360 | * from the lower half; e.g. the upper half of HT40 channel 1 is channel 5, |
361 | * and the overall FAT channel width centers on channel 3. | 361 | * and the overall HT40 channel width centers on channel 3. |
362 | * | 362 | * |
363 | * NOTE: The RXON command uses 20 MHz channel numbers to specify the | 363 | * NOTE: The RXON command uses 20 MHz channel numbers to specify the |
364 | * control channel to which to tune. RXON also specifies whether the | 364 | * control channel to which to tune. RXON also specifies whether the |
365 | * control channel is the upper or lower half of a FAT channel. | 365 | * control channel is the upper or lower half of a HT40 channel. |
366 | * | 366 | * |
367 | * NOTE: 4965 does not support FAT channels on 2.4 GHz. | 367 | * NOTE: 4965 does not support HT40 channels on 2.4 GHz. |
368 | */ | 368 | */ |
369 | #define EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */ | 369 | #define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */ |
370 | 370 | ||
371 | /* | 371 | /* |
372 | * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64), | 372 | * 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64), |
373 | * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) | 373 | * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) |
374 | */ | 374 | */ |
375 | #define EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */ | 375 | #define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */ |
376 | 376 | ||
377 | #define EEPROM_REGULATORY_BAND_NO_FAT (0) | 377 | #define EEPROM_REGULATORY_BAND_NO_HT40 (0) |
378 | 378 | ||
379 | struct iwl_eeprom_ops { | 379 | struct iwl_eeprom_ops { |
380 | const u32 regulatory_bands[7]; | 380 | const u32 regulatory_bands[7]; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index b82ad15d5189..532c8d6cd8da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c | |||
@@ -36,8 +36,6 @@ | |||
36 | #include "iwl-core.h" | 36 | #include "iwl-core.h" |
37 | 37 | ||
38 | 38 | ||
39 | #define IWL_CMD(x) case x: return #x | ||
40 | |||
41 | const char *get_cmd_string(u8 cmd) | 39 | const char *get_cmd_string(u8 cmd) |
42 | { | 40 | { |
43 | switch (cmd) { | 41 | switch (cmd) { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 3d61cb43151c..f420c99e7240 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c | |||
@@ -272,7 +272,8 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) | |||
272 | /* count both tx and rx traffic to be able to | 272 | /* count both tx and rx traffic to be able to |
273 | * handle traffic in either direction | 273 | * handle traffic in either direction |
274 | */ | 274 | */ |
275 | u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes; | 275 | u64 current_tpt = priv->tx_stats.data_bytes + |
276 | priv->rx_stats.data_bytes; | ||
276 | s64 tpt = current_tpt - priv->led_tpt; | 277 | s64 tpt = current_tpt - priv->led_tpt; |
277 | 278 | ||
278 | if (tpt < 0) /* wraparound */ | 279 | if (tpt < 0) /* wraparound */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 00937b3ee8ec..0b16841f45f4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c | |||
@@ -42,20 +42,35 @@ | |||
42 | #include "iwl-power.h" | 42 | #include "iwl-power.h" |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * Setting power level allow the card to go to sleep when not busy. | 45 | * Setting power level allows the card to go to sleep when not busy. |
46 | * | 46 | * |
47 | * The power level is set to INDEX_1 (the least deep state) by | 47 | * We calculate a sleep command based on the required latency, which |
48 | * default, and will, in the future, be the deepest state unless | 48 | * we get from mac80211. In order to handle thermal throttling, we can |
49 | * otherwise required by pm_qos network latency requirements. | 49 | * also use pre-defined power levels. |
50 | * | ||
51 | * Using INDEX_1 without pm_qos is ok because mac80211 will disable | ||
52 | * PS when even checking every beacon for the TIM bit would exceed | ||
53 | * the required latency. | ||
54 | */ | 50 | */ |
55 | 51 | ||
56 | #define IWL_POWER_RANGE_0_MAX (2) | 52 | /* |
57 | #define IWL_POWER_RANGE_1_MAX (10) | 53 | * For now, keep using power level 1 instead of automatically |
54 | * adjusting ... | ||
55 | */ | ||
56 | bool no_sleep_autoadjust = true; | ||
57 | module_param(no_sleep_autoadjust, bool, S_IRUGO); | ||
58 | MODULE_PARM_DESC(no_sleep_autoadjust, | ||
59 | "don't automatically adjust sleep level " | ||
60 | "according to maximum network latency"); | ||
58 | 61 | ||
62 | /* | ||
63 | * This defines the old power levels. They are still used by default | ||
64 | * (level 1) and for thermal throttle (levels 3 through 5) | ||
65 | */ | ||
66 | |||
67 | struct iwl_power_vec_entry { | ||
68 | struct iwl_powertable_cmd cmd; | ||
69 | u8 no_dtim; | ||
70 | }; | ||
71 | |||
72 | #define IWL_DTIM_RANGE_0_MAX 2 | ||
73 | #define IWL_DTIM_RANGE_1_MAX 10 | ||
59 | 74 | ||
60 | #define NOSLP cpu_to_le16(0), 0, 0 | 75 | #define NOSLP cpu_to_le16(0), 0, 0 |
61 | #define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 | 76 | #define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 |
@@ -67,9 +82,8 @@ | |||
67 | cpu_to_le32(X3), \ | 82 | cpu_to_le32(X3), \ |
68 | cpu_to_le32(X4)} | 83 | cpu_to_le32(X4)} |
69 | /* default power management (not Tx power) table values */ | 84 | /* default power management (not Tx power) table values */ |
70 | /* for DTIM period 0 through IWL_POWER_RANGE_0_MAX */ | 85 | /* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */ |
71 | static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { | 86 | static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { |
72 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, | ||
73 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, | 87 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, |
74 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, | 88 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, |
75 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, | 89 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, |
@@ -78,9 +92,8 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { | |||
78 | }; | 92 | }; |
79 | 93 | ||
80 | 94 | ||
81 | /* for DTIM period IWL_POWER_RANGE_0_MAX + 1 through IWL_POWER_RANGE_1_MAX */ | 95 | /* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */ |
82 | static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { | 96 | static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { |
83 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, | ||
84 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, | 97 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, |
85 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, | 98 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, |
86 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, | 99 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, |
@@ -88,9 +101,8 @@ static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { | |||
88 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} | 101 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} |
89 | }; | 102 | }; |
90 | 103 | ||
91 | /* for DTIM period > IWL_POWER_RANGE_1_MAX */ | 104 | /* for DTIM period > IWL_DTIM_RANGE_1_MAX */ |
92 | static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { | 105 | static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { |
93 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, | ||
94 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, | 106 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, |
95 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, | 107 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, |
96 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, | 108 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, |
@@ -98,6 +110,56 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { | |||
98 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} | 110 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} |
99 | }; | 111 | }; |
100 | 112 | ||
113 | static void iwl_static_sleep_cmd(struct iwl_priv *priv, | ||
114 | struct iwl_powertable_cmd *cmd, | ||
115 | enum iwl_power_level lvl, int period) | ||
116 | { | ||
117 | const struct iwl_power_vec_entry *table; | ||
118 | int max_sleep, i; | ||
119 | bool skip; | ||
120 | |||
121 | table = range_2; | ||
122 | if (period < IWL_DTIM_RANGE_1_MAX) | ||
123 | table = range_1; | ||
124 | if (period < IWL_DTIM_RANGE_0_MAX) | ||
125 | table = range_0; | ||
126 | |||
127 | BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); | ||
128 | |||
129 | *cmd = table[lvl].cmd; | ||
130 | |||
131 | if (period == 0) { | ||
132 | skip = false; | ||
133 | period = 1; | ||
134 | } else { | ||
135 | skip = !!table[lvl].no_dtim; | ||
136 | } | ||
137 | |||
138 | if (skip) { | ||
139 | __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; | ||
140 | max_sleep = le32_to_cpu(slp_itrvl); | ||
141 | if (max_sleep == 0xFF) | ||
142 | max_sleep = period * (skip + 1); | ||
143 | else if (max_sleep > period) | ||
144 | max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; | ||
145 | cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; | ||
146 | } else { | ||
147 | max_sleep = period; | ||
148 | cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; | ||
149 | } | ||
150 | |||
151 | for (i = 0; i < IWL_POWER_VEC_SIZE; i++) | ||
152 | if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) | ||
153 | cmd->sleep_interval[i] = cpu_to_le32(max_sleep); | ||
154 | |||
155 | if (priv->power_data.pci_pm) | ||
156 | cmd->flags |= IWL_POWER_PCI_PM_MSK; | ||
157 | else | ||
158 | cmd->flags &= ~IWL_POWER_PCI_PM_MSK; | ||
159 | |||
160 | IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1); | ||
161 | } | ||
162 | |||
101 | /* default Thermal Throttling transaction table | 163 | /* default Thermal Throttling transaction table |
102 | * Current state | Throttling Down | Throttling Up | 164 | * Current state | Throttling Down | Throttling Up |
103 | *============================================================================= | 165 | *============================================================================= |
@@ -132,104 +194,50 @@ static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = { | |||
132 | 194 | ||
133 | /* Advance Thermal Throttling default restriction table */ | 195 | /* Advance Thermal Throttling default restriction table */ |
134 | static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = { | 196 | static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = { |
135 | {IWL_TX_MULTI, true, IWL_RX_MULTI}, | 197 | {IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true }, |
136 | {IWL_TX_SINGLE, true, IWL_RX_MULTI}, | 198 | {IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true }, |
137 | {IWL_TX_SINGLE, false, IWL_RX_SINGLE}, | 199 | {IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false }, |
138 | {IWL_TX_NONE, false, IWL_RX_NONE} | 200 | {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false } |
139 | }; | 201 | }; |
140 | 202 | ||
141 | /* set card power command */ | ||
142 | static int iwl_set_power(struct iwl_priv *priv, void *cmd) | ||
143 | { | ||
144 | return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, | ||
145 | sizeof(struct iwl_powertable_cmd), cmd); | ||
146 | } | ||
147 | 203 | ||
148 | /* initialize to default */ | 204 | static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv, |
149 | static void iwl_power_init_handle(struct iwl_priv *priv) | 205 | struct iwl_powertable_cmd *cmd) |
150 | { | 206 | { |
151 | struct iwl_power_mgr *pow_data; | 207 | memset(cmd, 0, sizeof(*cmd)); |
152 | int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_NUM; | ||
153 | struct iwl_powertable_cmd *cmd; | ||
154 | int i; | ||
155 | u16 lctl; | ||
156 | |||
157 | IWL_DEBUG_POWER(priv, "Initialize power \n"); | ||
158 | |||
159 | pow_data = &priv->power_data; | ||
160 | |||
161 | memset(pow_data, 0, sizeof(*pow_data)); | ||
162 | 208 | ||
163 | memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); | 209 | if (priv->power_data.pci_pm) |
164 | memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); | 210 | cmd->flags |= IWL_POWER_PCI_PM_MSK; |
165 | memcpy(&pow_data->pwr_range_2[0], &range_2[0], size); | ||
166 | 211 | ||
167 | lctl = iwl_pcie_link_ctl(priv); | 212 | IWL_DEBUG_POWER(priv, "Sleep command for CAM\n"); |
168 | |||
169 | IWL_DEBUG_POWER(priv, "adjust power command flags\n"); | ||
170 | |||
171 | for (i = 0; i < IWL_POWER_NUM; i++) { | ||
172 | cmd = &pow_data->pwr_range_0[i].cmd; | ||
173 | |||
174 | if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN) | ||
175 | cmd->flags &= ~IWL_POWER_PCI_PM_MSK; | ||
176 | else | ||
177 | cmd->flags |= IWL_POWER_PCI_PM_MSK; | ||
178 | } | ||
179 | } | 213 | } |
180 | 214 | ||
181 | /* adjust power command according to DTIM period and power level*/ | 215 | static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, |
182 | static int iwl_update_power_cmd(struct iwl_priv *priv, | 216 | struct iwl_powertable_cmd *cmd, |
183 | struct iwl_powertable_cmd *cmd, u16 mode) | 217 | int dynps_ms, int wakeup_period) |
184 | { | 218 | { |
185 | struct iwl_power_vec_entry *range; | ||
186 | struct iwl_power_mgr *pow_data; | ||
187 | int i; | 219 | int i; |
188 | u32 max_sleep = 0; | ||
189 | u8 period; | ||
190 | bool skip; | ||
191 | 220 | ||
192 | if (mode > IWL_POWER_INDEX_5) { | 221 | memset(cmd, 0, sizeof(*cmd)); |
193 | IWL_DEBUG_POWER(priv, "Error invalid power mode \n"); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | 222 | ||
197 | pow_data = &priv->power_data; | 223 | cmd->flags = IWL_POWER_DRIVER_ALLOW_SLEEP_MSK | |
198 | 224 | IWL_POWER_FAST_PD; /* no use seeing frames for others */ | |
199 | if (pow_data->dtim_period <= IWL_POWER_RANGE_0_MAX) | ||
200 | range = &pow_data->pwr_range_0[0]; | ||
201 | else if (pow_data->dtim_period <= IWL_POWER_RANGE_1_MAX) | ||
202 | range = &pow_data->pwr_range_1[0]; | ||
203 | else | ||
204 | range = &pow_data->pwr_range_2[0]; | ||
205 | 225 | ||
206 | period = pow_data->dtim_period; | 226 | if (priv->power_data.pci_pm) |
207 | memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); | 227 | cmd->flags |= IWL_POWER_PCI_PM_MSK; |
208 | 228 | ||
209 | if (period == 0) { | 229 | cmd->rx_data_timeout = cpu_to_le32(1000 * dynps_ms); |
210 | period = 1; | 230 | cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms); |
211 | skip = false; | ||
212 | } else { | ||
213 | skip = !!range[mode].no_dtim; | ||
214 | } | ||
215 | |||
216 | if (skip) { | ||
217 | __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; | ||
218 | max_sleep = le32_to_cpu(slp_itrvl); | ||
219 | if (max_sleep == 0xFF) | ||
220 | max_sleep = period * (skip + 1); | ||
221 | else if (max_sleep > period) | ||
222 | max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; | ||
223 | cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; | ||
224 | } else { | ||
225 | max_sleep = period; | ||
226 | cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; | ||
227 | } | ||
228 | 231 | ||
229 | for (i = 0; i < IWL_POWER_VEC_SIZE; i++) | 232 | for (i = 0; i < IWL_POWER_VEC_SIZE; i++) |
230 | if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) | 233 | cmd->sleep_interval[i] = cpu_to_le32(wakeup_period); |
231 | cmd->sleep_interval[i] = cpu_to_le32(max_sleep); | 234 | |
235 | IWL_DEBUG_POWER(priv, "Automatic sleep command\n"); | ||
236 | } | ||
232 | 237 | ||
238 | static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd) | ||
239 | { | ||
240 | IWL_DEBUG_POWER(priv, "Sending power/sleep command\n"); | ||
233 | IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags); | 241 | IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags); |
234 | IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); | 242 | IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); |
235 | IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); | 243 | IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); |
@@ -240,113 +248,107 @@ static int iwl_update_power_cmd(struct iwl_priv *priv, | |||
240 | le32_to_cpu(cmd->sleep_interval[3]), | 248 | le32_to_cpu(cmd->sleep_interval[3]), |
241 | le32_to_cpu(cmd->sleep_interval[4])); | 249 | le32_to_cpu(cmd->sleep_interval[4])); |
242 | 250 | ||
243 | return 0; | 251 | return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, |
252 | sizeof(struct iwl_powertable_cmd), cmd); | ||
244 | } | 253 | } |
245 | 254 | ||
246 | 255 | ||
247 | /* | ||
248 | * compute the final power mode index | ||
249 | */ | ||
250 | int iwl_power_update_mode(struct iwl_priv *priv, bool force) | 256 | int iwl_power_update_mode(struct iwl_priv *priv, bool force) |
251 | { | 257 | { |
252 | struct iwl_power_mgr *setting = &(priv->power_data); | ||
253 | int ret = 0; | 258 | int ret = 0; |
254 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | 259 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
255 | u16 uninitialized_var(final_mode); | 260 | bool enabled = (priv->iw_mode == NL80211_IFTYPE_STATION) && |
261 | (priv->hw->conf.flags & IEEE80211_CONF_PS); | ||
256 | bool update_chains; | 262 | bool update_chains; |
263 | struct iwl_powertable_cmd cmd; | ||
264 | int dtimper; | ||
257 | 265 | ||
258 | /* Don't update the RX chain when chain noise calibration is running */ | 266 | /* Don't update the RX chain when chain noise calibration is running */ |
259 | update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || | 267 | update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || |
260 | priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; | 268 | priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; |
261 | 269 | ||
262 | final_mode = priv->power_data.user_power_setting; | 270 | if (priv->vif) |
263 | 271 | dtimper = priv->vif->bss_conf.dtim_period; | |
264 | if (setting->power_disabled) | 272 | else |
265 | final_mode = IWL_POWER_MODE_CAM; | 273 | dtimper = 1; |
274 | |||
275 | /* TT power setting overwrites everything */ | ||
276 | if (tt->state >= IWL_TI_1) | ||
277 | iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper); | ||
278 | else if (!enabled) | ||
279 | iwl_power_sleep_cam_cmd(priv, &cmd); | ||
280 | else if (priv->power_data.debug_sleep_level_override >= 0) | ||
281 | iwl_static_sleep_cmd(priv, &cmd, | ||
282 | priv->power_data.debug_sleep_level_override, | ||
283 | dtimper); | ||
284 | else if (no_sleep_autoadjust) | ||
285 | iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_1, dtimper); | ||
286 | else | ||
287 | iwl_power_fill_sleep_cmd(priv, &cmd, | ||
288 | priv->hw->conf.dynamic_ps_timeout, | ||
289 | priv->hw->conf.max_sleep_period); | ||
266 | 290 | ||
267 | if (tt->state >= IWL_TI_1) { | ||
268 | /* TT power setting overwrite user & system power setting */ | ||
269 | final_mode = tt->tt_power_mode; | ||
270 | } | ||
271 | if (iwl_is_ready_rf(priv) && | 291 | if (iwl_is_ready_rf(priv) && |
272 | ((setting->power_mode != final_mode) || force)) { | 292 | (memcmp(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)) || force)) { |
273 | struct iwl_powertable_cmd cmd; | 293 | if (cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK) |
274 | |||
275 | if (final_mode != IWL_POWER_MODE_CAM) | ||
276 | set_bit(STATUS_POWER_PMI, &priv->status); | 294 | set_bit(STATUS_POWER_PMI, &priv->status); |
277 | 295 | ||
278 | iwl_update_power_cmd(priv, &cmd, final_mode); | ||
279 | cmd.keep_alive_beacons = 0; | ||
280 | |||
281 | if (final_mode == IWL_POWER_INDEX_5) | ||
282 | cmd.flags |= IWL_POWER_FAST_PD; | ||
283 | |||
284 | ret = iwl_set_power(priv, &cmd); | 296 | ret = iwl_set_power(priv, &cmd); |
285 | 297 | if (!ret) { | |
286 | if (final_mode == IWL_POWER_MODE_CAM) | 298 | if (!(cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)) |
287 | clear_bit(STATUS_POWER_PMI, &priv->status); | 299 | clear_bit(STATUS_POWER_PMI, &priv->status); |
288 | 300 | ||
289 | if (priv->cfg->ops->lib->update_chain_flags && update_chains) | 301 | if (priv->cfg->ops->lib->update_chain_flags && |
290 | priv->cfg->ops->lib->update_chain_flags(priv); | 302 | update_chains) |
291 | else | 303 | priv->cfg->ops->lib->update_chain_flags(priv); |
292 | IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise " | 304 | else |
305 | IWL_DEBUG_POWER(priv, | ||
306 | "Cannot update the power, chain noise " | ||
293 | "calibration running: %d\n", | 307 | "calibration running: %d\n", |
294 | priv->chain_noise_data.state); | 308 | priv->chain_noise_data.state); |
295 | if (!ret) | 309 | memcpy(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)); |
296 | setting->power_mode = final_mode; | 310 | } else |
311 | IWL_ERR(priv, "set power fail, ret = %d", ret); | ||
297 | } | 312 | } |
298 | 313 | ||
299 | return ret; | 314 | return ret; |
300 | } | 315 | } |
301 | EXPORT_SYMBOL(iwl_power_update_mode); | 316 | EXPORT_SYMBOL(iwl_power_update_mode); |
302 | 317 | ||
303 | /* set user_power_setting */ | ||
304 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) | ||
305 | { | ||
306 | if (mode >= IWL_POWER_NUM) | ||
307 | return -EINVAL; | ||
308 | |||
309 | priv->power_data.user_power_setting = mode; | ||
310 | |||
311 | return iwl_power_update_mode(priv, 0); | ||
312 | } | ||
313 | EXPORT_SYMBOL(iwl_power_set_user_mode); | ||
314 | |||
315 | bool iwl_ht_enabled(struct iwl_priv *priv) | 318 | bool iwl_ht_enabled(struct iwl_priv *priv) |
316 | { | 319 | { |
317 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | 320 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
318 | struct iwl_tt_restriction *restriction; | 321 | struct iwl_tt_restriction *restriction; |
319 | 322 | ||
320 | if (!priv->power_data.adv_tt) | 323 | if (!priv->thermal_throttle.advanced_tt) |
321 | return true; | 324 | return true; |
322 | restriction = tt->restriction + tt->state; | 325 | restriction = tt->restriction + tt->state; |
323 | return restriction->is_ht; | 326 | return restriction->is_ht; |
324 | } | 327 | } |
325 | EXPORT_SYMBOL(iwl_ht_enabled); | 328 | EXPORT_SYMBOL(iwl_ht_enabled); |
326 | 329 | ||
327 | u8 iwl_tx_ant_restriction(struct iwl_priv *priv) | 330 | enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv) |
328 | { | 331 | { |
329 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | 332 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
330 | struct iwl_tt_restriction *restriction; | 333 | struct iwl_tt_restriction *restriction; |
331 | 334 | ||
332 | if (!priv->power_data.adv_tt) | 335 | if (!priv->thermal_throttle.advanced_tt) |
333 | return IWL_TX_MULTI; | 336 | return IWL_ANT_OK_MULTI; |
334 | restriction = tt->restriction + tt->state; | 337 | restriction = tt->restriction + tt->state; |
335 | return restriction->tx_stream; | 338 | return restriction->tx_stream; |
336 | } | 339 | } |
337 | EXPORT_SYMBOL(iwl_tx_ant_restriction); | 340 | EXPORT_SYMBOL(iwl_tx_ant_restriction); |
338 | 341 | ||
339 | u8 iwl_rx_ant_restriction(struct iwl_priv *priv) | 342 | enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv) |
340 | { | 343 | { |
341 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | 344 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
342 | struct iwl_tt_restriction *restriction; | 345 | struct iwl_tt_restriction *restriction; |
343 | 346 | ||
344 | if (!priv->power_data.adv_tt) | 347 | if (!priv->thermal_throttle.advanced_tt) |
345 | return IWL_RX_MULTI; | 348 | return IWL_ANT_OK_MULTI; |
346 | restriction = tt->restriction + tt->state; | 349 | restriction = tt->restriction + tt->state; |
347 | return restriction->rx_stream; | 350 | return restriction->rx_stream; |
348 | } | 351 | } |
349 | EXPORT_SYMBOL(iwl_rx_ant_restriction); | ||
350 | 352 | ||
351 | #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ | 353 | #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ |
352 | 354 | ||
@@ -361,21 +363,21 @@ EXPORT_SYMBOL(iwl_rx_ant_restriction); | |||
361 | static void iwl_tt_check_exit_ct_kill(unsigned long data) | 363 | static void iwl_tt_check_exit_ct_kill(unsigned long data) |
362 | { | 364 | { |
363 | struct iwl_priv *priv = (struct iwl_priv *)data; | 365 | struct iwl_priv *priv = (struct iwl_priv *)data; |
364 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | 366 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
365 | unsigned long flags; | 367 | unsigned long flags; |
366 | 368 | ||
367 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 369 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
368 | return; | 370 | return; |
369 | 371 | ||
370 | if (tt->state == IWL_TI_CT_KILL) { | 372 | if (tt->state == IWL_TI_CT_KILL) { |
371 | if (priv->power_data.ct_kill_toggle) { | 373 | if (priv->thermal_throttle.ct_kill_toggle) { |
372 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, | 374 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, |
373 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); | 375 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); |
374 | priv->power_data.ct_kill_toggle = false; | 376 | priv->thermal_throttle.ct_kill_toggle = false; |
375 | } else { | 377 | } else { |
376 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, | 378 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, |
377 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); | 379 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); |
378 | priv->power_data.ct_kill_toggle = true; | 380 | priv->thermal_throttle.ct_kill_toggle = true; |
379 | } | 381 | } |
380 | iwl_read32(priv, CSR_UCODE_DRV_GP1); | 382 | iwl_read32(priv, CSR_UCODE_DRV_GP1); |
381 | spin_lock_irqsave(&priv->reg_lock, flags); | 383 | spin_lock_irqsave(&priv->reg_lock, flags); |
@@ -386,7 +388,7 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) | |||
386 | /* Reschedule the ct_kill timer to occur in | 388 | /* Reschedule the ct_kill timer to occur in |
387 | * CT_KILL_EXIT_DURATION seconds to ensure we get a | 389 | * CT_KILL_EXIT_DURATION seconds to ensure we get a |
388 | * thermal update */ | 390 | * thermal update */ |
389 | mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + | 391 | mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies + |
390 | CT_KILL_EXIT_DURATION * HZ); | 392 | CT_KILL_EXIT_DURATION * HZ); |
391 | } | 393 | } |
392 | } | 394 | } |
@@ -400,7 +402,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, | |||
400 | ieee80211_stop_queues(priv->hw); | 402 | ieee80211_stop_queues(priv->hw); |
401 | IWL_DEBUG_POWER(priv, | 403 | IWL_DEBUG_POWER(priv, |
402 | "Schedule 5 seconds CT_KILL Timer\n"); | 404 | "Schedule 5 seconds CT_KILL Timer\n"); |
403 | mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + | 405 | mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies + |
404 | CT_KILL_EXIT_DURATION * HZ); | 406 | CT_KILL_EXIT_DURATION * HZ); |
405 | } else { | 407 | } else { |
406 | IWL_DEBUG_POWER(priv, "Wake all queues\n"); | 408 | IWL_DEBUG_POWER(priv, "Wake all queues\n"); |
@@ -424,9 +426,8 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, | |||
424 | */ | 426 | */ |
425 | static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) | 427 | static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) |
426 | { | 428 | { |
427 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | 429 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
428 | enum iwl_tt_state new_state; | 430 | enum iwl_tt_state old_state; |
429 | struct iwl_power_mgr *setting = &priv->power_data; | ||
430 | 431 | ||
431 | #ifdef CONFIG_IWLWIFI_DEBUG | 432 | #ifdef CONFIG_IWLWIFI_DEBUG |
432 | if ((tt->tt_previous_temp) && | 433 | if ((tt->tt_previous_temp) && |
@@ -438,38 +439,28 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) | |||
438 | (temp - tt->tt_previous_temp)); | 439 | (temp - tt->tt_previous_temp)); |
439 | } | 440 | } |
440 | #endif | 441 | #endif |
442 | old_state = tt->state; | ||
441 | /* in Celsius */ | 443 | /* in Celsius */ |
442 | if (temp >= IWL_MINIMAL_POWER_THRESHOLD) | 444 | if (temp >= IWL_MINIMAL_POWER_THRESHOLD) |
443 | new_state = IWL_TI_CT_KILL; | 445 | tt->state = IWL_TI_CT_KILL; |
444 | else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2) | 446 | else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2) |
445 | new_state = IWL_TI_2; | 447 | tt->state = IWL_TI_2; |
446 | else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1) | 448 | else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1) |
447 | new_state = IWL_TI_1; | 449 | tt->state = IWL_TI_1; |
448 | else | 450 | else |
449 | new_state = IWL_TI_0; | 451 | tt->state = IWL_TI_0; |
450 | 452 | ||
451 | #ifdef CONFIG_IWLWIFI_DEBUG | 453 | #ifdef CONFIG_IWLWIFI_DEBUG |
452 | tt->tt_previous_temp = temp; | 454 | tt->tt_previous_temp = temp; |
453 | #endif | 455 | #endif |
454 | if (tt->state != new_state) { | 456 | if (tt->state != old_state) { |
455 | if (tt->state == IWL_TI_0) { | 457 | switch (tt->state) { |
456 | tt->sys_power_mode = setting->power_mode; | ||
457 | IWL_DEBUG_POWER(priv, "current power mode: %u\n", | ||
458 | setting->power_mode); | ||
459 | } | ||
460 | switch (new_state) { | ||
461 | case IWL_TI_0: | 458 | case IWL_TI_0: |
462 | /* when system ready to go back to IWL_TI_0 state | 459 | /* |
463 | * using system power mode instead of TT power mode | 460 | * When the system is ready to go back to IWL_TI_0 |
464 | * revert back to the orginal power mode which was saved | 461 | * we only have to call iwl_power_update_mode() to |
465 | * before enter Thermal Throttling state | 462 | * do so. |
466 | * update priv->power_data.user_power_setting to the | ||
467 | * required power mode to make sure | ||
468 | * iwl_power_update_mode() will update power correctly. | ||
469 | */ | 463 | */ |
470 | priv->power_data.user_power_setting = | ||
471 | tt->sys_power_mode; | ||
472 | tt->tt_power_mode = tt->sys_power_mode; | ||
473 | break; | 464 | break; |
474 | case IWL_TI_1: | 465 | case IWL_TI_1: |
475 | tt->tt_power_mode = IWL_POWER_INDEX_3; | 466 | tt->tt_power_mode = IWL_POWER_INDEX_3; |
@@ -481,24 +472,26 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) | |||
481 | tt->tt_power_mode = IWL_POWER_INDEX_5; | 472 | tt->tt_power_mode = IWL_POWER_INDEX_5; |
482 | break; | 473 | break; |
483 | } | 474 | } |
475 | mutex_lock(&priv->mutex); | ||
484 | if (iwl_power_update_mode(priv, true)) { | 476 | if (iwl_power_update_mode(priv, true)) { |
485 | /* TT state not updated | 477 | /* TT state not updated |
486 | * try again during next temperature read | 478 | * try again during next temperature read |
487 | */ | 479 | */ |
480 | tt->state = old_state; | ||
488 | IWL_ERR(priv, "Cannot update power mode, " | 481 | IWL_ERR(priv, "Cannot update power mode, " |
489 | "TT state not updated\n"); | 482 | "TT state not updated\n"); |
490 | } else { | 483 | } else { |
491 | if (new_state == IWL_TI_CT_KILL) | 484 | if (tt->state == IWL_TI_CT_KILL) |
492 | iwl_perform_ct_kill_task(priv, true); | 485 | iwl_perform_ct_kill_task(priv, true); |
493 | else if (tt->state == IWL_TI_CT_KILL && | 486 | else if (old_state == IWL_TI_CT_KILL && |
494 | new_state != IWL_TI_CT_KILL) | 487 | tt->state != IWL_TI_CT_KILL) |
495 | iwl_perform_ct_kill_task(priv, false); | 488 | iwl_perform_ct_kill_task(priv, false); |
496 | tt->state = new_state; | ||
497 | IWL_DEBUG_POWER(priv, "Temperature state changed %u\n", | 489 | IWL_DEBUG_POWER(priv, "Temperature state changed %u\n", |
498 | tt->state); | 490 | tt->state); |
499 | IWL_DEBUG_POWER(priv, "Power Index change to %u\n", | 491 | IWL_DEBUG_POWER(priv, "Power Index change to %u\n", |
500 | tt->tt_power_mode); | 492 | tt->tt_power_mode); |
501 | } | 493 | } |
494 | mutex_unlock(&priv->mutex); | ||
502 | } | 495 | } |
503 | } | 496 | } |
504 | 497 | ||
@@ -525,7 +518,7 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) | |||
525 | */ | 518 | */ |
526 | static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) | 519 | static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) |
527 | { | 520 | { |
528 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | 521 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
529 | int i; | 522 | int i; |
530 | bool changed = false; | 523 | bool changed = false; |
531 | enum iwl_tt_state old_state; | 524 | enum iwl_tt_state old_state; |
@@ -570,20 +563,15 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) | |||
570 | } | 563 | } |
571 | if (changed) { | 564 | if (changed) { |
572 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; | 565 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; |
573 | struct iwl_power_mgr *setting = &priv->power_data; | ||
574 | 566 | ||
575 | if (tt->state >= IWL_TI_1) { | 567 | if (tt->state >= IWL_TI_1) { |
576 | /* if switching from IWL_TI_0 to other TT state | ||
577 | * save previous power setting in tt->sys_power_mode */ | ||
578 | if (old_state == IWL_TI_0) | ||
579 | tt->sys_power_mode = setting->power_mode; | ||
580 | /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */ | 568 | /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */ |
581 | tt->tt_power_mode = IWL_POWER_INDEX_5; | 569 | tt->tt_power_mode = IWL_POWER_INDEX_5; |
582 | if (!iwl_ht_enabled(priv)) | 570 | if (!iwl_ht_enabled(priv)) |
583 | /* disable HT */ | 571 | /* disable HT */ |
584 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | | 572 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | |
585 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | | 573 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | |
586 | RXON_FLG_FAT_PROT_MSK | | 574 | RXON_FLG_HT40_PROT_MSK | |
587 | RXON_FLG_HT_PROT_MSK); | 575 | RXON_FLG_HT_PROT_MSK); |
588 | else { | 576 | else { |
589 | /* check HT capability and set | 577 | /* check HT capability and set |
@@ -593,22 +581,17 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) | |||
593 | } | 581 | } |
594 | 582 | ||
595 | } else { | 583 | } else { |
596 | /* restore system power setting */ | 584 | /* |
597 | /* the previous power mode was saved in | 585 | * restore system power setting -- it will be |
598 | * tt->sys_power_mode when system move into | 586 | * recalculated automatically. |
599 | * Thermal Throttling state | ||
600 | * set power_data.user_power_setting to the previous | ||
601 | * system power mode to make sure power will get | ||
602 | * updated correctly | ||
603 | */ | 587 | */ |
604 | priv->power_data.user_power_setting = | 588 | |
605 | tt->sys_power_mode; | ||
606 | tt->tt_power_mode = tt->sys_power_mode; | ||
607 | /* check HT capability and set | 589 | /* check HT capability and set |
608 | * according to the system HT capability | 590 | * according to the system HT capability |
609 | * in case get disabled before */ | 591 | * in case get disabled before */ |
610 | iwl_set_rxon_ht(priv, &priv->current_ht_config); | 592 | iwl_set_rxon_ht(priv, &priv->current_ht_config); |
611 | } | 593 | } |
594 | mutex_lock(&priv->mutex); | ||
612 | if (iwl_power_update_mode(priv, true)) { | 595 | if (iwl_power_update_mode(priv, true)) { |
613 | /* TT state not updated | 596 | /* TT state not updated |
614 | * try again during next temperature read | 597 | * try again during next temperature read |
@@ -631,6 +614,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) | |||
631 | iwl_perform_ct_kill_task(priv, false); | 614 | iwl_perform_ct_kill_task(priv, false); |
632 | } | 615 | } |
633 | } | 616 | } |
617 | mutex_unlock(&priv->mutex); | ||
634 | } | 618 | } |
635 | } | 619 | } |
636 | 620 | ||
@@ -644,17 +628,21 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) | |||
644 | * for advance mode | 628 | * for advance mode |
645 | * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state | 629 | * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state |
646 | */ | 630 | */ |
647 | void iwl_tt_enter_ct_kill(struct iwl_priv *priv) | 631 | static void iwl_bg_ct_enter(struct work_struct *work) |
648 | { | 632 | { |
649 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | 633 | struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter); |
634 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; | ||
650 | 635 | ||
651 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 636 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
652 | return; | 637 | return; |
653 | 638 | ||
639 | if (!iwl_is_ready(priv)) | ||
640 | return; | ||
641 | |||
654 | if (tt->state != IWL_TI_CT_KILL) { | 642 | if (tt->state != IWL_TI_CT_KILL) { |
655 | IWL_ERR(priv, "Device reached critical temperature " | 643 | IWL_ERR(priv, "Device reached critical temperature " |
656 | "- ucode going to sleep!\n"); | 644 | "- ucode going to sleep!\n"); |
657 | if (!priv->power_data.adv_tt) | 645 | if (!priv->thermal_throttle.advanced_tt) |
658 | iwl_legacy_tt_handler(priv, | 646 | iwl_legacy_tt_handler(priv, |
659 | IWL_MINIMAL_POWER_THRESHOLD); | 647 | IWL_MINIMAL_POWER_THRESHOLD); |
660 | else | 648 | else |
@@ -662,38 +650,61 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv) | |||
662 | CT_KILL_THRESHOLD + 1); | 650 | CT_KILL_THRESHOLD + 1); |
663 | } | 651 | } |
664 | } | 652 | } |
665 | EXPORT_SYMBOL(iwl_tt_enter_ct_kill); | ||
666 | 653 | ||
667 | /* Card State Notification indicated out of critical temperature | 654 | /* Card State Notification indicated out of critical temperature |
668 | * since Card State Notification will not provide any temperature reading | 655 | * since Card State Notification will not provide any temperature reading |
669 | * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature | 656 | * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature |
670 | * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state | 657 | * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state |
671 | */ | 658 | */ |
672 | void iwl_tt_exit_ct_kill(struct iwl_priv *priv) | 659 | static void iwl_bg_ct_exit(struct work_struct *work) |
673 | { | 660 | { |
674 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | 661 | struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit); |
662 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; | ||
675 | 663 | ||
676 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 664 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
677 | return; | 665 | return; |
678 | 666 | ||
667 | if (!iwl_is_ready(priv)) | ||
668 | return; | ||
669 | |||
679 | /* stop ct_kill_exit_tm timer */ | 670 | /* stop ct_kill_exit_tm timer */ |
680 | del_timer_sync(&priv->power_data.ct_kill_exit_tm); | 671 | del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm); |
681 | 672 | ||
682 | if (tt->state == IWL_TI_CT_KILL) { | 673 | if (tt->state == IWL_TI_CT_KILL) { |
683 | IWL_ERR(priv, | 674 | IWL_ERR(priv, |
684 | "Device temperature below critical" | 675 | "Device temperature below critical" |
685 | "- ucode awake!\n"); | 676 | "- ucode awake!\n"); |
686 | if (!priv->power_data.adv_tt) | 677 | if (!priv->thermal_throttle.advanced_tt) |
687 | iwl_legacy_tt_handler(priv, | 678 | iwl_legacy_tt_handler(priv, |
688 | IWL_REDUCED_PERFORMANCE_THRESHOLD_2); | 679 | IWL_REDUCED_PERFORMANCE_THRESHOLD_2); |
689 | else | 680 | else |
690 | iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD); | 681 | iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD); |
691 | } | 682 | } |
692 | } | 683 | } |
684 | |||
685 | void iwl_tt_enter_ct_kill(struct iwl_priv *priv) | ||
686 | { | ||
687 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
688 | return; | ||
689 | |||
690 | IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n"); | ||
691 | queue_work(priv->workqueue, &priv->ct_enter); | ||
692 | } | ||
693 | EXPORT_SYMBOL(iwl_tt_enter_ct_kill); | ||
694 | |||
695 | void iwl_tt_exit_ct_kill(struct iwl_priv *priv) | ||
696 | { | ||
697 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
698 | return; | ||
699 | |||
700 | IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n"); | ||
701 | queue_work(priv->workqueue, &priv->ct_exit); | ||
702 | } | ||
693 | EXPORT_SYMBOL(iwl_tt_exit_ct_kill); | 703 | EXPORT_SYMBOL(iwl_tt_exit_ct_kill); |
694 | 704 | ||
695 | void iwl_tt_handler(struct iwl_priv *priv) | 705 | static void iwl_bg_tt_work(struct work_struct *work) |
696 | { | 706 | { |
707 | struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work); | ||
697 | s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */ | 708 | s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */ |
698 | 709 | ||
699 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 710 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
@@ -702,11 +713,20 @@ void iwl_tt_handler(struct iwl_priv *priv) | |||
702 | if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) | 713 | if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) |
703 | temp = KELVIN_TO_CELSIUS(priv->temperature); | 714 | temp = KELVIN_TO_CELSIUS(priv->temperature); |
704 | 715 | ||
705 | if (!priv->power_data.adv_tt) | 716 | if (!priv->thermal_throttle.advanced_tt) |
706 | iwl_legacy_tt_handler(priv, temp); | 717 | iwl_legacy_tt_handler(priv, temp); |
707 | else | 718 | else |
708 | iwl_advance_tt_handler(priv, temp); | 719 | iwl_advance_tt_handler(priv, temp); |
709 | } | 720 | } |
721 | |||
722 | void iwl_tt_handler(struct iwl_priv *priv) | ||
723 | { | ||
724 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
725 | return; | ||
726 | |||
727 | IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n"); | ||
728 | queue_work(priv->workqueue, &priv->tt_work); | ||
729 | } | ||
710 | EXPORT_SYMBOL(iwl_tt_handler); | 730 | EXPORT_SYMBOL(iwl_tt_handler); |
711 | 731 | ||
712 | /* Thermal throttling initialization | 732 | /* Thermal throttling initialization |
@@ -716,8 +736,7 @@ EXPORT_SYMBOL(iwl_tt_handler); | |||
716 | */ | 736 | */ |
717 | void iwl_tt_initialize(struct iwl_priv *priv) | 737 | void iwl_tt_initialize(struct iwl_priv *priv) |
718 | { | 738 | { |
719 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | 739 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
720 | struct iwl_power_mgr *setting = &priv->power_data; | ||
721 | int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1); | 740 | int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1); |
722 | struct iwl_tt_trans *transaction; | 741 | struct iwl_tt_trans *transaction; |
723 | 742 | ||
@@ -726,11 +745,15 @@ void iwl_tt_initialize(struct iwl_priv *priv) | |||
726 | memset(tt, 0, sizeof(struct iwl_tt_mgmt)); | 745 | memset(tt, 0, sizeof(struct iwl_tt_mgmt)); |
727 | 746 | ||
728 | tt->state = IWL_TI_0; | 747 | tt->state = IWL_TI_0; |
729 | tt->sys_power_mode = setting->power_mode; | 748 | init_timer(&priv->thermal_throttle.ct_kill_exit_tm); |
730 | tt->tt_power_mode = tt->sys_power_mode; | 749 | priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv; |
731 | init_timer(&priv->power_data.ct_kill_exit_tm); | 750 | priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; |
732 | priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; | 751 | |
733 | priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; | 752 | /* setup deferred ct kill work */ |
753 | INIT_WORK(&priv->tt_work, iwl_bg_tt_work); | ||
754 | INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); | ||
755 | INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit); | ||
756 | |||
734 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { | 757 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { |
735 | case CSR_HW_REV_TYPE_6x00: | 758 | case CSR_HW_REV_TYPE_6x00: |
736 | case CSR_HW_REV_TYPE_6x50: | 759 | case CSR_HW_REV_TYPE_6x50: |
@@ -742,7 +765,7 @@ void iwl_tt_initialize(struct iwl_priv *priv) | |||
742 | GFP_KERNEL); | 765 | GFP_KERNEL); |
743 | if (!tt->restriction || !tt->transaction) { | 766 | if (!tt->restriction || !tt->transaction) { |
744 | IWL_ERR(priv, "Fallback to Legacy Throttling\n"); | 767 | IWL_ERR(priv, "Fallback to Legacy Throttling\n"); |
745 | priv->power_data.adv_tt = false; | 768 | priv->thermal_throttle.advanced_tt = false; |
746 | kfree(tt->restriction); | 769 | kfree(tt->restriction); |
747 | tt->restriction = NULL; | 770 | tt->restriction = NULL; |
748 | kfree(tt->transaction); | 771 | kfree(tt->transaction); |
@@ -764,12 +787,12 @@ void iwl_tt_initialize(struct iwl_priv *priv) | |||
764 | IWL_TI_STATE_MAX; | 787 | IWL_TI_STATE_MAX; |
765 | memcpy(tt->restriction, | 788 | memcpy(tt->restriction, |
766 | &restriction_range[0], size); | 789 | &restriction_range[0], size); |
767 | priv->power_data.adv_tt = true; | 790 | priv->thermal_throttle.advanced_tt = true; |
768 | } | 791 | } |
769 | break; | 792 | break; |
770 | default: | 793 | default: |
771 | IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n"); | 794 | IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n"); |
772 | priv->power_data.adv_tt = false; | 795 | priv->thermal_throttle.advanced_tt = false; |
773 | break; | 796 | break; |
774 | } | 797 | } |
775 | } | 798 | } |
@@ -778,12 +801,15 @@ EXPORT_SYMBOL(iwl_tt_initialize); | |||
778 | /* cleanup thermal throttling management related memory and timer */ | 801 | /* cleanup thermal throttling management related memory and timer */ |
779 | void iwl_tt_exit(struct iwl_priv *priv) | 802 | void iwl_tt_exit(struct iwl_priv *priv) |
780 | { | 803 | { |
781 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | 804 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
782 | 805 | ||
783 | /* stop ct_kill_exit_tm timer if activated */ | 806 | /* stop ct_kill_exit_tm timer if activated */ |
784 | del_timer_sync(&priv->power_data.ct_kill_exit_tm); | 807 | del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm); |
808 | cancel_work_sync(&priv->tt_work); | ||
809 | cancel_work_sync(&priv->ct_enter); | ||
810 | cancel_work_sync(&priv->ct_exit); | ||
785 | 811 | ||
786 | if (priv->power_data.adv_tt) { | 812 | if (priv->thermal_throttle.advanced_tt) { |
787 | /* free advance thermal throttling memory */ | 813 | /* free advance thermal throttling memory */ |
788 | kfree(tt->restriction); | 814 | kfree(tt->restriction); |
789 | tt->restriction = NULL; | 815 | tt->restriction = NULL; |
@@ -796,9 +822,13 @@ EXPORT_SYMBOL(iwl_tt_exit); | |||
796 | /* initialize to default */ | 822 | /* initialize to default */ |
797 | void iwl_power_initialize(struct iwl_priv *priv) | 823 | void iwl_power_initialize(struct iwl_priv *priv) |
798 | { | 824 | { |
799 | iwl_power_init_handle(priv); | 825 | u16 lctl = iwl_pcie_link_ctl(priv); |
800 | priv->power_data.user_power_setting = IWL_POWER_INDEX_1; | 826 | |
801 | /* default to disabled until mac80211 says otherwise */ | 827 | priv->power_data.pci_pm = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN); |
802 | priv->power_data.power_disabled = 1; | 828 | |
829 | priv->power_data.debug_sleep_level_override = -1; | ||
830 | |||
831 | memset(&priv->power_data.sleep_cmd, 0, | ||
832 | sizeof(priv->power_data.sleep_cmd)); | ||
803 | } | 833 | } |
804 | EXPORT_SYMBOL(iwl_power_initialize); | 834 | EXPORT_SYMBOL(iwl_power_initialize); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 3d49b7a45b74..df6f6a49712b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h | |||
@@ -28,22 +28,17 @@ | |||
28 | #ifndef __iwl_power_setting_h__ | 28 | #ifndef __iwl_power_setting_h__ |
29 | #define __iwl_power_setting_h__ | 29 | #define __iwl_power_setting_h__ |
30 | 30 | ||
31 | #include <net/mac80211.h> | ||
32 | #include "iwl-commands.h" | 31 | #include "iwl-commands.h" |
33 | 32 | ||
34 | struct iwl_priv; | ||
35 | |||
36 | #define IWL_ABSOLUTE_ZERO 0 | 33 | #define IWL_ABSOLUTE_ZERO 0 |
37 | #define IWL_ABSOLUTE_MAX 0xFFFFFFFF | 34 | #define IWL_ABSOLUTE_MAX 0xFFFFFFFF |
38 | #define IWL_TT_INCREASE_MARGIN 5 | 35 | #define IWL_TT_INCREASE_MARGIN 5 |
39 | 36 | ||
40 | /* Tx/Rx restrictions */ | 37 | enum iwl_antenna_ok { |
41 | #define IWL_TX_MULTI 0x02 | 38 | IWL_ANT_OK_NONE, |
42 | #define IWL_TX_SINGLE 0x01 | 39 | IWL_ANT_OK_SINGLE, |
43 | #define IWL_TX_NONE 0x00 | 40 | IWL_ANT_OK_MULTI, |
44 | #define IWL_RX_MULTI 0x02 | 41 | }; |
45 | #define IWL_RX_SINGLE 0x01 | ||
46 | #define IWL_RX_NONE 0x00 | ||
47 | 42 | ||
48 | /* Thermal Throttling State Machine states */ | 43 | /* Thermal Throttling State Machine states */ |
49 | enum iwl_tt_state { | 44 | enum iwl_tt_state { |
@@ -55,27 +50,30 @@ enum iwl_tt_state { | |||
55 | }; | 50 | }; |
56 | 51 | ||
57 | /** | 52 | /** |
58 | * struct iwl_tt_restriction - Thermal Throttling restriction table used | 53 | * struct iwl_tt_restriction - Thermal Throttling restriction table |
59 | * by advance thermal throttling management | ||
60 | * based on the current thermal throttling state, determine | ||
61 | * number of tx/rx streams; and the status of HT operation | ||
62 | * @tx_stream: number of tx stream allowed | 54 | * @tx_stream: number of tx stream allowed |
63 | * @is_ht: ht enable/disable | 55 | * @is_ht: ht enable/disable |
64 | * @rx_stream: number of rx stream allowed | 56 | * @rx_stream: number of rx stream allowed |
57 | * | ||
58 | * This table is used by advance thermal throttling management | ||
59 | * based on the current thermal throttling state, and determines | ||
60 | * the number of tx/rx streams and the status of HT operation. | ||
65 | */ | 61 | */ |
66 | struct iwl_tt_restriction { | 62 | struct iwl_tt_restriction { |
67 | u8 tx_stream; | 63 | enum iwl_antenna_ok tx_stream; |
64 | enum iwl_antenna_ok rx_stream; | ||
68 | bool is_ht; | 65 | bool is_ht; |
69 | u8 rx_stream; | ||
70 | }; | 66 | }; |
71 | 67 | ||
72 | /** | 68 | /** |
73 | * struct iwl_tt_trans - Thermal Throttling transaction table; used by | 69 | * struct iwl_tt_trans - Thermal Throttling transaction table |
74 | * advance thermal throttling algorithm to determine next | ||
75 | * thermal state to go based on the current temperature | ||
76 | * @next_state: next thermal throttling mode | 70 | * @next_state: next thermal throttling mode |
77 | * @tt_low: low temperature threshold to change state | 71 | * @tt_low: low temperature threshold to change state |
78 | * @tt_high: high temperature threshold to change state | 72 | * @tt_high: high temperature threshold to change state |
73 | * | ||
74 | * This is used by the advanced thermal throttling algorithm | ||
75 | * to determine the next thermal state to go based on the | ||
76 | * current temperature. | ||
79 | */ | 77 | */ |
80 | struct iwl_tt_trans { | 78 | struct iwl_tt_trans { |
81 | enum iwl_tt_state next_state; | 79 | enum iwl_tt_state next_state; |
@@ -85,34 +83,36 @@ struct iwl_tt_trans { | |||
85 | 83 | ||
86 | /** | 84 | /** |
87 | * struct iwl_tt_mgnt - Thermal Throttling Management structure | 85 | * struct iwl_tt_mgnt - Thermal Throttling Management structure |
86 | * @advanced_tt: advanced thermal throttle required | ||
88 | * @state: current Thermal Throttling state | 87 | * @state: current Thermal Throttling state |
89 | * @tt_power_mode: Thermal Throttling power mode index | 88 | * @tt_power_mode: Thermal Throttling power mode index |
90 | * being used to set power level when | 89 | * being used to set power level when |
91 | * when thermal throttling state != IWL_TI_0 | 90 | * when thermal throttling state != IWL_TI_0 |
92 | * the tt_power_mode should set to different | 91 | * the tt_power_mode should set to different |
93 | * power mode based on the current tt state | 92 | * power mode based on the current tt state |
94 | * @sys_power_mode: previous system power mode | ||
95 | * before transition into TT state | ||
96 | * @tt_previous_temperature: last measured temperature | 93 | * @tt_previous_temperature: last measured temperature |
97 | * @iwl_tt_restriction: ptr to restriction tbl, used by advance | 94 | * @iwl_tt_restriction: ptr to restriction tbl, used by advance |
98 | * thermal throttling to determine how many tx/rx streams | 95 | * thermal throttling to determine how many tx/rx streams |
99 | * should be used in tt state; and can HT be enabled or not | 96 | * should be used in tt state; and can HT be enabled or not |
100 | * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling | 97 | * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling |
101 | * state transaction | 98 | * state transaction |
99 | * @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature | ||
100 | * @ct_kill_exit_tm: timer to exit thermal kill | ||
102 | */ | 101 | */ |
103 | struct iwl_tt_mgmt { | 102 | struct iwl_tt_mgmt { |
104 | enum iwl_tt_state state; | 103 | enum iwl_tt_state state; |
104 | bool advanced_tt; | ||
105 | u8 tt_power_mode; | 105 | u8 tt_power_mode; |
106 | u8 sys_power_mode; | 106 | bool ct_kill_toggle; |
107 | #ifdef CONFIG_IWLWIFI_DEBUG | 107 | #ifdef CONFIG_IWLWIFI_DEBUG |
108 | s32 tt_previous_temp; | 108 | s32 tt_previous_temp; |
109 | #endif | 109 | #endif |
110 | struct iwl_tt_restriction *restriction; | 110 | struct iwl_tt_restriction *restriction; |
111 | struct iwl_tt_trans *transaction; | 111 | struct iwl_tt_trans *transaction; |
112 | struct timer_list ct_kill_exit_tm; | ||
112 | }; | 113 | }; |
113 | 114 | ||
114 | enum { | 115 | enum iwl_power_level { |
115 | IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */ | ||
116 | IWL_POWER_INDEX_1, | 116 | IWL_POWER_INDEX_1, |
117 | IWL_POWER_INDEX_2, | 117 | IWL_POWER_INDEX_2, |
118 | IWL_POWER_INDEX_3, | 118 | IWL_POWER_INDEX_3, |
@@ -121,36 +121,16 @@ enum { | |||
121 | IWL_POWER_NUM | 121 | IWL_POWER_NUM |
122 | }; | 122 | }; |
123 | 123 | ||
124 | /* Power management (not Tx power) structures */ | ||
125 | |||
126 | struct iwl_power_vec_entry { | ||
127 | struct iwl_powertable_cmd cmd; | ||
128 | u8 no_dtim; | ||
129 | }; | ||
130 | |||
131 | struct iwl_power_mgr { | 124 | struct iwl_power_mgr { |
132 | struct iwl_power_vec_entry pwr_range_0[IWL_POWER_NUM]; | 125 | struct iwl_powertable_cmd sleep_cmd; |
133 | struct iwl_power_vec_entry pwr_range_1[IWL_POWER_NUM]; | 126 | int debug_sleep_level_override; |
134 | struct iwl_power_vec_entry pwr_range_2[IWL_POWER_NUM]; | 127 | bool pci_pm; |
135 | u32 dtim_period; | ||
136 | /* final power level that used to calculate final power command */ | ||
137 | u8 power_mode; | ||
138 | u8 user_power_setting; /* set by user through sysfs */ | ||
139 | u8 power_disabled; /* set by mac80211's CONF_PS */ | ||
140 | struct iwl_tt_mgmt tt; /* Thermal Throttling Management */ | ||
141 | bool adv_tt; /* false: legacy mode */ | ||
142 | /* true: advance mode */ | ||
143 | bool ct_kill_toggle; /* use to toggle the CSR bit when | ||
144 | * checking uCode temperature | ||
145 | */ | ||
146 | struct timer_list ct_kill_exit_tm; | ||
147 | }; | 128 | }; |
148 | 129 | ||
149 | int iwl_power_update_mode(struct iwl_priv *priv, bool force); | 130 | int iwl_power_update_mode(struct iwl_priv *priv, bool force); |
150 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); | ||
151 | bool iwl_ht_enabled(struct iwl_priv *priv); | 131 | bool iwl_ht_enabled(struct iwl_priv *priv); |
152 | u8 iwl_tx_ant_restriction(struct iwl_priv *priv); | 132 | enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv); |
153 | u8 iwl_rx_ant_restriction(struct iwl_priv *priv); | 133 | enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv); |
154 | void iwl_tt_enter_ct_kill(struct iwl_priv *priv); | 134 | void iwl_tt_enter_ct_kill(struct iwl_priv *priv); |
155 | void iwl_tt_exit_ct_kill(struct iwl_priv *priv); | 135 | void iwl_tt_exit_ct_kill(struct iwl_priv *priv); |
156 | void iwl_tt_handler(struct iwl_priv *priv); | 136 | void iwl_tt_handler(struct iwl_priv *priv); |
@@ -158,4 +138,6 @@ void iwl_tt_initialize(struct iwl_priv *priv); | |||
158 | void iwl_tt_exit(struct iwl_priv *priv); | 138 | void iwl_tt_exit(struct iwl_priv *priv); |
159 | void iwl_power_initialize(struct iwl_priv *priv); | 139 | void iwl_power_initialize(struct iwl_priv *priv); |
160 | 140 | ||
141 | extern bool no_sleep_autoadjust; | ||
142 | |||
161 | #endif /* __iwl_power_setting_h__ */ | 143 | #endif /* __iwl_power_setting_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index e002c8b56c49..43b2fce4cbf0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -544,8 +544,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
544 | change = ((priv->statistics.general.temperature != | 544 | change = ((priv->statistics.general.temperature != |
545 | pkt->u.stats.general.temperature) || | 545 | pkt->u.stats.general.temperature) || |
546 | ((priv->statistics.flag & | 546 | ((priv->statistics.flag & |
547 | STATISTICS_REPLY_FLG_FAT_MODE_MSK) != | 547 | STATISTICS_REPLY_FLG_HT40_MODE_MSK) != |
548 | (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK))); | 548 | (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK))); |
549 | 549 | ||
550 | memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); | 550 | memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); |
551 | 551 | ||
@@ -645,7 +645,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, | |||
645 | u32 tsf_low; | 645 | u32 tsf_low; |
646 | int rssi; | 646 | int rssi; |
647 | 647 | ||
648 | if (likely(!(iwl_debug_level & IWL_DL_RX))) | 648 | if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX))) |
649 | return; | 649 | return; |
650 | 650 | ||
651 | /* MAC header */ | 651 | /* MAC header */ |
@@ -741,18 +741,10 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, | |||
741 | } | 741 | } |
742 | } | 742 | } |
743 | if (print_dump) | 743 | if (print_dump) |
744 | iwl_print_hex_dump(IWL_DL_RX, header, length); | 744 | iwl_print_hex_dump(priv, IWL_DL_RX, header, length); |
745 | } | 745 | } |
746 | #endif | 746 | #endif |
747 | 747 | ||
748 | static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) | ||
749 | { | ||
750 | /* 0 - mgmt, 1 - cnt, 2 - data */ | ||
751 | int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; | ||
752 | priv->rx_stats[idx].cnt++; | ||
753 | priv->rx_stats[idx].bytes += len; | ||
754 | } | ||
755 | |||
756 | /* | 748 | /* |
757 | * returns non-zero if packet should be dropped | 749 | * returns non-zero if packet should be dropped |
758 | */ | 750 | */ |
@@ -930,7 +922,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
930 | iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) | 922 | iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) |
931 | return; | 923 | return; |
932 | 924 | ||
933 | iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); | 925 | iwl_update_stats(priv, false, hdr->frame_control, len); |
934 | memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); | 926 | memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); |
935 | ieee80211_rx_irqsafe(priv->hw, rxb->skb); | 927 | ieee80211_rx_irqsafe(priv->hw, rxb->skb); |
936 | priv->alloc_rxb_skb--; | 928 | priv->alloc_rxb_skb--; |
@@ -1060,9 +1052,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, | |||
1060 | 1052 | ||
1061 | /* Set "1" to report good data frames in groups of 100 */ | 1053 | /* Set "1" to report good data frames in groups of 100 */ |
1062 | #ifdef CONFIG_IWLWIFI_DEBUG | 1054 | #ifdef CONFIG_IWLWIFI_DEBUG |
1063 | if (unlikely(iwl_debug_level & IWL_DL_RX)) | 1055 | if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) |
1064 | iwl_dbg_report_frame(priv, rx_start, len, header, 1); | 1056 | iwl_dbg_report_frame(priv, rx_start, len, header, 1); |
1065 | #endif | 1057 | #endif |
1058 | iwl_dbg_log_rx_data_frame(priv, len, header); | ||
1066 | IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", | 1059 | IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", |
1067 | rx_status.signal, rx_status.noise, rx_status.qual, | 1060 | rx_status.signal, rx_status.noise, rx_status.qual, |
1068 | (unsigned long long)rx_status.mactime); | 1061 | (unsigned long long)rx_status.mactime); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index efcae0d5e193..c6633fec8216 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -214,10 +214,10 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, | |||
214 | sta_flags |= cpu_to_le32( | 214 | sta_flags |= cpu_to_le32( |
215 | (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); | 215 | (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); |
216 | 216 | ||
217 | if (iwl_is_fat_tx_allowed(priv, sta_ht_inf)) | 217 | if (iwl_is_ht40_tx_allowed(priv, sta_ht_inf)) |
218 | sta_flags |= STA_FLG_FAT_EN_MSK; | 218 | sta_flags |= STA_FLG_HT40_EN_MSK; |
219 | else | 219 | else |
220 | sta_flags &= ~STA_FLG_FAT_EN_MSK; | 220 | sta_flags &= ~STA_FLG_HT40_EN_MSK; |
221 | 221 | ||
222 | priv->stations[index].sta.station_flags = sta_flags; | 222 | priv->stations[index].sta.station_flags = sta_flags; |
223 | done: | 223 | done: |
@@ -1088,7 +1088,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) | |||
1088 | IWL_DEBUG_DROP(priv, "Station %pM not in station map. " | 1088 | IWL_DEBUG_DROP(priv, "Station %pM not in station map. " |
1089 | "Defaulting to broadcast...\n", | 1089 | "Defaulting to broadcast...\n", |
1090 | hdr->addr1); | 1090 | hdr->addr1); |
1091 | iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); | 1091 | iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); |
1092 | return priv->hw_params.bcast_sta_id; | 1092 | return priv->hw_params.bcast_sta_id; |
1093 | 1093 | ||
1094 | default: | 1094 | default: |
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 288b871e974b..9b76bd41f214 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
@@ -668,14 +668,6 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, | |||
668 | } | 668 | } |
669 | } | 669 | } |
670 | 670 | ||
671 | static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) | ||
672 | { | ||
673 | /* 0 - mgmt, 1 - cnt, 2 - data */ | ||
674 | int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; | ||
675 | priv->tx_stats[idx].cnt++; | ||
676 | priv->tx_stats[idx].bytes += len; | ||
677 | } | ||
678 | |||
679 | /* | 671 | /* |
680 | * start REPLY_TX command process | 672 | * start REPLY_TX command process |
681 | */ | 673 | */ |
@@ -808,12 +800,12 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
808 | 800 | ||
809 | /* TODO need this for burst mode later on */ | 801 | /* TODO need this for burst mode later on */ |
810 | iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id); | 802 | iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id); |
803 | iwl_dbg_log_tx_data_frame(priv, len, hdr); | ||
811 | 804 | ||
812 | /* set is_hcca to 0; it probably will never be implemented */ | 805 | /* set is_hcca to 0; it probably will never be implemented */ |
813 | iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); | 806 | iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); |
814 | 807 | ||
815 | iwl_update_tx_stats(priv, le16_to_cpu(fc), len); | 808 | iwl_update_stats(priv, true, fc, len); |
816 | |||
817 | /* | 809 | /* |
818 | * Use the first empty entry in this queue's command buffer array | 810 | * Use the first empty entry in this queue's command buffer array |
819 | * to contain the Tx command and MAC header concatenated together | 811 | * to contain the Tx command and MAC header concatenated together |
@@ -884,8 +876,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
884 | IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", | 876 | IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", |
885 | le16_to_cpu(out_cmd->hdr.sequence)); | 877 | le16_to_cpu(out_cmd->hdr.sequence)); |
886 | IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags)); | 878 | IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags)); |
887 | iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); | 879 | iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); |
888 | iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); | 880 | iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); |
889 | 881 | ||
890 | /* Set up entry for this TFD in Tx byte-count array */ | 882 | /* Set up entry for this TFD in Tx byte-count array */ |
891 | if (info->flags & IEEE80211_TX_CTL_AMPDU) | 883 | if (info->flags & IEEE80211_TX_CTL_AMPDU) |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index ea051b739ba2..e617411d0c5e 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -598,7 +598,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
598 | len = (u16)skb->len; | 598 | len = (u16)skb->len; |
599 | tx->len = cpu_to_le16(len); | 599 | tx->len = cpu_to_le16(len); |
600 | 600 | ||
601 | 601 | iwl_dbg_log_tx_data_frame(priv, len, hdr); | |
602 | iwl_update_stats(priv, true, fc, len); | ||
602 | tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; | 603 | tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; |
603 | tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; | 604 | tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; |
604 | 605 | ||
@@ -614,8 +615,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
614 | IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", | 615 | IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", |
615 | le16_to_cpu(out_cmd->hdr.sequence)); | 616 | le16_to_cpu(out_cmd->hdr.sequence)); |
616 | IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags)); | 617 | IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags)); |
617 | iwl_print_hex_dump(IWL_DL_TX, tx, sizeof(*tx)); | 618 | iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx)); |
618 | iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx->hdr, | 619 | iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr, |
619 | ieee80211_hdrlen(fc)); | 620 | ieee80211_hdrlen(fc)); |
620 | 621 | ||
621 | /* | 622 | /* |
@@ -1646,7 +1647,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) | |||
1646 | iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); | 1647 | iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); |
1647 | 1648 | ||
1648 | #ifdef CONFIG_IWLWIFI_DEBUG | 1649 | #ifdef CONFIG_IWLWIFI_DEBUG |
1649 | if (iwl_debug_level & IWL_DL_ISR) { | 1650 | if (iwl_get_debug_level(priv) & IWL_DL_ISR) { |
1650 | /* just for debug */ | 1651 | /* just for debug */ |
1651 | inta_mask = iwl_read32(priv, CSR_INT_MASK); | 1652 | inta_mask = iwl_read32(priv, CSR_INT_MASK); |
1652 | IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", | 1653 | IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", |
@@ -1681,7 +1682,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) | |||
1681 | } | 1682 | } |
1682 | 1683 | ||
1683 | #ifdef CONFIG_IWLWIFI_DEBUG | 1684 | #ifdef CONFIG_IWLWIFI_DEBUG |
1684 | if (iwl_debug_level & (IWL_DL_ISR)) { | 1685 | if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { |
1685 | /* NIC fires this, but we don't use it, redundant with WAKEUP */ | 1686 | /* NIC fires this, but we don't use it, redundant with WAKEUP */ |
1686 | if (inta & CSR_INT_BIT_SCD) { | 1687 | if (inta & CSR_INT_BIT_SCD) { |
1687 | IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " | 1688 | IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " |
@@ -1760,7 +1761,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) | |||
1760 | iwl_enable_interrupts(priv); | 1761 | iwl_enable_interrupts(priv); |
1761 | 1762 | ||
1762 | #ifdef CONFIG_IWLWIFI_DEBUG | 1763 | #ifdef CONFIG_IWLWIFI_DEBUG |
1763 | if (iwl_debug_level & (IWL_DL_ISR)) { | 1764 | if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { |
1764 | inta = iwl_read32(priv, CSR_INT); | 1765 | inta = iwl_read32(priv, CSR_INT); |
1765 | inta_mask = iwl_read32(priv, CSR_INT_MASK); | 1766 | inta_mask = iwl_read32(priv, CSR_INT_MASK); |
1766 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | 1767 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); |
@@ -3311,14 +3312,15 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3311 | * | 3312 | * |
3312 | * See the level definitions in iwl for details. | 3313 | * See the level definitions in iwl for details. |
3313 | * | 3314 | * |
3314 | * FIXME This file can be deprecated as the module parameter is | 3315 | * The debug_level being managed using sysfs below is a per device debug |
3315 | * writable and users can thus also change the debug level | 3316 | * level that is used instead of the global debug level if it (the per |
3316 | * using the /sys/module/iwl3945/parameters/debug file. | 3317 | * device debug level) is set. |
3317 | */ | 3318 | */ |
3318 | static ssize_t show_debug_level(struct device *d, | 3319 | static ssize_t show_debug_level(struct device *d, |
3319 | struct device_attribute *attr, char *buf) | 3320 | struct device_attribute *attr, char *buf) |
3320 | { | 3321 | { |
3321 | return sprintf(buf, "0x%08X\n", iwl_debug_level); | 3322 | struct iwl_priv *priv = dev_get_drvdata(d); |
3323 | return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); | ||
3322 | } | 3324 | } |
3323 | static ssize_t store_debug_level(struct device *d, | 3325 | static ssize_t store_debug_level(struct device *d, |
3324 | struct device_attribute *attr, | 3326 | struct device_attribute *attr, |
@@ -3331,9 +3333,12 @@ static ssize_t store_debug_level(struct device *d, | |||
3331 | ret = strict_strtoul(buf, 0, &val); | 3333 | ret = strict_strtoul(buf, 0, &val); |
3332 | if (ret) | 3334 | if (ret) |
3333 | IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf); | 3335 | IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf); |
3334 | else | 3336 | else { |
3335 | iwl_debug_level = val; | 3337 | priv->debug_level = val; |
3336 | 3338 | if (iwl_alloc_traffic_mem(priv)) | |
3339 | IWL_ERR(priv, | ||
3340 | "Not enough memory to generate traffic log\n"); | ||
3341 | } | ||
3337 | return strnlen(buf, count); | 3342 | return strnlen(buf, count); |
3338 | } | 3343 | } |
3339 | 3344 | ||
@@ -3549,65 +3554,6 @@ static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, | |||
3549 | store_retry_rate); | 3554 | store_retry_rate); |
3550 | 3555 | ||
3551 | 3556 | ||
3552 | static ssize_t store_power_level(struct device *d, | ||
3553 | struct device_attribute *attr, | ||
3554 | const char *buf, size_t count) | ||
3555 | { | ||
3556 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
3557 | int ret; | ||
3558 | unsigned long mode; | ||
3559 | |||
3560 | |||
3561 | mutex_lock(&priv->mutex); | ||
3562 | |||
3563 | ret = strict_strtoul(buf, 10, &mode); | ||
3564 | if (ret) | ||
3565 | goto out; | ||
3566 | |||
3567 | ret = iwl_power_set_user_mode(priv, mode); | ||
3568 | if (ret) { | ||
3569 | IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n"); | ||
3570 | goto out; | ||
3571 | } | ||
3572 | ret = count; | ||
3573 | |||
3574 | out: | ||
3575 | mutex_unlock(&priv->mutex); | ||
3576 | return ret; | ||
3577 | } | ||
3578 | |||
3579 | static ssize_t show_power_level(struct device *d, | ||
3580 | struct device_attribute *attr, char *buf) | ||
3581 | { | ||
3582 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
3583 | int level = priv->power_data.power_mode; | ||
3584 | char *p = buf; | ||
3585 | |||
3586 | p += sprintf(p, "%d\n", level); | ||
3587 | return p - buf + 1; | ||
3588 | } | ||
3589 | |||
3590 | static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, | ||
3591 | show_power_level, store_power_level); | ||
3592 | |||
3593 | #define MAX_WX_STRING 80 | ||
3594 | |||
3595 | /* Values are in microsecond */ | ||
3596 | static const s32 timeout_duration[] = { | ||
3597 | 350000, | ||
3598 | 250000, | ||
3599 | 75000, | ||
3600 | 37000, | ||
3601 | 25000, | ||
3602 | }; | ||
3603 | static const s32 period_duration[] = { | ||
3604 | 400000, | ||
3605 | 700000, | ||
3606 | 1000000, | ||
3607 | 1000000, | ||
3608 | 1000000 | ||
3609 | }; | ||
3610 | |||
3611 | static ssize_t show_channels(struct device *d, | 3557 | static ssize_t show_channels(struct device *d, |
3612 | struct device_attribute *attr, char *buf) | 3558 | struct device_attribute *attr, char *buf) |
3613 | { | 3559 | { |
@@ -3784,7 +3730,6 @@ static struct attribute *iwl3945_sysfs_entries[] = { | |||
3784 | #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT | 3730 | #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT |
3785 | &dev_attr_measurement.attr, | 3731 | &dev_attr_measurement.attr, |
3786 | #endif | 3732 | #endif |
3787 | &dev_attr_power_level.attr, | ||
3788 | &dev_attr_retry_rate.attr, | 3733 | &dev_attr_retry_rate.attr, |
3789 | &dev_attr_statistics.attr, | 3734 | &dev_attr_statistics.attr, |
3790 | &dev_attr_status.attr, | 3735 | &dev_attr_status.attr, |
@@ -3849,8 +3794,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) | |||
3849 | priv->qos_data.qos_cap.val = 0; | 3794 | priv->qos_data.qos_cap.val = 0; |
3850 | 3795 | ||
3851 | priv->rates_mask = IWL_RATES_MASK; | 3796 | priv->rates_mask = IWL_RATES_MASK; |
3852 | /* If power management is turned on, default to CAM mode */ | ||
3853 | priv->power_mode = IWL_POWER_MODE_CAM; | ||
3854 | priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; | 3797 | priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; |
3855 | 3798 | ||
3856 | if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { | 3799 | if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { |
@@ -3897,7 +3840,9 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) | |||
3897 | /* Tell mac80211 our characteristics */ | 3840 | /* Tell mac80211 our characteristics */ |
3898 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | 3841 | hw->flags = IEEE80211_HW_SIGNAL_DBM | |
3899 | IEEE80211_HW_NOISE_DBM | | 3842 | IEEE80211_HW_NOISE_DBM | |
3900 | IEEE80211_HW_SPECTRUM_MGMT; | 3843 | IEEE80211_HW_SPECTRUM_MGMT | |
3844 | IEEE80211_HW_SUPPORTS_PS | | ||
3845 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; | ||
3901 | 3846 | ||
3902 | hw->wiphy->interface_modes = | 3847 | hw->wiphy->interface_modes = |
3903 | BIT(NL80211_IFTYPE_STATION) | | 3848 | BIT(NL80211_IFTYPE_STATION) | |
@@ -3975,6 +3920,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
3975 | #ifdef CONFIG_IWLWIFI_DEBUG | 3920 | #ifdef CONFIG_IWLWIFI_DEBUG |
3976 | atomic_set(&priv->restrict_refcnt, 0); | 3921 | atomic_set(&priv->restrict_refcnt, 0); |
3977 | #endif | 3922 | #endif |
3923 | if (iwl_alloc_traffic_mem(priv)) | ||
3924 | IWL_ERR(priv, "Not enough memory to generate traffic log\n"); | ||
3978 | 3925 | ||
3979 | /*************************** | 3926 | /*************************** |
3980 | * 2. Initializing PCI bus | 3927 | * 2. Initializing PCI bus |
@@ -4137,6 +4084,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
4137 | pci_disable_device(pdev); | 4084 | pci_disable_device(pdev); |
4138 | out_ieee80211_free_hw: | 4085 | out_ieee80211_free_hw: |
4139 | ieee80211_free_hw(priv->hw); | 4086 | ieee80211_free_hw(priv->hw); |
4087 | iwl_free_traffic_mem(priv); | ||
4140 | out: | 4088 | out: |
4141 | return err; | 4089 | return err; |
4142 | } | 4090 | } |
@@ -4192,6 +4140,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) | |||
4192 | * until now... */ | 4140 | * until now... */ |
4193 | destroy_workqueue(priv->workqueue); | 4141 | destroy_workqueue(priv->workqueue); |
4194 | priv->workqueue = NULL; | 4142 | priv->workqueue = NULL; |
4143 | iwl_free_traffic_mem(priv); | ||
4195 | 4144 | ||
4196 | free_irq(pdev->irq, priv); | 4145 | free_irq(pdev->irq, priv); |
4197 | pci_disable_msi(pdev); | 4146 | pci_disable_msi(pdev); |
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 89575e448015..8df1cfd5f93a 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -1176,7 +1176,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
1176 | /* Allocate an Ethernet device and register it */ | 1176 | /* Allocate an Ethernet device and register it */ |
1177 | dev = alloc_etherdev(sizeof(struct lbs_private)); | 1177 | dev = alloc_etherdev(sizeof(struct lbs_private)); |
1178 | if (!dev) { | 1178 | if (!dev) { |
1179 | lbs_pr_err("init ethX device failed\n"); | 1179 | lbs_pr_err("init wlanX device failed\n"); |
1180 | goto done; | 1180 | goto done; |
1181 | } | 1181 | } |
1182 | priv = netdev_priv(dev); | 1182 | priv = netdev_priv(dev); |
@@ -1204,6 +1204,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
1204 | SET_NETDEV_DEV(dev, dmdev); | 1204 | SET_NETDEV_DEV(dev, dmdev); |
1205 | 1205 | ||
1206 | priv->rtap_net_dev = NULL; | 1206 | priv->rtap_net_dev = NULL; |
1207 | strcpy(dev->name, "wlan%d"); | ||
1207 | 1208 | ||
1208 | lbs_deb_thread("Starting main thread...\n"); | 1209 | lbs_deb_thread("Starting main thread...\n"); |
1209 | init_waitqueue_head(&priv->waitq); | 1210 | init_waitqueue_head(&priv->waitq); |
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index fa508af1a351..40d8dfa7eace 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c | |||
@@ -642,7 +642,7 @@ int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc) | |||
642 | { | 642 | { |
643 | hermes_t *hw = &priv->hw; | 643 | hermes_t *hw = &priv->hw; |
644 | int err = 0; | 644 | int err = 0; |
645 | u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE]; | 645 | u8 tsc_arr[4][ORINOCO_SEQ_LEN]; |
646 | 646 | ||
647 | if ((key < 0) || (key > 4)) | 647 | if ((key < 0) || (key > 4)) |
648 | return -EINVAL; | 648 | return -EINVAL; |
@@ -768,12 +768,29 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) | |||
768 | { | 768 | { |
769 | hermes_t *hw = &priv->hw; | 769 | hermes_t *hw = &priv->hw; |
770 | int err = 0; | 770 | int err = 0; |
771 | int i; | ||
771 | 772 | ||
772 | switch (priv->firmware_type) { | 773 | switch (priv->firmware_type) { |
773 | case FIRMWARE_TYPE_AGERE: | 774 | case FIRMWARE_TYPE_AGERE: |
775 | { | ||
776 | struct orinoco_key keys[ORINOCO_MAX_KEYS]; | ||
777 | |||
778 | memset(&keys, 0, sizeof(keys)); | ||
779 | for (i = 0; i < ORINOCO_MAX_KEYS; i++) { | ||
780 | int len = min(priv->keys[i].key_len, | ||
781 | ORINOCO_MAX_KEY_SIZE); | ||
782 | memcpy(&keys[i].data, priv->keys[i].key, len); | ||
783 | if (len > SMALL_KEY_SIZE) | ||
784 | keys[i].len = cpu_to_le16(LARGE_KEY_SIZE); | ||
785 | else if (len > 0) | ||
786 | keys[i].len = cpu_to_le16(SMALL_KEY_SIZE); | ||
787 | else | ||
788 | keys[i].len = cpu_to_le16(0); | ||
789 | } | ||
790 | |||
774 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | 791 | err = HERMES_WRITE_RECORD(hw, USER_BAP, |
775 | HERMES_RID_CNFWEPKEYS_AGERE, | 792 | HERMES_RID_CNFWEPKEYS_AGERE, |
776 | &priv->keys); | 793 | &keys); |
777 | if (err) | 794 | if (err) |
778 | return err; | 795 | return err; |
779 | err = hermes_write_wordrec(hw, USER_BAP, | 796 | err = hermes_write_wordrec(hw, USER_BAP, |
@@ -782,28 +799,38 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) | |||
782 | if (err) | 799 | if (err) |
783 | return err; | 800 | return err; |
784 | break; | 801 | break; |
802 | } | ||
785 | case FIRMWARE_TYPE_INTERSIL: | 803 | case FIRMWARE_TYPE_INTERSIL: |
786 | case FIRMWARE_TYPE_SYMBOL: | 804 | case FIRMWARE_TYPE_SYMBOL: |
787 | { | 805 | { |
788 | int keylen; | 806 | int keylen; |
789 | int i; | ||
790 | 807 | ||
791 | /* Force uniform key length to work around | 808 | /* Force uniform key length to work around |
792 | * firmware bugs */ | 809 | * firmware bugs */ |
793 | keylen = le16_to_cpu(priv->keys[priv->tx_key].len); | 810 | keylen = priv->keys[priv->tx_key].key_len; |
794 | 811 | ||
795 | if (keylen > LARGE_KEY_SIZE) { | 812 | if (keylen > LARGE_KEY_SIZE) { |
796 | printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", | 813 | printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", |
797 | priv->ndev->name, priv->tx_key, keylen); | 814 | priv->ndev->name, priv->tx_key, keylen); |
798 | return -E2BIG; | 815 | return -E2BIG; |
799 | } | 816 | } else if (keylen > SMALL_KEY_SIZE) |
817 | keylen = LARGE_KEY_SIZE; | ||
818 | else if (keylen > 0) | ||
819 | keylen = SMALL_KEY_SIZE; | ||
820 | else | ||
821 | keylen = 0; | ||
800 | 822 | ||
801 | /* Write all 4 keys */ | 823 | /* Write all 4 keys */ |
802 | for (i = 0; i < ORINOCO_MAX_KEYS; i++) { | 824 | for (i = 0; i < ORINOCO_MAX_KEYS; i++) { |
825 | u8 key[LARGE_KEY_SIZE] = { 0 }; | ||
826 | |||
827 | memcpy(key, priv->keys[i].key, | ||
828 | priv->keys[i].key_len); | ||
829 | |||
803 | err = hermes_write_ltv(hw, USER_BAP, | 830 | err = hermes_write_ltv(hw, USER_BAP, |
804 | HERMES_RID_CNFDEFAULTKEY0 + i, | 831 | HERMES_RID_CNFDEFAULTKEY0 + i, |
805 | HERMES_BYTES_TO_RECLEN(keylen), | 832 | HERMES_BYTES_TO_RECLEN(keylen), |
806 | priv->keys[i].data); | 833 | key); |
807 | if (err) | 834 | if (err) |
808 | return err; | 835 | return err; |
809 | } | 836 | } |
@@ -829,8 +856,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) | |||
829 | int auth_flag; | 856 | int auth_flag; |
830 | int enc_flag; | 857 | int enc_flag; |
831 | 858 | ||
832 | /* Setup WEP keys for WEP and WPA */ | 859 | /* Setup WEP keys */ |
833 | if (priv->encode_alg) | 860 | if (priv->encode_alg == ORINOCO_ALG_WEP) |
834 | __orinoco_hw_setup_wepkeys(priv); | 861 | __orinoco_hw_setup_wepkeys(priv); |
835 | 862 | ||
836 | if (priv->wep_restrict) | 863 | if (priv->wep_restrict) |
@@ -840,14 +867,14 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) | |||
840 | 867 | ||
841 | if (priv->wpa_enabled) | 868 | if (priv->wpa_enabled) |
842 | enc_flag = 2; | 869 | enc_flag = 2; |
843 | else if (priv->encode_alg == IW_ENCODE_ALG_WEP) | 870 | else if (priv->encode_alg == ORINOCO_ALG_WEP) |
844 | enc_flag = 1; | 871 | enc_flag = 1; |
845 | else | 872 | else |
846 | enc_flag = 0; | 873 | enc_flag = 0; |
847 | 874 | ||
848 | switch (priv->firmware_type) { | 875 | switch (priv->firmware_type) { |
849 | case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ | 876 | case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ |
850 | if (priv->encode_alg == IW_ENCODE_ALG_WEP) { | 877 | if (priv->encode_alg == ORINOCO_ALG_WEP) { |
851 | /* Enable the shared-key authentication. */ | 878 | /* Enable the shared-key authentication. */ |
852 | err = hermes_write_wordrec(hw, USER_BAP, | 879 | err = hermes_write_wordrec(hw, USER_BAP, |
853 | HERMES_RID_CNFAUTHENTICATION_AGERE, | 880 | HERMES_RID_CNFAUTHENTICATION_AGERE, |
@@ -872,7 +899,7 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) | |||
872 | 899 | ||
873 | case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ | 900 | case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ |
874 | case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ | 901 | case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ |
875 | if (priv->encode_alg == IW_ENCODE_ALG_WEP) { | 902 | if (priv->encode_alg == ORINOCO_ALG_WEP) { |
876 | if (priv->wep_restrict || | 903 | if (priv->wep_restrict || |
877 | (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) | 904 | (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) |
878 | master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | | 905 | master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | |
@@ -905,19 +932,20 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) | |||
905 | } | 932 | } |
906 | 933 | ||
907 | /* key must be 32 bytes, including the tx and rx MIC keys. | 934 | /* key must be 32 bytes, including the tx and rx MIC keys. |
908 | * rsc must be 8 bytes | 935 | * rsc must be NULL or up to 8 bytes |
909 | * tsc must be 8 bytes or NULL | 936 | * tsc must be NULL or up to 8 bytes |
910 | */ | 937 | */ |
911 | int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, | 938 | int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, |
912 | int set_tx, u8 *key, u8 *rsc, u8 *tsc) | 939 | int set_tx, u8 *key, u8 *rsc, size_t rsc_len, |
940 | u8 *tsc, size_t tsc_len) | ||
913 | { | 941 | { |
914 | struct { | 942 | struct { |
915 | __le16 idx; | 943 | __le16 idx; |
916 | u8 rsc[IW_ENCODE_SEQ_MAX_SIZE]; | 944 | u8 rsc[ORINOCO_SEQ_LEN]; |
917 | u8 key[TKIP_KEYLEN]; | 945 | u8 key[TKIP_KEYLEN]; |
918 | u8 tx_mic[MIC_KEYLEN]; | 946 | u8 tx_mic[MIC_KEYLEN]; |
919 | u8 rx_mic[MIC_KEYLEN]; | 947 | u8 rx_mic[MIC_KEYLEN]; |
920 | u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; | 948 | u8 tsc[ORINOCO_SEQ_LEN]; |
921 | } __attribute__ ((packed)) buf; | 949 | } __attribute__ ((packed)) buf; |
922 | hermes_t *hw = &priv->hw; | 950 | hermes_t *hw = &priv->hw; |
923 | int ret; | 951 | int ret; |
@@ -934,17 +962,22 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, | |||
934 | memcpy(buf.key, key, | 962 | memcpy(buf.key, key, |
935 | sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); | 963 | sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); |
936 | 964 | ||
937 | if (rsc == NULL) | 965 | if (rsc_len > sizeof(buf.rsc)) |
938 | memset(buf.rsc, 0, sizeof(buf.rsc)); | 966 | rsc_len = sizeof(buf.rsc); |
939 | else | ||
940 | memcpy(buf.rsc, rsc, sizeof(buf.rsc)); | ||
941 | 967 | ||
942 | if (tsc == NULL) { | 968 | if (tsc_len > sizeof(buf.tsc)) |
943 | memset(buf.tsc, 0, sizeof(buf.tsc)); | 969 | tsc_len = sizeof(buf.tsc); |
970 | |||
971 | memset(buf.rsc, 0, sizeof(buf.rsc)); | ||
972 | memset(buf.tsc, 0, sizeof(buf.tsc)); | ||
973 | |||
974 | if (rsc != NULL) | ||
975 | memcpy(buf.rsc, rsc, rsc_len); | ||
976 | |||
977 | if (tsc != NULL) | ||
978 | memcpy(buf.tsc, tsc, tsc_len); | ||
979 | else | ||
944 | buf.tsc[4] = 0x10; | 980 | buf.tsc[4] = 0x10; |
945 | } else { | ||
946 | memcpy(buf.tsc, tsc, sizeof(buf.tsc)); | ||
947 | } | ||
948 | 981 | ||
949 | /* Wait upto 100ms for tx queue to empty */ | 982 | /* Wait upto 100ms for tx queue to empty */ |
950 | for (k = 100; k > 0; k--) { | 983 | for (k = 100; k > 0; k--) { |
@@ -970,7 +1003,6 @@ int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx) | |||
970 | hermes_t *hw = &priv->hw; | 1003 | hermes_t *hw = &priv->hw; |
971 | int err; | 1004 | int err; |
972 | 1005 | ||
973 | memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx])); | ||
974 | err = hermes_write_wordrec(hw, USER_BAP, | 1006 | err = hermes_write_wordrec(hw, USER_BAP, |
975 | HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, | 1007 | HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, |
976 | key_idx); | 1008 | key_idx); |
@@ -1242,3 +1274,39 @@ int orinoco_hw_trigger_scan(struct orinoco_private *priv, | |||
1242 | 1274 | ||
1243 | return err; | 1275 | return err; |
1244 | } | 1276 | } |
1277 | |||
1278 | /* Disassociate from node with BSSID addr */ | ||
1279 | int orinoco_hw_disassociate(struct orinoco_private *priv, | ||
1280 | u8 *addr, u16 reason_code) | ||
1281 | { | ||
1282 | hermes_t *hw = &priv->hw; | ||
1283 | int err; | ||
1284 | |||
1285 | struct { | ||
1286 | u8 addr[ETH_ALEN]; | ||
1287 | __le16 reason_code; | ||
1288 | } __attribute__ ((packed)) buf; | ||
1289 | |||
1290 | /* Currently only supported by WPA enabled Agere fw */ | ||
1291 | if (!priv->has_wpa) | ||
1292 | return -EOPNOTSUPP; | ||
1293 | |||
1294 | memcpy(buf.addr, addr, ETH_ALEN); | ||
1295 | buf.reason_code = cpu_to_le16(reason_code); | ||
1296 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
1297 | HERMES_RID_CNFDISASSOCIATE, | ||
1298 | &buf); | ||
1299 | return err; | ||
1300 | } | ||
1301 | |||
1302 | int orinoco_hw_get_current_bssid(struct orinoco_private *priv, | ||
1303 | u8 *addr) | ||
1304 | { | ||
1305 | hermes_t *hw = &priv->hw; | ||
1306 | int err; | ||
1307 | |||
1308 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, | ||
1309 | ETH_ALEN, NULL, addr); | ||
1310 | |||
1311 | return err; | ||
1312 | } | ||
diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 27b427649d1b..8df6e8752be6 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h | |||
@@ -38,7 +38,8 @@ int __orinoco_hw_set_wap(struct orinoco_private *priv); | |||
38 | int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv); | 38 | int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv); |
39 | int __orinoco_hw_setup_enc(struct orinoco_private *priv); | 39 | int __orinoco_hw_setup_enc(struct orinoco_private *priv); |
40 | int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, | 40 | int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, |
41 | int set_tx, u8 *key, u8 *rsc, u8 *tsc); | 41 | int set_tx, u8 *key, u8 *rsc, size_t rsc_len, |
42 | u8 *tsc, size_t tsc_len); | ||
42 | int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx); | 43 | int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx); |
43 | int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, | 44 | int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, |
44 | struct dev_addr_list *mc_list, | 45 | struct dev_addr_list *mc_list, |
@@ -50,5 +51,9 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv, | |||
50 | int *numrates, s32 *rates, int max); | 51 | int *numrates, s32 *rates, int max); |
51 | int orinoco_hw_trigger_scan(struct orinoco_private *priv, | 52 | int orinoco_hw_trigger_scan(struct orinoco_private *priv, |
52 | const struct cfg80211_ssid *ssid); | 53 | const struct cfg80211_ssid *ssid); |
54 | int orinoco_hw_disassociate(struct orinoco_private *priv, | ||
55 | u8 *addr, u16 reason_code); | ||
56 | int orinoco_hw_get_current_bssid(struct orinoco_private *priv, | ||
57 | u8 *addr); | ||
53 | 58 | ||
54 | #endif /* _ORINOCO_HW_H_ */ | 59 | #endif /* _ORINOCO_HW_H_ */ |
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index e8c550a61f33..2c7dc65cd2be 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c | |||
@@ -341,12 +341,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) | |||
341 | { | 341 | { |
342 | struct orinoco_private *priv = ndev_priv(dev); | 342 | struct orinoco_private *priv = ndev_priv(dev); |
343 | struct net_device_stats *stats = &priv->stats; | 343 | struct net_device_stats *stats = &priv->stats; |
344 | struct orinoco_tkip_key *key; | ||
344 | hermes_t *hw = &priv->hw; | 345 | hermes_t *hw = &priv->hw; |
345 | int err = 0; | 346 | int err = 0; |
346 | u16 txfid = priv->txfid; | 347 | u16 txfid = priv->txfid; |
347 | struct ethhdr *eh; | 348 | struct ethhdr *eh; |
348 | int tx_control; | 349 | int tx_control; |
349 | unsigned long flags; | 350 | unsigned long flags; |
351 | int do_mic; | ||
350 | 352 | ||
351 | if (!netif_running(dev)) { | 353 | if (!netif_running(dev)) { |
352 | printk(KERN_ERR "%s: Tx on stopped device!\n", | 354 | printk(KERN_ERR "%s: Tx on stopped device!\n", |
@@ -378,9 +380,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) | |||
378 | if (skb->len < ETH_HLEN) | 380 | if (skb->len < ETH_HLEN) |
379 | goto drop; | 381 | goto drop; |
380 | 382 | ||
383 | key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key; | ||
384 | |||
385 | do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) && | ||
386 | (key != NULL)); | ||
387 | |||
381 | tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; | 388 | tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; |
382 | 389 | ||
383 | if (priv->encode_alg == IW_ENCODE_ALG_TKIP) | 390 | if (do_mic) |
384 | tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | | 391 | tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | |
385 | HERMES_TXCTRL_MIC; | 392 | HERMES_TXCTRL_MIC; |
386 | 393 | ||
@@ -462,7 +469,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) | |||
462 | } | 469 | } |
463 | 470 | ||
464 | /* Calculate Michael MIC */ | 471 | /* Calculate Michael MIC */ |
465 | if (priv->encode_alg == IW_ENCODE_ALG_TKIP) { | 472 | if (do_mic) { |
466 | u8 mic_buf[MICHAEL_MIC_LEN + 1]; | 473 | u8 mic_buf[MICHAEL_MIC_LEN + 1]; |
467 | u8 *mic; | 474 | u8 *mic; |
468 | size_t offset; | 475 | size_t offset; |
@@ -480,8 +487,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) | |||
480 | len = MICHAEL_MIC_LEN; | 487 | len = MICHAEL_MIC_LEN; |
481 | } | 488 | } |
482 | 489 | ||
483 | orinoco_mic(priv->tx_tfm_mic, | 490 | orinoco_mic(priv->tx_tfm_mic, key->tx_mic, |
484 | priv->tkip_key[priv->tx_key].tx_mic, | ||
485 | eh->h_dest, eh->h_source, 0 /* priority */, | 491 | eh->h_dest, eh->h_source, 0 /* priority */, |
486 | skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic); | 492 | skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic); |
487 | 493 | ||
@@ -926,6 +932,7 @@ static void orinoco_rx(struct net_device *dev, | |||
926 | 932 | ||
927 | /* Calculate and check MIC */ | 933 | /* Calculate and check MIC */ |
928 | if (status & HERMES_RXSTAT_MIC) { | 934 | if (status & HERMES_RXSTAT_MIC) { |
935 | struct orinoco_tkip_key *key; | ||
929 | int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >> | 936 | int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >> |
930 | HERMES_MIC_KEY_ID_SHIFT); | 937 | HERMES_MIC_KEY_ID_SHIFT); |
931 | u8 mic[MICHAEL_MIC_LEN]; | 938 | u8 mic[MICHAEL_MIC_LEN]; |
@@ -939,14 +946,18 @@ static void orinoco_rx(struct net_device *dev, | |||
939 | skb_trim(skb, skb->len - MICHAEL_MIC_LEN); | 946 | skb_trim(skb, skb->len - MICHAEL_MIC_LEN); |
940 | length -= MICHAEL_MIC_LEN; | 947 | length -= MICHAEL_MIC_LEN; |
941 | 948 | ||
942 | orinoco_mic(priv->rx_tfm_mic, | 949 | key = (struct orinoco_tkip_key *) priv->keys[key_id].key; |
943 | priv->tkip_key[key_id].rx_mic, | 950 | |
944 | desc->addr1, | 951 | if (!key) { |
945 | src, | 952 | printk(KERN_WARNING "%s: Received encrypted frame from " |
953 | "%pM using key %i, but key is not installed\n", | ||
954 | dev->name, src, key_id); | ||
955 | goto drop; | ||
956 | } | ||
957 | |||
958 | orinoco_mic(priv->rx_tfm_mic, key->rx_mic, desc->addr1, src, | ||
946 | 0, /* priority or QoS? */ | 959 | 0, /* priority or QoS? */ |
947 | skb->data, | 960 | skb->data, skb->len, &mic[0]); |
948 | skb->len, | ||
949 | &mic[0]); | ||
950 | 961 | ||
951 | if (memcmp(mic, rxmic, | 962 | if (memcmp(mic, rxmic, |
952 | MICHAEL_MIC_LEN)) { | 963 | MICHAEL_MIC_LEN)) { |
@@ -2040,7 +2051,7 @@ int orinoco_init(struct orinoco_private *priv) | |||
2040 | priv->channel = 0; /* use firmware default */ | 2051 | priv->channel = 0; /* use firmware default */ |
2041 | 2052 | ||
2042 | priv->promiscuous = 0; | 2053 | priv->promiscuous = 0; |
2043 | priv->encode_alg = IW_ENCODE_ALG_NONE; | 2054 | priv->encode_alg = ORINOCO_ALG_NONE; |
2044 | priv->tx_key = 0; | 2055 | priv->tx_key = 0; |
2045 | priv->wpa_enabled = 0; | 2056 | priv->wpa_enabled = 0; |
2046 | priv->tkip_cm_active = 0; | 2057 | priv->tkip_cm_active = 0; |
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 5f4f5c9eef79..9ac6f1dda4b0 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | #define MAX_SCAN_LEN 4096 | 26 | #define MAX_SCAN_LEN 4096 |
27 | 27 | ||
28 | #define ORINOCO_SEQ_LEN 8 | ||
28 | #define ORINOCO_MAX_KEY_SIZE 14 | 29 | #define ORINOCO_MAX_KEY_SIZE 14 |
29 | #define ORINOCO_MAX_KEYS 4 | 30 | #define ORINOCO_MAX_KEYS 4 |
30 | 31 | ||
@@ -42,6 +43,12 @@ struct orinoco_tkip_key { | |||
42 | u8 rx_mic[MIC_KEYLEN]; | 43 | u8 rx_mic[MIC_KEYLEN]; |
43 | }; | 44 | }; |
44 | 45 | ||
46 | enum orinoco_alg { | ||
47 | ORINOCO_ALG_NONE, | ||
48 | ORINOCO_ALG_WEP, | ||
49 | ORINOCO_ALG_TKIP | ||
50 | }; | ||
51 | |||
45 | typedef enum { | 52 | typedef enum { |
46 | FIRMWARE_TYPE_AGERE, | 53 | FIRMWARE_TYPE_AGERE, |
47 | FIRMWARE_TYPE_INTERSIL, | 54 | FIRMWARE_TYPE_INTERSIL, |
@@ -107,12 +114,14 @@ struct orinoco_private { | |||
107 | unsigned int do_fw_download:1; | 114 | unsigned int do_fw_download:1; |
108 | unsigned int broken_disableport:1; | 115 | unsigned int broken_disableport:1; |
109 | unsigned int broken_monitor:1; | 116 | unsigned int broken_monitor:1; |
117 | unsigned int prefer_port3:1; | ||
110 | 118 | ||
111 | /* Configuration paramaters */ | 119 | /* Configuration paramaters */ |
112 | enum nl80211_iftype iw_mode; | 120 | enum nl80211_iftype iw_mode; |
113 | int prefer_port3; | 121 | enum orinoco_alg encode_alg; |
114 | u16 encode_alg, wep_restrict, tx_key; | 122 | u16 wep_restrict, tx_key; |
115 | struct orinoco_key keys[ORINOCO_MAX_KEYS]; | 123 | struct key_params keys[ORINOCO_MAX_KEYS]; |
124 | |||
116 | int bitratemode; | 125 | int bitratemode; |
117 | char nick[IW_ESSID_MAX_SIZE+1]; | 126 | char nick[IW_ESSID_MAX_SIZE+1]; |
118 | char desired_essid[IW_ESSID_MAX_SIZE+1]; | 127 | char desired_essid[IW_ESSID_MAX_SIZE+1]; |
@@ -142,7 +151,6 @@ struct orinoco_private { | |||
142 | u8 *wpa_ie; | 151 | u8 *wpa_ie; |
143 | int wpa_ie_len; | 152 | int wpa_ie_len; |
144 | 153 | ||
145 | struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS]; | ||
146 | struct crypto_hash *rx_tfm_mic; | 154 | struct crypto_hash *rx_tfm_mic; |
147 | struct crypto_hash *tx_tfm_mic; | 155 | struct crypto_hash *tx_tfm_mic; |
148 | 156 | ||
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index b6ff3dbb7dd6..3e56f7643df5 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c | |||
@@ -22,6 +22,67 @@ | |||
22 | 22 | ||
23 | #define MAX_RID_LEN 1024 | 23 | #define MAX_RID_LEN 1024 |
24 | 24 | ||
25 | /* Helper routine to record keys | ||
26 | * Do not call from interrupt context */ | ||
27 | static int orinoco_set_key(struct orinoco_private *priv, int index, | ||
28 | enum orinoco_alg alg, const u8 *key, int key_len, | ||
29 | const u8 *seq, int seq_len) | ||
30 | { | ||
31 | kzfree(priv->keys[index].key); | ||
32 | kzfree(priv->keys[index].seq); | ||
33 | |||
34 | if (key_len) { | ||
35 | priv->keys[index].key = kzalloc(key_len, GFP_KERNEL); | ||
36 | if (!priv->keys[index].key) | ||
37 | goto nomem; | ||
38 | } else | ||
39 | priv->keys[index].key = NULL; | ||
40 | |||
41 | if (seq_len) { | ||
42 | priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL); | ||
43 | if (!priv->keys[index].seq) | ||
44 | goto free_key; | ||
45 | } else | ||
46 | priv->keys[index].seq = NULL; | ||
47 | |||
48 | priv->keys[index].key_len = key_len; | ||
49 | priv->keys[index].seq_len = seq_len; | ||
50 | |||
51 | if (key_len) | ||
52 | memcpy(priv->keys[index].key, key, key_len); | ||
53 | if (seq_len) | ||
54 | memcpy(priv->keys[index].seq, seq, seq_len); | ||
55 | |||
56 | switch (alg) { | ||
57 | case ORINOCO_ALG_TKIP: | ||
58 | priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP; | ||
59 | break; | ||
60 | |||
61 | case ORINOCO_ALG_WEP: | ||
62 | priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ? | ||
63 | WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40; | ||
64 | break; | ||
65 | |||
66 | case ORINOCO_ALG_NONE: | ||
67 | default: | ||
68 | priv->keys[index].cipher = 0; | ||
69 | break; | ||
70 | } | ||
71 | |||
72 | return 0; | ||
73 | |||
74 | free_key: | ||
75 | kfree(priv->keys[index].key); | ||
76 | priv->keys[index].key = NULL; | ||
77 | |||
78 | nomem: | ||
79 | priv->keys[index].key_len = 0; | ||
80 | priv->keys[index].seq_len = 0; | ||
81 | priv->keys[index].cipher = 0; | ||
82 | |||
83 | return -ENOMEM; | ||
84 | } | ||
85 | |||
25 | static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) | 86 | static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) |
26 | { | 87 | { |
27 | struct orinoco_private *priv = ndev_priv(dev); | 88 | struct orinoco_private *priv = ndev_priv(dev); |
@@ -156,7 +217,6 @@ static int orinoco_ioctl_getwap(struct net_device *dev, | |||
156 | { | 217 | { |
157 | struct orinoco_private *priv = ndev_priv(dev); | 218 | struct orinoco_private *priv = ndev_priv(dev); |
158 | 219 | ||
159 | hermes_t *hw = &priv->hw; | ||
160 | int err = 0; | 220 | int err = 0; |
161 | unsigned long flags; | 221 | unsigned long flags; |
162 | 222 | ||
@@ -164,8 +224,7 @@ static int orinoco_ioctl_getwap(struct net_device *dev, | |||
164 | return -EBUSY; | 224 | return -EBUSY; |
165 | 225 | ||
166 | ap_addr->sa_family = ARPHRD_ETHER; | 226 | ap_addr->sa_family = ARPHRD_ETHER; |
167 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, | 227 | err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data); |
168 | ETH_ALEN, NULL, ap_addr->sa_data); | ||
169 | 228 | ||
170 | orinoco_unlock(priv, &flags); | 229 | orinoco_unlock(priv, &flags); |
171 | 230 | ||
@@ -180,9 +239,8 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, | |||
180 | struct orinoco_private *priv = ndev_priv(dev); | 239 | struct orinoco_private *priv = ndev_priv(dev); |
181 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; | 240 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; |
182 | int setindex = priv->tx_key; | 241 | int setindex = priv->tx_key; |
183 | int encode_alg = priv->encode_alg; | 242 | enum orinoco_alg encode_alg = priv->encode_alg; |
184 | int restricted = priv->wep_restrict; | 243 | int restricted = priv->wep_restrict; |
185 | u16 xlen = 0; | ||
186 | int err = -EINPROGRESS; /* Call commit handler */ | 244 | int err = -EINPROGRESS; /* Call commit handler */ |
187 | unsigned long flags; | 245 | unsigned long flags; |
188 | 246 | ||
@@ -202,25 +260,17 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, | |||
202 | return -EBUSY; | 260 | return -EBUSY; |
203 | 261 | ||
204 | /* Clear any TKIP key we have */ | 262 | /* Clear any TKIP key we have */ |
205 | if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP)) | 263 | if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP)) |
206 | (void) orinoco_clear_tkip_key(priv, setindex); | 264 | (void) orinoco_clear_tkip_key(priv, setindex); |
207 | 265 | ||
208 | if (erq->length > 0) { | 266 | if (erq->length > 0) { |
209 | if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) | 267 | if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) |
210 | index = priv->tx_key; | 268 | index = priv->tx_key; |
211 | 269 | ||
212 | /* Adjust key length to a supported value */ | ||
213 | if (erq->length > SMALL_KEY_SIZE) | ||
214 | xlen = LARGE_KEY_SIZE; | ||
215 | else if (erq->length > 0) | ||
216 | xlen = SMALL_KEY_SIZE; | ||
217 | else | ||
218 | xlen = 0; | ||
219 | |||
220 | /* Switch on WEP if off */ | 270 | /* Switch on WEP if off */ |
221 | if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) { | 271 | if (encode_alg != ORINOCO_ALG_WEP) { |
222 | setindex = index; | 272 | setindex = index; |
223 | encode_alg = IW_ENCODE_ALG_WEP; | 273 | encode_alg = ORINOCO_ALG_WEP; |
224 | } | 274 | } |
225 | } else { | 275 | } else { |
226 | /* Important note : if the user do "iwconfig eth0 enc off", | 276 | /* Important note : if the user do "iwconfig eth0 enc off", |
@@ -233,7 +283,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, | |||
233 | } | 283 | } |
234 | } else { | 284 | } else { |
235 | /* Set the index : Check that the key is valid */ | 285 | /* Set the index : Check that the key is valid */ |
236 | if (priv->keys[index].len == 0) { | 286 | if (priv->keys[index].key_len == 0) { |
237 | err = -EINVAL; | 287 | err = -EINVAL; |
238 | goto out; | 288 | goto out; |
239 | } | 289 | } |
@@ -242,17 +292,15 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, | |||
242 | } | 292 | } |
243 | 293 | ||
244 | if (erq->flags & IW_ENCODE_DISABLED) | 294 | if (erq->flags & IW_ENCODE_DISABLED) |
245 | encode_alg = IW_ENCODE_ALG_NONE; | 295 | encode_alg = ORINOCO_ALG_NONE; |
246 | if (erq->flags & IW_ENCODE_OPEN) | 296 | if (erq->flags & IW_ENCODE_OPEN) |
247 | restricted = 0; | 297 | restricted = 0; |
248 | if (erq->flags & IW_ENCODE_RESTRICTED) | 298 | if (erq->flags & IW_ENCODE_RESTRICTED) |
249 | restricted = 1; | 299 | restricted = 1; |
250 | 300 | ||
251 | if (erq->pointer && erq->length > 0) { | 301 | if (erq->pointer && erq->length > 0) { |
252 | priv->keys[index].len = cpu_to_le16(xlen); | 302 | err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf, |
253 | memset(priv->keys[index].data, 0, | 303 | erq->length, NULL, 0); |
254 | sizeof(priv->keys[index].data)); | ||
255 | memcpy(priv->keys[index].data, keybuf, erq->length); | ||
256 | } | 304 | } |
257 | priv->tx_key = setindex; | 305 | priv->tx_key = setindex; |
258 | 306 | ||
@@ -281,7 +329,6 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, | |||
281 | { | 329 | { |
282 | struct orinoco_private *priv = ndev_priv(dev); | 330 | struct orinoco_private *priv = ndev_priv(dev); |
283 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; | 331 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; |
284 | u16 xlen = 0; | ||
285 | unsigned long flags; | 332 | unsigned long flags; |
286 | 333 | ||
287 | if (!priv->has_wep) | 334 | if (!priv->has_wep) |
@@ -303,11 +350,9 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, | |||
303 | else | 350 | else |
304 | erq->flags |= IW_ENCODE_OPEN; | 351 | erq->flags |= IW_ENCODE_OPEN; |
305 | 352 | ||
306 | xlen = le16_to_cpu(priv->keys[index].len); | 353 | erq->length = priv->keys[index].key_len; |
307 | 354 | ||
308 | erq->length = xlen; | 355 | memcpy(keybuf, priv->keys[index].key, erq->length); |
309 | |||
310 | memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); | ||
311 | 356 | ||
312 | orinoco_unlock(priv, &flags); | 357 | orinoco_unlock(priv, &flags); |
313 | return 0; | 358 | return 0; |
@@ -793,7 +838,6 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, | |||
793 | int idx, alg = ext->alg, set_key = 1; | 838 | int idx, alg = ext->alg, set_key = 1; |
794 | unsigned long flags; | 839 | unsigned long flags; |
795 | int err = -EINVAL; | 840 | int err = -EINVAL; |
796 | u16 key_len; | ||
797 | 841 | ||
798 | if (orinoco_lock(priv, &flags) != 0) | 842 | if (orinoco_lock(priv, &flags) != 0) |
799 | return -EBUSY; | 843 | return -EBUSY; |
@@ -825,25 +869,18 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, | |||
825 | /* Set the requested key first */ | 869 | /* Set the requested key first */ |
826 | switch (alg) { | 870 | switch (alg) { |
827 | case IW_ENCODE_ALG_NONE: | 871 | case IW_ENCODE_ALG_NONE: |
828 | priv->encode_alg = alg; | 872 | priv->encode_alg = ORINOCO_ALG_NONE; |
829 | priv->keys[idx].len = 0; | 873 | err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE, |
874 | NULL, 0, NULL, 0); | ||
830 | break; | 875 | break; |
831 | 876 | ||
832 | case IW_ENCODE_ALG_WEP: | 877 | case IW_ENCODE_ALG_WEP: |
833 | if (ext->key_len > SMALL_KEY_SIZE) | 878 | if (ext->key_len <= 0) |
834 | key_len = LARGE_KEY_SIZE; | ||
835 | else if (ext->key_len > 0) | ||
836 | key_len = SMALL_KEY_SIZE; | ||
837 | else | ||
838 | goto out; | 879 | goto out; |
839 | 880 | ||
840 | priv->encode_alg = alg; | 881 | priv->encode_alg = ORINOCO_ALG_WEP; |
841 | priv->keys[idx].len = cpu_to_le16(key_len); | 882 | err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP, |
842 | 883 | ext->key, ext->key_len, NULL, 0); | |
843 | key_len = min(ext->key_len, key_len); | ||
844 | |||
845 | memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE); | ||
846 | memcpy(priv->keys[idx].data, ext->key, key_len); | ||
847 | break; | 884 | break; |
848 | 885 | ||
849 | case IW_ENCODE_ALG_TKIP: | 886 | case IW_ENCODE_ALG_TKIP: |
@@ -851,21 +888,22 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, | |||
851 | u8 *tkip_iv = NULL; | 888 | u8 *tkip_iv = NULL; |
852 | 889 | ||
853 | if (!priv->has_wpa || | 890 | if (!priv->has_wpa || |
854 | (ext->key_len > sizeof(priv->tkip_key[0]))) | 891 | (ext->key_len > sizeof(struct orinoco_tkip_key))) |
855 | goto out; | 892 | goto out; |
856 | 893 | ||
857 | priv->encode_alg = alg; | 894 | priv->encode_alg = ORINOCO_ALG_TKIP; |
858 | memset(&priv->tkip_key[idx], 0, | ||
859 | sizeof(priv->tkip_key[idx])); | ||
860 | memcpy(&priv->tkip_key[idx], ext->key, ext->key_len); | ||
861 | 895 | ||
862 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) | 896 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) |
863 | tkip_iv = &ext->rx_seq[0]; | 897 | tkip_iv = &ext->rx_seq[0]; |
864 | 898 | ||
899 | err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP, | ||
900 | ext->key, ext->key_len, tkip_iv, | ||
901 | ORINOCO_SEQ_LEN); | ||
902 | |||
865 | err = __orinoco_hw_set_tkip_key(priv, idx, | 903 | err = __orinoco_hw_set_tkip_key(priv, idx, |
866 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, | 904 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, |
867 | (u8 *) &priv->tkip_key[idx], | 905 | priv->keys[idx].key, |
868 | tkip_iv, NULL); | 906 | tkip_iv, ORINOCO_SEQ_LEN, NULL, 0); |
869 | if (err) | 907 | if (err) |
870 | printk(KERN_ERR "%s: Error %d setting TKIP key" | 908 | printk(KERN_ERR "%s: Error %d setting TKIP key" |
871 | "\n", dev->name, err); | 909 | "\n", dev->name, err); |
@@ -914,22 +952,22 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev, | |||
914 | encoding->flags = idx + 1; | 952 | encoding->flags = idx + 1; |
915 | memset(ext, 0, sizeof(*ext)); | 953 | memset(ext, 0, sizeof(*ext)); |
916 | 954 | ||
917 | ext->alg = priv->encode_alg; | ||
918 | switch (priv->encode_alg) { | 955 | switch (priv->encode_alg) { |
919 | case IW_ENCODE_ALG_NONE: | 956 | case ORINOCO_ALG_NONE: |
957 | ext->alg = IW_ENCODE_ALG_NONE; | ||
920 | ext->key_len = 0; | 958 | ext->key_len = 0; |
921 | encoding->flags |= IW_ENCODE_DISABLED; | 959 | encoding->flags |= IW_ENCODE_DISABLED; |
922 | break; | 960 | break; |
923 | case IW_ENCODE_ALG_WEP: | 961 | case ORINOCO_ALG_WEP: |
924 | ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len), | 962 | ext->alg = IW_ENCODE_ALG_WEP; |
925 | max_key_len); | 963 | ext->key_len = min(priv->keys[idx].key_len, max_key_len); |
926 | memcpy(ext->key, priv->keys[idx].data, ext->key_len); | 964 | memcpy(ext->key, priv->keys[idx].key, ext->key_len); |
927 | encoding->flags |= IW_ENCODE_ENABLED; | 965 | encoding->flags |= IW_ENCODE_ENABLED; |
928 | break; | 966 | break; |
929 | case IW_ENCODE_ALG_TKIP: | 967 | case ORINOCO_ALG_TKIP: |
930 | ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key), | 968 | ext->alg = IW_ENCODE_ALG_TKIP; |
931 | max_key_len); | 969 | ext->key_len = min(priv->keys[idx].key_len, max_key_len); |
932 | memcpy(ext->key, &priv->tkip_key[idx], ext->key_len); | 970 | memcpy(ext->key, priv->keys[idx].key, ext->key_len); |
933 | encoding->flags |= IW_ENCODE_ENABLED; | 971 | encoding->flags |= IW_ENCODE_ENABLED; |
934 | break; | 972 | break; |
935 | } | 973 | } |
@@ -1136,7 +1174,6 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev, | |||
1136 | union iwreq_data *wrqu, char *extra) | 1174 | union iwreq_data *wrqu, char *extra) |
1137 | { | 1175 | { |
1138 | struct orinoco_private *priv = ndev_priv(dev); | 1176 | struct orinoco_private *priv = ndev_priv(dev); |
1139 | hermes_t *hw = &priv->hw; | ||
1140 | struct iw_mlme *mlme = (struct iw_mlme *)extra; | 1177 | struct iw_mlme *mlme = (struct iw_mlme *)extra; |
1141 | unsigned long flags; | 1178 | unsigned long flags; |
1142 | int ret = 0; | 1179 | int ret = 0; |
@@ -1150,19 +1187,11 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev, | |||
1150 | break; | 1187 | break; |
1151 | 1188 | ||
1152 | case IW_MLME_DISASSOC: | 1189 | case IW_MLME_DISASSOC: |
1153 | { | 1190 | |
1154 | struct { | 1191 | ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data, |
1155 | u8 addr[ETH_ALEN]; | 1192 | mlme->reason_code); |
1156 | __le16 reason_code; | ||
1157 | } __attribute__ ((packed)) buf; | ||
1158 | |||
1159 | memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN); | ||
1160 | buf.reason_code = cpu_to_le16(mlme->reason_code); | ||
1161 | ret = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
1162 | HERMES_RID_CNFDISASSOCIATE, | ||
1163 | &buf); | ||
1164 | break; | 1193 | break; |
1165 | } | 1194 | |
1166 | default: | 1195 | default: |
1167 | ret = -EOPNOTSUPP; | 1196 | ret = -EOPNOTSUPP; |
1168 | } | 1197 | } |
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 21f19018fab5..e7b9e9cb39f5 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c | |||
@@ -320,7 +320,7 @@ int p54_setup_mac(struct p54_common *priv) | |||
320 | return -ENOMEM; | 320 | return -ENOMEM; |
321 | 321 | ||
322 | setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); | 322 | setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); |
323 | if (priv->hw->conf.radio_enabled) { | 323 | if (!(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) { |
324 | switch (priv->mode) { | 324 | switch (priv->mode) { |
325 | case NL80211_IFTYPE_STATION: | 325 | case NL80211_IFTYPE_STATION: |
326 | mode = P54_FILTER_TYPE_STATION; | 326 | mode = P54_FILTER_TYPE_STATION; |
@@ -348,8 +348,9 @@ int p54_setup_mac(struct p54_common *priv) | |||
348 | (priv->filter_flags & FIF_OTHER_BSS)) && | 348 | (priv->filter_flags & FIF_OTHER_BSS)) && |
349 | (mode != P54_FILTER_TYPE_PROMISCUOUS)) | 349 | (mode != P54_FILTER_TYPE_PROMISCUOUS)) |
350 | mode |= P54_FILTER_TYPE_TRANSPARENT; | 350 | mode |= P54_FILTER_TYPE_TRANSPARENT; |
351 | } else | 351 | } else { |
352 | mode = P54_FILTER_TYPE_HIBERNATE; | 352 | mode = P54_FILTER_TYPE_HIBERNATE; |
353 | } | ||
353 | 354 | ||
354 | setup->mac_mode = cpu_to_le16(mode); | 355 | setup->mac_mode = cpu_to_le16(mode); |
355 | memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); | 356 | memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); |
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index a0d0e726bc4e..4a741df9c081 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c | |||
@@ -288,6 +288,11 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed) | |||
288 | if (ret) | 288 | if (ret) |
289 | goto out; | 289 | goto out; |
290 | } | 290 | } |
291 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { | ||
292 | ret = p54_setup_mac(priv); | ||
293 | if (ret) | ||
294 | goto out; | ||
295 | } | ||
291 | 296 | ||
292 | out: | 297 | out: |
293 | mutex_unlock(&priv->conf_mutex); | 298 | mutex_unlock(&priv->conf_mutex); |
@@ -317,7 +322,7 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, | |||
317 | int ret; | 322 | int ret; |
318 | 323 | ||
319 | mutex_lock(&priv->conf_mutex); | 324 | mutex_lock(&priv->conf_mutex); |
320 | if ((params) && !(queue > 4)) { | 325 | if (queue < dev->queues) { |
321 | P54_SET_QUEUE(priv->qos_params[queue], params->aifs, | 326 | P54_SET_QUEUE(priv->qos_params[queue], params->aifs, |
322 | params->cw_min, params->cw_max, params->txop); | 327 | params->cw_min, params->cw_max, params->txop); |
323 | ret = p54_set_edcf(priv); | 328 | ret = p54_set_edcf(priv); |
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 704685fab177..6fc0b6148c8a 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c | |||
@@ -552,6 +552,12 @@ static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb) | |||
552 | break; | 552 | break; |
553 | case P54_TRAP_TIMER: | 553 | case P54_TRAP_TIMER: |
554 | break; | 554 | break; |
555 | case P54_TRAP_FAA_RADIO_OFF: | ||
556 | wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); | ||
557 | break; | ||
558 | case P54_TRAP_FAA_RADIO_ON: | ||
559 | wiphy_rfkill_set_hw_state(priv->hw->wiphy, false); | ||
560 | break; | ||
555 | default: | 561 | default: |
556 | printk(KERN_INFO "%s: received event:%x freq:%d\n", | 562 | printk(KERN_INFO "%s: received event:%x freq:%d\n", |
557 | wiphy_name(priv->hw->wiphy), event, freq); | 563 | wiphy_name(priv->hw->wiphy), event, freq); |
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 828dc1825bba..d42692dfbc67 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -1764,8 +1764,15 @@ static int rndis_iw_set_essid(struct net_device *dev, | |||
1764 | 1764 | ||
1765 | if (!wrqu->essid.flags || length == 0) | 1765 | if (!wrqu->essid.flags || length == 0) |
1766 | return disassociate(usbdev, 1); | 1766 | return disassociate(usbdev, 1); |
1767 | else | 1767 | else { |
1768 | /* Pause and purge rx queue, so we don't pass packets before | ||
1769 | * 'media connect'-indication. | ||
1770 | */ | ||
1771 | usbnet_pause_rx(usbdev); | ||
1772 | usbnet_purge_paused_rxq(usbdev); | ||
1773 | |||
1768 | return set_essid(usbdev, &ssid); | 1774 | return set_essid(usbdev, &ssid); |
1775 | } | ||
1769 | } | 1776 | } |
1770 | 1777 | ||
1771 | 1778 | ||
@@ -2328,6 +2335,8 @@ get_bssid: | |||
2328 | memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); | 2335 | memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); |
2329 | wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); | 2336 | wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); |
2330 | } | 2337 | } |
2338 | |||
2339 | usbnet_resume_rx(usbdev); | ||
2331 | } | 2340 | } |
2332 | 2341 | ||
2333 | if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) { | 2342 | if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) { |
@@ -2541,6 +2550,8 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) | |||
2541 | 2550 | ||
2542 | switch (msg->status) { | 2551 | switch (msg->status) { |
2543 | case RNDIS_STATUS_MEDIA_CONNECT: | 2552 | case RNDIS_STATUS_MEDIA_CONNECT: |
2553 | usbnet_pause_rx(usbdev); | ||
2554 | |||
2544 | devinfo(usbdev, "media connect"); | 2555 | devinfo(usbdev, "media connect"); |
2545 | 2556 | ||
2546 | /* queue work to avoid recursive calls into rndis_command */ | 2557 | /* queue work to avoid recursive calls into rndis_command */ |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 30185ad28d93..164df9347a2f 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -1069,8 +1069,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry) | |||
1069 | * otherwise we might be sending out invalid data. | 1069 | * otherwise we might be sending out invalid data. |
1070 | */ | 1070 | */ |
1071 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); | 1071 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); |
1072 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); | ||
1073 | rt2x00_set_field32(®, CSR14_TBCN, 0); | ||
1074 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); | 1072 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); |
1075 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); | 1073 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); |
1076 | 1074 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 3b3171578b14..4186582f2770 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -1227,8 +1227,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry) | |||
1227 | * otherwise we might be sending out invalid data. | 1227 | * otherwise we might be sending out invalid data. |
1228 | */ | 1228 | */ |
1229 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); | 1229 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); |
1230 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); | ||
1231 | rt2x00_set_field32(®, CSR14_TBCN, 0); | ||
1232 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); | 1230 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); |
1233 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); | 1231 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); |
1234 | 1232 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index de48c5c68eff..09a589432dab 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -1238,8 +1238,6 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) | |||
1238 | * otherwise we might be sending out invalid data. | 1238 | * otherwise we might be sending out invalid data. |
1239 | */ | 1239 | */ |
1240 | rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); | 1240 | rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); |
1241 | rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0); | ||
1242 | rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0); | ||
1243 | rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); | 1241 | rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); |
1244 | rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); | 1242 | rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); |
1245 | 1243 | ||
@@ -1287,7 +1285,7 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry) | |||
1287 | static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, | 1285 | static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, |
1288 | const enum data_queue_qid queue) | 1286 | const enum data_queue_qid queue) |
1289 | { | 1287 | { |
1290 | u16 reg; | 1288 | u16 reg, reg0; |
1291 | 1289 | ||
1292 | if (queue != QID_BEACON) { | 1290 | if (queue != QID_BEACON) { |
1293 | rt2x00usb_kick_tx_queue(rt2x00dev, queue); | 1291 | rt2x00usb_kick_tx_queue(rt2x00dev, queue); |
@@ -1298,16 +1296,19 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, | |||
1298 | if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) { | 1296 | if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) { |
1299 | rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); | 1297 | rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); |
1300 | rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); | 1298 | rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); |
1299 | reg0 = reg; | ||
1301 | rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 1); | 1300 | rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 1); |
1302 | /* | 1301 | /* |
1303 | * Beacon generation will fail initially. | 1302 | * Beacon generation will fail initially. |
1304 | * To prevent this we need to register the TXRX_CSR19 | 1303 | * To prevent this we need to change the TXRX_CSR19 |
1305 | * register several times. | 1304 | * register several times (reg0 is the same as reg |
1305 | * except for TXRX_CSR19_BEACON_GEN, which is 0 in reg0 | ||
1306 | * and 1 in reg). | ||
1306 | */ | 1307 | */ |
1307 | rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); | 1308 | rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); |
1308 | rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); | 1309 | rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0); |
1309 | rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); | 1310 | rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); |
1310 | rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); | 1311 | rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0); |
1311 | rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); | 1312 | rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); |
1312 | } | 1313 | } |
1313 | } | 1314 | } |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 9efb41710508..3856f06fdca7 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -518,7 +518,7 @@ static void rt2800usb_config_filter(struct rt2x00_dev *rt2x00dev, | |||
518 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS, | 518 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS, |
519 | !(filter_flags & FIF_CONTROL)); | 519 | !(filter_flags & FIF_CONTROL)); |
520 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, | 520 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, |
521 | !(filter_flags & FIF_CONTROL)); | 521 | !(filter_flags & FIF_PSPOLL)); |
522 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); | 522 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); |
523 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); | 523 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); |
524 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, | 524 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, |
@@ -2050,8 +2050,6 @@ static void rt2800usb_write_beacon(struct queue_entry *entry) | |||
2050 | * otherwise we might be sending out invalid data. | 2050 | * otherwise we might be sending out invalid data. |
2051 | */ | 2051 | */ |
2052 | rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); | 2052 | rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); |
2053 | rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); | ||
2054 | rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); | ||
2055 | rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); | 2053 | rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); |
2056 | rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); | 2054 | rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); |
2057 | 2055 | ||
@@ -2624,6 +2622,13 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
2624 | return retval; | 2622 | return retval; |
2625 | 2623 | ||
2626 | /* | 2624 | /* |
2625 | * This device has multiple filters for control frames | ||
2626 | * and has a separate filter for PS Poll frames. | ||
2627 | */ | ||
2628 | __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); | ||
2629 | __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags); | ||
2630 | |||
2631 | /* | ||
2627 | * This device requires firmware. | 2632 | * This device requires firmware. |
2628 | */ | 2633 | */ |
2629 | __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); | 2634 | __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index cbec91ef6f76..5bc100db28d4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -134,6 +134,17 @@ | |||
134 | GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) | 134 | GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) |
135 | 135 | ||
136 | /* | 136 | /* |
137 | * Structure for average calculation | ||
138 | * The avg field contains the actual average value, | ||
139 | * but avg_weight is internally used during calculations | ||
140 | * to prevent rounding errors. | ||
141 | */ | ||
142 | struct avg_val { | ||
143 | int avg; | ||
144 | int avg_weight; | ||
145 | }; | ||
146 | |||
147 | /* | ||
137 | * Chipset identification | 148 | * Chipset identification |
138 | * The chipset on the device is composed of a RT and RF chip. | 149 | * The chipset on the device is composed of a RT and RF chip. |
139 | * The chipset combination is important for determining device capabilities. | 150 | * The chipset combination is important for determining device capabilities. |
@@ -245,21 +256,18 @@ struct link_ant { | |||
245 | struct antenna_setup active; | 256 | struct antenna_setup active; |
246 | 257 | ||
247 | /* | 258 | /* |
248 | * RSSI information for the different antennas. | 259 | * RSSI history information for the antenna. |
249 | * These statistics are used to determine when | 260 | * Used to determine when to switch antenna |
250 | * to switch antenna when using software diversity. | 261 | * when using software diversity. |
251 | * | ||
252 | * rssi[0] -> Antenna A RSSI | ||
253 | * rssi[1] -> Antenna B RSSI | ||
254 | */ | 262 | */ |
255 | int rssi_history[2]; | 263 | int rssi_history; |
256 | 264 | ||
257 | /* | 265 | /* |
258 | * Current RSSI average of the currently active antenna. | 266 | * Current RSSI average of the currently active antenna. |
259 | * Similar to the avg_rssi in the link_qual structure | 267 | * Similar to the avg_rssi in the link_qual structure |
260 | * this value is updated by using the walking average. | 268 | * this value is updated by using the walking average. |
261 | */ | 269 | */ |
262 | int rssi_ant; | 270 | struct avg_val rssi_ant; |
263 | }; | 271 | }; |
264 | 272 | ||
265 | /* | 273 | /* |
@@ -288,7 +296,7 @@ struct link { | |||
288 | /* | 296 | /* |
289 | * Currently active average RSSI value | 297 | * Currently active average RSSI value |
290 | */ | 298 | */ |
291 | int avg_rssi; | 299 | struct avg_val avg_rssi; |
292 | 300 | ||
293 | /* | 301 | /* |
294 | * Currently precalculated percentages of successful | 302 | * Currently precalculated percentages of successful |
@@ -326,6 +334,11 @@ struct rt2x00_intf { | |||
326 | u8 bssid[ETH_ALEN]; | 334 | u8 bssid[ETH_ALEN]; |
327 | 335 | ||
328 | /* | 336 | /* |
337 | * beacon->skb must be protected with the mutex. | ||
338 | */ | ||
339 | struct mutex beacon_skb_mutex; | ||
340 | |||
341 | /* | ||
329 | * Entry in the beacon queue which belongs to | 342 | * Entry in the beacon queue which belongs to |
330 | * this interface. Each interface has its own | 343 | * this interface. Each interface has its own |
331 | * dedicated beacon entry. | 344 | * dedicated beacon entry. |
@@ -611,6 +624,8 @@ enum rt2x00_flags { | |||
611 | */ | 624 | */ |
612 | CONFIG_SUPPORT_HW_BUTTON, | 625 | CONFIG_SUPPORT_HW_BUTTON, |
613 | CONFIG_SUPPORT_HW_CRYPTO, | 626 | CONFIG_SUPPORT_HW_CRYPTO, |
627 | DRIVER_SUPPORT_CONTROL_FILTERS, | ||
628 | DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, | ||
614 | 629 | ||
615 | /* | 630 | /* |
616 | * Driver configuration | 631 | * Driver configuration |
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 3845316ccd39..3501788ab498 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c | |||
@@ -124,8 +124,9 @@ enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant, | |||
124 | } | 124 | } |
125 | 125 | ||
126 | void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, | 126 | void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, |
127 | struct antenna_setup ant) | 127 | struct antenna_setup config) |
128 | { | 128 | { |
129 | struct link_ant *ant = &rt2x00dev->link.ant; | ||
129 | struct antenna_setup *def = &rt2x00dev->default_ant; | 130 | struct antenna_setup *def = &rt2x00dev->default_ant; |
130 | struct antenna_setup *active = &rt2x00dev->link.ant.active; | 131 | struct antenna_setup *active = &rt2x00dev->link.ant.active; |
131 | 132 | ||
@@ -134,14 +135,23 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, | |||
134 | * ANTENNA_SW_DIVERSITY state to the driver. | 135 | * ANTENNA_SW_DIVERSITY state to the driver. |
135 | * If that happens, fallback to hardware defaults, | 136 | * If that happens, fallback to hardware defaults, |
136 | * or our own default. | 137 | * or our own default. |
138 | * If diversity handling is active for a particular antenna, | ||
139 | * we shouldn't overwrite that antenna. | ||
137 | * The calls to rt2x00lib_config_antenna_check() | 140 | * The calls to rt2x00lib_config_antenna_check() |
138 | * might have caused that we restore back to the already | 141 | * might have caused that we restore back to the already |
139 | * active setting. If that has happened we can quit. | 142 | * active setting. If that has happened we can quit. |
140 | */ | 143 | */ |
141 | ant.rx = rt2x00lib_config_antenna_check(ant.rx, def->rx); | 144 | if (!(ant->flags & ANTENNA_RX_DIVERSITY)) |
142 | ant.tx = rt2x00lib_config_antenna_check(ant.tx, def->tx); | 145 | config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx); |
146 | else | ||
147 | config.rx = active->rx; | ||
143 | 148 | ||
144 | if (ant.rx == active->rx && ant.tx == active->tx) | 149 | if (!(ant->flags & ANTENNA_TX_DIVERSITY)) |
150 | config.tx = rt2x00lib_config_antenna_check(config.tx, def->tx); | ||
151 | else | ||
152 | config.tx = active->tx; | ||
153 | |||
154 | if (config.rx == active->rx && config.tx == active->tx) | ||
145 | return; | 155 | return; |
146 | 156 | ||
147 | /* | 157 | /* |
@@ -156,11 +166,11 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, | |||
156 | * The latter is required since we need to recalibrate the | 166 | * The latter is required since we need to recalibrate the |
157 | * noise-sensitivity ratio for the new setup. | 167 | * noise-sensitivity ratio for the new setup. |
158 | */ | 168 | */ |
159 | rt2x00dev->ops->lib->config_ant(rt2x00dev, &ant); | 169 | rt2x00dev->ops->lib->config_ant(rt2x00dev, &config); |
160 | 170 | ||
161 | rt2x00link_reset_tuner(rt2x00dev, true); | 171 | rt2x00link_reset_tuner(rt2x00dev, true); |
162 | 172 | ||
163 | memcpy(active, &ant, sizeof(ant)); | 173 | memcpy(active, &config, sizeof(config)); |
164 | 174 | ||
165 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | 175 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
166 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); | 176 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index db54fcc94c8f..b6676c6722fc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -186,7 +186,6 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work) | |||
186 | static void rt2x00lib_beacondone_iter(void *data, u8 *mac, | 186 | static void rt2x00lib_beacondone_iter(void *data, u8 *mac, |
187 | struct ieee80211_vif *vif) | 187 | struct ieee80211_vif *vif) |
188 | { | 188 | { |
189 | struct rt2x00_dev *rt2x00dev = data; | ||
190 | struct rt2x00_intf *intf = vif_to_intf(vif); | 189 | struct rt2x00_intf *intf = vif_to_intf(vif); |
191 | 190 | ||
192 | if (vif->type != NL80211_IFTYPE_AP && | 191 | if (vif->type != NL80211_IFTYPE_AP && |
@@ -195,12 +194,6 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac, | |||
195 | vif->type != NL80211_IFTYPE_WDS) | 194 | vif->type != NL80211_IFTYPE_WDS) |
196 | return; | 195 | return; |
197 | 196 | ||
198 | /* | ||
199 | * Clean up the beacon skb. | ||
200 | */ | ||
201 | rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb); | ||
202 | intf->beacon->skb = NULL; | ||
203 | |||
204 | spin_lock(&intf->lock); | 197 | spin_lock(&intf->lock); |
205 | intf->delayed_flags |= DELAYED_UPDATE_BEACON; | 198 | intf->delayed_flags |= DELAYED_UPDATE_BEACON; |
206 | spin_unlock(&intf->lock); | 199 | spin_unlock(&intf->lock); |
@@ -785,6 +778,13 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) | |||
785 | rt2x00dev->intf_sta_count = 0; | 778 | rt2x00dev->intf_sta_count = 0; |
786 | rt2x00dev->intf_associated = 0; | 779 | rt2x00dev->intf_associated = 0; |
787 | 780 | ||
781 | /* Enable the radio */ | ||
782 | retval = rt2x00lib_enable_radio(rt2x00dev); | ||
783 | if (retval) { | ||
784 | rt2x00queue_uninitialize(rt2x00dev); | ||
785 | return retval; | ||
786 | } | ||
787 | |||
788 | set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags); | 788 | set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags); |
789 | 789 | ||
790 | return 0; | 790 | return 0; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 917831689ccd..c64db0ba7f40 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c | |||
@@ -46,7 +46,15 @@ | |||
46 | #define DEFAULT_PERCENTAGE 50 | 46 | #define DEFAULT_PERCENTAGE 50 |
47 | 47 | ||
48 | /* | 48 | /* |
49 | * Small helper macro to work with moving/walking averages. | 49 | * Small helper macro for percentage calculation |
50 | * This is a very simple macro with the only catch that it will | ||
51 | * produce a default value in case no total value was provided. | ||
52 | */ | ||
53 | #define PERCENTAGE(__value, __total) \ | ||
54 | ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) ) | ||
55 | |||
56 | /* | ||
57 | * Helper struct and macro to work with moving/walking averages. | ||
50 | * When adding a value to the average value the following calculation | 58 | * When adding a value to the average value the following calculation |
51 | * is needed: | 59 | * is needed: |
52 | * | 60 | * |
@@ -60,18 +68,28 @@ | |||
60 | * for a few minutes but when the device is moved away from the AP | 68 | * for a few minutes but when the device is moved away from the AP |
61 | * the average will not decrease fast enough to compensate. | 69 | * the average will not decrease fast enough to compensate. |
62 | * The walking average compensates this and will move towards | 70 | * The walking average compensates this and will move towards |
63 | * the new values correctly allowing a effective link tuning. | 71 | * the new values correctly allowing a effective link tuning, |
64 | */ | 72 | * the speed of the average moving towards other values depends |
65 | #define MOVING_AVERAGE(__avg, __val, __samples) \ | 73 | * on the value for the number of samples. The higher the number |
66 | ( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) ) | 74 | * of samples, the slower the average will move. |
67 | 75 | * We use two variables to keep track of the average value to | |
68 | /* | 76 | * compensate for the rounding errors. This can be a significant |
69 | * Small helper macro for percentage calculation | 77 | * error (>5dBm) if the factor is too low. |
70 | * This is a very simple macro with the only catch that it will | ||
71 | * produce a default value in case no total value was provided. | ||
72 | */ | 78 | */ |
73 | #define PERCENTAGE(__value, __total) \ | 79 | #define AVG_SAMPLES 8 |
74 | ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) ) | 80 | #define AVG_FACTOR 1000 |
81 | #define MOVING_AVERAGE(__avg, __val) \ | ||
82 | ({ \ | ||
83 | struct avg_val __new; \ | ||
84 | __new.avg_weight = \ | ||
85 | (__avg).avg_weight ? \ | ||
86 | ((((__avg).avg_weight * ((AVG_SAMPLES) - 1)) + \ | ||
87 | ((__val) * (AVG_FACTOR))) / \ | ||
88 | (AVG_SAMPLES) ) : \ | ||
89 | ((__val) * (AVG_FACTOR)); \ | ||
90 | __new.avg = __new.avg_weight / (AVG_FACTOR); \ | ||
91 | __new; \ | ||
92 | }) | ||
75 | 93 | ||
76 | /* | 94 | /* |
77 | * For calculating the Signal quality we have determined | 95 | * For calculating the Signal quality we have determined |
@@ -98,56 +116,41 @@ static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev) | |||
98 | { | 116 | { |
99 | struct link_ant *ant = &rt2x00dev->link.ant; | 117 | struct link_ant *ant = &rt2x00dev->link.ant; |
100 | 118 | ||
101 | if (ant->rssi_ant && rt2x00dev->link.qual.rx_success) | 119 | if (ant->rssi_ant.avg && rt2x00dev->link.qual.rx_success) |
102 | return ant->rssi_ant; | 120 | return ant->rssi_ant.avg; |
103 | return DEFAULT_RSSI; | 121 | return DEFAULT_RSSI; |
104 | } | 122 | } |
105 | 123 | ||
106 | static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev, | 124 | static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev) |
107 | enum antenna antenna) | ||
108 | { | 125 | { |
109 | struct link_ant *ant = &rt2x00dev->link.ant; | 126 | struct link_ant *ant = &rt2x00dev->link.ant; |
110 | 127 | ||
111 | if (ant->rssi_history[antenna - ANTENNA_A]) | 128 | if (ant->rssi_history) |
112 | return ant->rssi_history[antenna - ANTENNA_A]; | 129 | return ant->rssi_history; |
113 | return DEFAULT_RSSI; | 130 | return DEFAULT_RSSI; |
114 | } | 131 | } |
115 | /* Small wrapper for rt2x00link_antenna_get_rssi_history() */ | ||
116 | #define rt2x00link_antenna_get_rssi_rx_history(__dev) \ | ||
117 | rt2x00link_antenna_get_rssi_history((__dev), \ | ||
118 | (__dev)->link.ant.active.rx) | ||
119 | #define rt2x00link_antenna_get_rssi_tx_history(__dev) \ | ||
120 | rt2x00link_antenna_get_rssi_history((__dev), \ | ||
121 | (__dev)->link.ant.active.tx) | ||
122 | 132 | ||
123 | static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev, | 133 | static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev, |
124 | enum antenna antenna, | ||
125 | int rssi) | 134 | int rssi) |
126 | { | 135 | { |
127 | struct link_ant *ant = &rt2x00dev->link.ant; | 136 | struct link_ant *ant = &rt2x00dev->link.ant; |
128 | ant->rssi_history[ant->active.rx - ANTENNA_A] = rssi; | 137 | ant->rssi_history = rssi; |
129 | } | 138 | } |
130 | /* Small wrapper for rt2x00link_antenna_get_rssi_history() */ | ||
131 | #define rt2x00link_antenna_update_rssi_rx_history(__dev, __rssi) \ | ||
132 | rt2x00link_antenna_update_rssi_history((__dev), \ | ||
133 | (__dev)->link.ant.active.rx, \ | ||
134 | (__rssi)) | ||
135 | #define rt2x00link_antenna_update_rssi_tx_history(__dev, __rssi) \ | ||
136 | rt2x00link_antenna_update_rssi_history((__dev), \ | ||
137 | (__dev)->link.ant.active.tx, \ | ||
138 | (__rssi)) | ||
139 | 139 | ||
140 | static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev) | 140 | static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev) |
141 | { | 141 | { |
142 | rt2x00dev->link.ant.rssi_ant = 0; | 142 | rt2x00dev->link.ant.rssi_ant.avg = 0; |
143 | rt2x00dev->link.ant.rssi_ant.avg_weight = 0; | ||
143 | } | 144 | } |
144 | 145 | ||
145 | static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) | 146 | static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) |
146 | { | 147 | { |
147 | struct link_ant *ant = &rt2x00dev->link.ant; | 148 | struct link_ant *ant = &rt2x00dev->link.ant; |
148 | struct antenna_setup new_ant; | 149 | struct antenna_setup new_ant; |
149 | int sample_a = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_A); | 150 | int other_antenna; |
150 | int sample_b = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_B); | 151 | |
152 | int sample_current = rt2x00link_antenna_get_link_rssi(rt2x00dev); | ||
153 | int sample_other = rt2x00link_antenna_get_rssi_history(rt2x00dev); | ||
151 | 154 | ||
152 | memcpy(&new_ant, &ant->active, sizeof(new_ant)); | 155 | memcpy(&new_ant, &ant->active, sizeof(new_ant)); |
153 | 156 | ||
@@ -161,17 +164,22 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) | |||
161 | * from both antennas. It now is time to determine | 164 | * from both antennas. It now is time to determine |
162 | * which antenna demonstrated the best performance. | 165 | * which antenna demonstrated the best performance. |
163 | * When we are already on the antenna with the best | 166 | * When we are already on the antenna with the best |
164 | * performance, then there really is nothing for us | 167 | * performance, just create a good starting point |
165 | * left to do. | 168 | * for the history and we are done. |
166 | */ | 169 | */ |
167 | if (sample_a == sample_b) | 170 | if (sample_current >= sample_other) { |
171 | rt2x00link_antenna_update_rssi_history(rt2x00dev, | ||
172 | sample_current); | ||
168 | return; | 173 | return; |
174 | } | ||
175 | |||
176 | other_antenna = (ant->active.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; | ||
169 | 177 | ||
170 | if (ant->flags & ANTENNA_RX_DIVERSITY) | 178 | if (ant->flags & ANTENNA_RX_DIVERSITY) |
171 | new_ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; | 179 | new_ant.rx = other_antenna; |
172 | 180 | ||
173 | if (ant->flags & ANTENNA_TX_DIVERSITY) | 181 | if (ant->flags & ANTENNA_TX_DIVERSITY) |
174 | new_ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; | 182 | new_ant.tx = other_antenna; |
175 | 183 | ||
176 | rt2x00lib_config_antenna(rt2x00dev, new_ant); | 184 | rt2x00lib_config_antenna(rt2x00dev, new_ant); |
177 | } | 185 | } |
@@ -190,8 +198,8 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) | |||
190 | * after that update the history with the current value. | 198 | * after that update the history with the current value. |
191 | */ | 199 | */ |
192 | rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev); | 200 | rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev); |
193 | rssi_old = rt2x00link_antenna_get_rssi_rx_history(rt2x00dev); | 201 | rssi_old = rt2x00link_antenna_get_rssi_history(rt2x00dev); |
194 | rt2x00link_antenna_update_rssi_rx_history(rt2x00dev, rssi_curr); | 202 | rt2x00link_antenna_update_rssi_history(rt2x00dev, rssi_curr); |
195 | 203 | ||
196 | /* | 204 | /* |
197 | * Legacy driver indicates that we should swap antenna's | 205 | * Legacy driver indicates that we should swap antenna's |
@@ -216,9 +224,10 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) | |||
216 | rt2x00lib_config_antenna(rt2x00dev, new_ant); | 224 | rt2x00lib_config_antenna(rt2x00dev, new_ant); |
217 | } | 225 | } |
218 | 226 | ||
219 | static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) | 227 | static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) |
220 | { | 228 | { |
221 | struct link_ant *ant = &rt2x00dev->link.ant; | 229 | struct link_ant *ant = &rt2x00dev->link.ant; |
230 | unsigned int flags = ant->flags; | ||
222 | 231 | ||
223 | /* | 232 | /* |
224 | * Determine if software diversity is enabled for | 233 | * Determine if software diversity is enabled for |
@@ -226,30 +235,38 @@ static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) | |||
226 | * Always perform this check since within the link | 235 | * Always perform this check since within the link |
227 | * tuner interval the configuration might have changed. | 236 | * tuner interval the configuration might have changed. |
228 | */ | 237 | */ |
229 | ant->flags &= ~ANTENNA_RX_DIVERSITY; | 238 | flags &= ~ANTENNA_RX_DIVERSITY; |
230 | ant->flags &= ~ANTENNA_TX_DIVERSITY; | 239 | flags &= ~ANTENNA_TX_DIVERSITY; |
231 | 240 | ||
232 | if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) | 241 | if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) |
233 | ant->flags |= ANTENNA_RX_DIVERSITY; | 242 | flags |= ANTENNA_RX_DIVERSITY; |
234 | if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) | 243 | if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) |
235 | ant->flags |= ANTENNA_TX_DIVERSITY; | 244 | flags |= ANTENNA_TX_DIVERSITY; |
236 | 245 | ||
237 | if (!(ant->flags & ANTENNA_RX_DIVERSITY) && | 246 | if (!(ant->flags & ANTENNA_RX_DIVERSITY) && |
238 | !(ant->flags & ANTENNA_TX_DIVERSITY)) { | 247 | !(ant->flags & ANTENNA_TX_DIVERSITY)) { |
239 | ant->flags = 0; | 248 | ant->flags = 0; |
240 | return; | 249 | return true; |
241 | } | 250 | } |
242 | 251 | ||
252 | /* Update flags */ | ||
253 | ant->flags = flags; | ||
254 | |||
243 | /* | 255 | /* |
244 | * If we have only sampled the data over the last period | 256 | * If we have only sampled the data over the last period |
245 | * we should now harvest the data. Otherwise just evaluate | 257 | * we should now harvest the data. Otherwise just evaluate |
246 | * the data. The latter should only be performed once | 258 | * the data. The latter should only be performed once |
247 | * every 2 seconds. | 259 | * every 2 seconds. |
248 | */ | 260 | */ |
249 | if (ant->flags & ANTENNA_MODE_SAMPLE) | 261 | if (ant->flags & ANTENNA_MODE_SAMPLE) { |
250 | rt2x00lib_antenna_diversity_sample(rt2x00dev); | 262 | rt2x00lib_antenna_diversity_sample(rt2x00dev); |
251 | else if (rt2x00dev->link.count & 1) | 263 | return true; |
264 | } else if (rt2x00dev->link.count & 1) { | ||
252 | rt2x00lib_antenna_diversity_eval(rt2x00dev); | 265 | rt2x00lib_antenna_diversity_eval(rt2x00dev); |
266 | return true; | ||
267 | } | ||
268 | |||
269 | return false; | ||
253 | } | 270 | } |
254 | 271 | ||
255 | void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, | 272 | void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, |
@@ -260,8 +277,6 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, | |||
260 | struct link_qual *qual = &rt2x00dev->link.qual; | 277 | struct link_qual *qual = &rt2x00dev->link.qual; |
261 | struct link_ant *ant = &rt2x00dev->link.ant; | 278 | struct link_ant *ant = &rt2x00dev->link.ant; |
262 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 279 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
263 | int avg_rssi = rxdesc->rssi; | ||
264 | int ant_rssi = rxdesc->rssi; | ||
265 | 280 | ||
266 | /* | 281 | /* |
267 | * Frame was received successfully since non-succesfull | 282 | * Frame was received successfully since non-succesfull |
@@ -281,16 +296,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, | |||
281 | /* | 296 | /* |
282 | * Update global RSSI | 297 | * Update global RSSI |
283 | */ | 298 | */ |
284 | if (link->avg_rssi) | 299 | link->avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi); |
285 | avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi, 8); | ||
286 | link->avg_rssi = avg_rssi; | ||
287 | 300 | ||
288 | /* | 301 | /* |
289 | * Update antenna RSSI | 302 | * Update antenna RSSI |
290 | */ | 303 | */ |
291 | if (ant->rssi_ant) | 304 | ant->rssi_ant = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi); |
292 | ant_rssi = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi, 8); | ||
293 | ant->rssi_ant = ant_rssi; | ||
294 | } | 305 | } |
295 | 306 | ||
296 | static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev) | 307 | static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev) |
@@ -423,10 +434,10 @@ static void rt2x00link_tuner(struct work_struct *work) | |||
423 | * collect the RSSI data we could use this. Otherwise we | 434 | * collect the RSSI data we could use this. Otherwise we |
424 | * must fallback to the default RSSI value. | 435 | * must fallback to the default RSSI value. |
425 | */ | 436 | */ |
426 | if (!link->avg_rssi || !qual->rx_success) | 437 | if (!link->avg_rssi.avg || !qual->rx_success) |
427 | qual->rssi = DEFAULT_RSSI; | 438 | qual->rssi = DEFAULT_RSSI; |
428 | else | 439 | else |
429 | qual->rssi = link->avg_rssi; | 440 | qual->rssi = link->avg_rssi.avg; |
430 | 441 | ||
431 | /* | 442 | /* |
432 | * Only perform the link tuning when Link tuning | 443 | * Only perform the link tuning when Link tuning |
@@ -444,18 +455,15 @@ static void rt2x00link_tuner(struct work_struct *work) | |||
444 | /* | 455 | /* |
445 | * Send a signal to the led to update the led signal strength. | 456 | * Send a signal to the led to update the led signal strength. |
446 | */ | 457 | */ |
447 | rt2x00leds_led_quality(rt2x00dev, link->avg_rssi); | 458 | rt2x00leds_led_quality(rt2x00dev, qual->rssi); |
448 | |||
449 | /* | ||
450 | * Evaluate antenna setup, make this the last step since this could | ||
451 | * possibly reset some statistics. | ||
452 | */ | ||
453 | rt2x00lib_antenna_diversity(rt2x00dev); | ||
454 | 459 | ||
455 | /* | 460 | /* |
456 | * Reset the quality counters which recounted during each period. | 461 | * Evaluate antenna setup, make this the last step when |
462 | * rt2x00lib_antenna_diversity made changes the quality | ||
463 | * statistics will be reset. | ||
457 | */ | 464 | */ |
458 | rt2x00link_reset_qual(rt2x00dev); | 465 | if (rt2x00lib_antenna_diversity(rt2x00dev)) |
466 | rt2x00link_reset_qual(rt2x00dev); | ||
459 | 467 | ||
460 | /* | 468 | /* |
461 | * Increase tuner counter, and reschedule the next link tuner run. | 469 | * Increase tuner counter, and reschedule the next link tuner run. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 81febdfd6639..cb7b6d459331 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -274,6 +274,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, | |||
274 | 274 | ||
275 | spin_lock_init(&intf->lock); | 275 | spin_lock_init(&intf->lock); |
276 | spin_lock_init(&intf->seqlock); | 276 | spin_lock_init(&intf->seqlock); |
277 | mutex_init(&intf->beacon_skb_mutex); | ||
277 | intf->beacon = entry; | 278 | intf->beacon = entry; |
278 | 279 | ||
279 | if (conf->type == NL80211_IFTYPE_AP) | 280 | if (conf->type == NL80211_IFTYPE_AP) |
@@ -338,7 +339,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) | |||
338 | { | 339 | { |
339 | struct rt2x00_dev *rt2x00dev = hw->priv; | 340 | struct rt2x00_dev *rt2x00dev = hw->priv; |
340 | struct ieee80211_conf *conf = &hw->conf; | 341 | struct ieee80211_conf *conf = &hw->conf; |
341 | int status; | ||
342 | 342 | ||
343 | /* | 343 | /* |
344 | * mac80211 might be calling this function while we are trying | 344 | * mac80211 might be calling this function while we are trying |
@@ -348,44 +348,29 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) | |||
348 | return 0; | 348 | return 0; |
349 | 349 | ||
350 | /* | 350 | /* |
351 | * Only change device state when the radio is enabled. It does not | 351 | * Some configuration parameters (e.g. channel and antenna values) can |
352 | * matter what parameters we have configured when the radio is disabled | 352 | * only be set when the radio is enabled, but do require the RX to |
353 | * because we won't be able to send or receive anyway. Also note that | 353 | * be off. |
354 | * some configuration parameters (e.g. channel and antenna values) can | ||
355 | * only be set when the radio is enabled. | ||
356 | */ | 354 | */ |
357 | if (conf->radio_enabled) { | 355 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); |
358 | /* For programming the values, we have to turn RX off */ | ||
359 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); | ||
360 | 356 | ||
361 | /* Enable the radio */ | 357 | /* |
362 | status = rt2x00lib_enable_radio(rt2x00dev); | 358 | * When we've just turned on the radio, we want to reprogram |
363 | if (unlikely(status)) | 359 | * everything to ensure a consistent state |
364 | return status; | 360 | */ |
361 | rt2x00lib_config(rt2x00dev, conf, changed); | ||
365 | 362 | ||
366 | /* | 363 | /* |
367 | * When we've just turned on the radio, we want to reprogram | 364 | * After the radio has been enabled we need to configure |
368 | * everything to ensure a consistent state | 365 | * the antenna to the default settings. rt2x00lib_config_antenna() |
369 | */ | 366 | * should determine if any action should be taken based on |
370 | rt2x00lib_config(rt2x00dev, conf, changed); | 367 | * checking if diversity has been enabled or no antenna changes |
368 | * have been made since the last configuration change. | ||
369 | */ | ||
370 | rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant); | ||
371 | 371 | ||
372 | /* | 372 | /* Turn RX back on */ |
373 | * The radio was enabled, configure the antenna to the | 373 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); |
374 | * default settings, the link tuner will later start | ||
375 | * continue configuring the antenna based on the software | ||
376 | * diversity. But for non-diversity configurations, we need | ||
377 | * to have configured the correct state now. | ||
378 | */ | ||
379 | if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) | ||
380 | rt2x00lib_config_antenna(rt2x00dev, | ||
381 | rt2x00dev->default_ant); | ||
382 | |||
383 | /* Turn RX back on */ | ||
384 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); | ||
385 | } else { | ||
386 | /* Disable the radio */ | ||
387 | rt2x00lib_disable_radio(rt2x00dev); | ||
388 | } | ||
389 | 374 | ||
390 | return 0; | 375 | return 0; |
391 | } | 376 | } |
@@ -407,6 +392,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, | |||
407 | FIF_FCSFAIL | | 392 | FIF_FCSFAIL | |
408 | FIF_PLCPFAIL | | 393 | FIF_PLCPFAIL | |
409 | FIF_CONTROL | | 394 | FIF_CONTROL | |
395 | FIF_PSPOLL | | ||
410 | FIF_OTHER_BSS | | 396 | FIF_OTHER_BSS | |
411 | FIF_PROMISC_IN_BSS; | 397 | FIF_PROMISC_IN_BSS; |
412 | 398 | ||
@@ -422,6 +408,22 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, | |||
422 | *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; | 408 | *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; |
423 | 409 | ||
424 | /* | 410 | /* |
411 | * If the device has a single filter for all control frames, | ||
412 | * FIF_CONTROL and FIF_PSPOLL flags imply each other. | ||
413 | * And if the device has more than one filter for control frames | ||
414 | * of different types, but has no a separate filter for PS Poll frames, | ||
415 | * FIF_CONTROL flag implies FIF_PSPOLL. | ||
416 | */ | ||
417 | if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags)) { | ||
418 | if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL) | ||
419 | *total_flags |= FIF_CONTROL | FIF_PSPOLL; | ||
420 | } | ||
421 | if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags)) { | ||
422 | if (*total_flags & FIF_CONTROL) | ||
423 | *total_flags |= FIF_PSPOLL; | ||
424 | } | ||
425 | |||
426 | /* | ||
425 | * Check if there is any work left for us. | 427 | * Check if there is any work left for us. |
426 | */ | 428 | */ |
427 | if (rt2x00dev->packet_filter == *total_flags) | 429 | if (rt2x00dev->packet_filter == *total_flags) |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 44e5b3279ca7..06af823efd83 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -324,7 +324,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, | |||
324 | /* | 324 | /* |
325 | * Check if more fragments are pending | 325 | * Check if more fragments are pending |
326 | */ | 326 | */ |
327 | if (ieee80211_has_morefrags(hdr->frame_control)) { | 327 | if (ieee80211_has_morefrags(hdr->frame_control) || |
328 | (tx_info->flags & IEEE80211_TX_CTL_MORE_FRAMES)) { | ||
328 | __set_bit(ENTRY_TXD_BURST, &txdesc->flags); | 329 | __set_bit(ENTRY_TXD_BURST, &txdesc->flags); |
329 | __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags); | 330 | __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags); |
330 | } | 331 | } |
@@ -452,9 +453,21 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) | |||
452 | rt2x00crypto_tx_remove_iv(skb, &txdesc); | 453 | rt2x00crypto_tx_remove_iv(skb, &txdesc); |
453 | } | 454 | } |
454 | 455 | ||
456 | /* | ||
457 | * When DMA allocation is required we should guarentee to the | ||
458 | * driver that the DMA is aligned to a 4-byte boundary. | ||
459 | * Aligning the header to this boundary can be done by calling | ||
460 | * rt2x00queue_payload_align with the header length of 0. | ||
461 | * However some drivers require L2 padding to pad the payload | ||
462 | * rather then the header. This could be a requirement for | ||
463 | * PCI and USB devices, while header alignment only is valid | ||
464 | * for PCI devices. | ||
465 | */ | ||
455 | if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) | 466 | if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) |
456 | rt2x00queue_payload_align(entry->skb, true, | 467 | rt2x00queue_payload_align(entry->skb, true, |
457 | txdesc.header_length); | 468 | txdesc.header_length); |
469 | else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) | ||
470 | rt2x00queue_payload_align(entry->skb, false, 0); | ||
458 | 471 | ||
459 | /* | 472 | /* |
460 | * It could be possible that the queue was corrupted and this | 473 | * It could be possible that the queue was corrupted and this |
@@ -490,14 +503,25 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, | |||
490 | if (unlikely(!intf->beacon)) | 503 | if (unlikely(!intf->beacon)) |
491 | return -ENOBUFS; | 504 | return -ENOBUFS; |
492 | 505 | ||
506 | mutex_lock(&intf->beacon_skb_mutex); | ||
507 | |||
508 | /* | ||
509 | * Clean up the beacon skb. | ||
510 | */ | ||
511 | rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb); | ||
512 | intf->beacon->skb = NULL; | ||
513 | |||
493 | if (!enable_beacon) { | 514 | if (!enable_beacon) { |
494 | rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_BEACON); | 515 | rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_BEACON); |
516 | mutex_unlock(&intf->beacon_skb_mutex); | ||
495 | return 0; | 517 | return 0; |
496 | } | 518 | } |
497 | 519 | ||
498 | intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif); | 520 | intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif); |
499 | if (!intf->beacon->skb) | 521 | if (!intf->beacon->skb) { |
522 | mutex_unlock(&intf->beacon_skb_mutex); | ||
500 | return -ENOMEM; | 523 | return -ENOMEM; |
524 | } | ||
501 | 525 | ||
502 | /* | 526 | /* |
503 | * Copy all TX descriptor information into txdesc, | 527 | * Copy all TX descriptor information into txdesc, |
@@ -535,6 +559,8 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, | |||
535 | rt2x00dev->ops->lib->write_beacon(intf->beacon); | 559 | rt2x00dev->ops->lib->write_beacon(intf->beacon); |
536 | rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); | 560 | rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); |
537 | 561 | ||
562 | mutex_unlock(&intf->beacon_skb_mutex); | ||
563 | |||
538 | return 0; | 564 | return 0; |
539 | } | 565 | } |
540 | 566 | ||
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index e20dd7431f21..f4b4b86da4da 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -530,7 +530,7 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev, | |||
530 | rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, | 530 | rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, |
531 | !(filter_flags & FIF_PLCPFAIL)); | 531 | !(filter_flags & FIF_PLCPFAIL)); |
532 | rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, | 532 | rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, |
533 | !(filter_flags & FIF_CONTROL)); | 533 | !(filter_flags & (FIF_CONTROL | FIF_PSPOLL))); |
534 | rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, | 534 | rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, |
535 | !(filter_flags & FIF_PROMISC_IN_BSS)); | 535 | !(filter_flags & FIF_PROMISC_IN_BSS)); |
536 | rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, | 536 | rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, |
@@ -1855,8 +1855,6 @@ static void rt61pci_write_beacon(struct queue_entry *entry) | |||
1855 | * otherwise we might be sending out invalid data. | 1855 | * otherwise we might be sending out invalid data. |
1856 | */ | 1856 | */ |
1857 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); | 1857 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); |
1858 | rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); | ||
1859 | rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); | ||
1860 | rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); | 1858 | rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); |
1861 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); | 1859 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); |
1862 | 1860 | ||
@@ -2624,6 +2622,12 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
2624 | return retval; | 2622 | return retval; |
2625 | 2623 | ||
2626 | /* | 2624 | /* |
2625 | * This device has multiple filters for control frames, | ||
2626 | * but has no a separate filter for PS Poll frames. | ||
2627 | */ | ||
2628 | __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); | ||
2629 | |||
2630 | /* | ||
2627 | * This device requires firmware and DMA mapped skbs. | 2631 | * This device requires firmware and DMA mapped skbs. |
2628 | */ | 2632 | */ |
2629 | __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); | 2633 | __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4f9b1772e1a1..4d94b65943f1 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -493,7 +493,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, | |||
493 | rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, | 493 | rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, |
494 | !(filter_flags & FIF_PLCPFAIL)); | 494 | !(filter_flags & FIF_PLCPFAIL)); |
495 | rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, | 495 | rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, |
496 | !(filter_flags & FIF_CONTROL)); | 496 | !(filter_flags & (FIF_CONTROL | FIF_PSPOLL))); |
497 | rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, | 497 | rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, |
498 | !(filter_flags & FIF_PROMISC_IN_BSS)); | 498 | !(filter_flags & FIF_PROMISC_IN_BSS)); |
499 | rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, | 499 | rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, |
@@ -1527,8 +1527,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry) | |||
1527 | * otherwise we might be sending out invalid data. | 1527 | * otherwise we might be sending out invalid data. |
1528 | */ | 1528 | */ |
1529 | rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); | 1529 | rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); |
1530 | rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); | ||
1531 | rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); | ||
1532 | rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); | 1530 | rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); |
1533 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); | 1531 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); |
1534 | 1532 | ||
@@ -2144,6 +2142,12 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
2144 | return retval; | 2142 | return retval; |
2145 | 2143 | ||
2146 | /* | 2144 | /* |
2145 | * This device has multiple filters for control frames, | ||
2146 | * but has no a separate filter for PS Poll frames. | ||
2147 | */ | ||
2148 | __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); | ||
2149 | |||
2150 | /* | ||
2147 | * This device requires firmware. | 2151 | * This device requires firmware. |
2148 | */ | 2152 | */ |
2149 | __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); | 2153 | __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); |
diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h index 34a5555cc19c..562222e6cf1f 100644 --- a/drivers/net/wireless/rtl818x/rtl818x.h +++ b/drivers/net/wireless/rtl818x/rtl818x.h | |||
@@ -194,8 +194,18 @@ struct rtl818x_rf_ops { | |||
194 | void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *); | 194 | void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *); |
195 | }; | 195 | }; |
196 | 196 | ||
197 | /* Tx/Rx flags are common between RTL818X chips */ | 197 | /** |
198 | 198 | * enum rtl818x_tx_desc_flags - Tx/Rx flags are common between RTL818X chips | |
199 | * | ||
200 | * @RTL818X_TX_DESC_FLAG_NO_ENC: Disable hardware based encryption. | ||
201 | * @RTL818X_TX_DESC_FLAG_TX_OK: TX frame was ACKed. | ||
202 | * @RTL818X_TX_DESC_FLAG_SPLCP: Use short preamble. | ||
203 | * @RTL818X_TX_DESC_FLAG_MOREFRAG: More fragments follow. | ||
204 | * @RTL818X_TX_DESC_FLAG_CTS: Use CTS-to-self protection. | ||
205 | * @RTL818X_TX_DESC_FLAG_RTS: Use RTS/CTS protection. | ||
206 | * @RTL818X_TX_DESC_FLAG_LS: Last segment of the frame. | ||
207 | * @RTL818X_TX_DESC_FLAG_FS: First segment of the frame. | ||
208 | */ | ||
199 | enum rtl818x_tx_desc_flags { | 209 | enum rtl818x_tx_desc_flags { |
200 | RTL818X_TX_DESC_FLAG_NO_ENC = (1 << 15), | 210 | RTL818X_TX_DESC_FLAG_NO_ENC = (1 << 15), |
201 | RTL818X_TX_DESC_FLAG_TX_OK = (1 << 15), | 211 | RTL818X_TX_DESC_FLAG_TX_OK = (1 << 15), |
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 82a0f97975de..7b14d5bc63d6 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig | |||
@@ -7,12 +7,46 @@ menuconfig WL12XX | |||
7 | 7 | ||
8 | config WL1251 | 8 | config WL1251 |
9 | tristate "TI wl1251 support" | 9 | tristate "TI wl1251 support" |
10 | depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS | 10 | depends on WL12XX && GENERIC_HARDIRQS |
11 | select FW_LOADER | 11 | select FW_LOADER |
12 | select CRC7 | 12 | select CRC7 |
13 | ---help--- | 13 | ---help--- |
14 | This module adds support for wireless adapters based on | 14 | This module adds support for wireless adapters based on |
15 | TI wl1251 chipset. | 15 | TI wl1251 chipset. |
16 | 16 | ||
17 | If you choose to build a module, it'll be called wl1251. Say N if | 17 | If you choose to build a module, it'll be called wl1251. Say |
18 | N if unsure. | ||
19 | |||
20 | config WL1251_SPI | ||
21 | tristate "TI wl1251 SPI support" | ||
22 | depends on WL1251 && SPI_MASTER | ||
23 | ---help--- | ||
24 | This module adds support for the SPI interface of adapters using | ||
25 | TI wl1251 chipset. Select this if your platform is using | ||
26 | the SPI bus. | ||
27 | |||
28 | If you choose to build a module, it'll be called wl1251_spi. | ||
29 | Say N if unsure. | ||
30 | |||
31 | config WL1251_SDIO | ||
32 | tristate "TI wl1251 SDIO support" | ||
33 | depends on WL1251 && MMC | ||
34 | ---help--- | ||
35 | This module adds support for the SDIO interface of adapters using | ||
36 | TI wl1251 chipset. Select this if your platform is using | ||
37 | the SDIO bus. | ||
38 | |||
39 | If you choose to build a module, it'll be called | ||
40 | wl1251_sdio. Say N if unsure. | ||
41 | |||
42 | config WL1271 | ||
43 | tristate "TI wl1271 support" | ||
44 | depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS | ||
45 | select FW_LOADER | ||
46 | select CRC7 | ||
47 | ---help--- | ||
48 | This module adds support for wireless adapters based on the | ||
49 | TI wl1271 chipset. | ||
50 | |||
51 | If you choose to build a module, it'll be called wl1271. Say N if | ||
18 | unsure. | 52 | unsure. |
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index d5595a841f5f..62e37ad01cc0 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile | |||
@@ -1,5 +1,14 @@ | |||
1 | wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \ | 1 | wl1251-objs = wl1251_main.o wl1251_event.o \ |
2 | wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ | 2 | wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ |
3 | wl1251_acx.o wl1251_boot.o wl1251_init.o \ | 3 | wl1251_acx.o wl1251_boot.o wl1251_init.o \ |
4 | wl1251_ops.o wl1251_debugfs.o | 4 | wl1251_debugfs.o wl1251_io.o |
5 | |||
5 | obj-$(CONFIG_WL1251) += wl1251.o | 6 | obj-$(CONFIG_WL1251) += wl1251.o |
7 | obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o | ||
8 | obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o | ||
9 | |||
10 | wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \ | ||
11 | wl1271_event.o wl1271_tx.o wl1271_rx.o \ | ||
12 | wl1271_ps.o wl1271_acx.o wl1271_boot.o \ | ||
13 | wl1271_init.o wl1271_debugfs.o | ||
14 | obj-$(CONFIG_WL1271) += wl1271.o | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 665aca02bea9..998e4b6252bd 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h | |||
@@ -143,35 +143,6 @@ struct wl1251_partition_set { | |||
143 | 143 | ||
144 | struct wl1251; | 144 | struct wl1251; |
145 | 145 | ||
146 | /* FIXME: I'm not sure about this structure name */ | ||
147 | struct wl1251_chip { | ||
148 | u32 id; | ||
149 | |||
150 | const char *fw_filename; | ||
151 | const char *nvs_filename; | ||
152 | |||
153 | char fw_ver[21]; | ||
154 | |||
155 | unsigned int power_on_sleep; | ||
156 | int intr_cmd_complete; | ||
157 | int intr_init_complete; | ||
158 | |||
159 | int (*op_upload_fw)(struct wl1251 *wl); | ||
160 | int (*op_upload_nvs)(struct wl1251 *wl); | ||
161 | int (*op_boot)(struct wl1251 *wl); | ||
162 | void (*op_set_ecpu_ctrl)(struct wl1251 *wl, u32 flag); | ||
163 | void (*op_target_enable_interrupts)(struct wl1251 *wl); | ||
164 | int (*op_hw_init)(struct wl1251 *wl); | ||
165 | int (*op_plt_init)(struct wl1251 *wl); | ||
166 | void (*op_tx_flush)(struct wl1251 *wl); | ||
167 | void (*op_fw_version)(struct wl1251 *wl); | ||
168 | int (*op_cmd_join)(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, | ||
169 | u16 beacon_interval, u8 wait); | ||
170 | |||
171 | struct wl1251_partition_set *p_table; | ||
172 | enum wl12xx_acx_int_reg *acx_reg_table; | ||
173 | }; | ||
174 | |||
175 | struct wl1251_stats { | 146 | struct wl1251_stats { |
176 | struct acx_statistics *fw_stats; | 147 | struct acx_statistics *fw_stats; |
177 | unsigned long fw_stats_update; | 148 | unsigned long fw_stats_update; |
@@ -281,11 +252,20 @@ struct wl1251_debugfs { | |||
281 | struct dentry *excessive_retries; | 252 | struct dentry *excessive_retries; |
282 | }; | 253 | }; |
283 | 254 | ||
255 | struct wl1251_if_operations { | ||
256 | void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
257 | void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
258 | void (*reset)(struct wl1251 *wl); | ||
259 | void (*enable_irq)(struct wl1251 *wl); | ||
260 | void (*disable_irq)(struct wl1251 *wl); | ||
261 | }; | ||
262 | |||
284 | struct wl1251 { | 263 | struct wl1251 { |
285 | struct ieee80211_hw *hw; | 264 | struct ieee80211_hw *hw; |
286 | bool mac80211_registered; | 265 | bool mac80211_registered; |
287 | 266 | ||
288 | struct spi_device *spi; | 267 | void *if_priv; |
268 | const struct wl1251_if_operations *if_ops; | ||
289 | 269 | ||
290 | void (*set_power)(bool enable); | 270 | void (*set_power)(bool enable); |
291 | int irq; | 271 | int irq; |
@@ -298,8 +278,6 @@ struct wl1251 { | |||
298 | int virtual_mem_addr; | 278 | int virtual_mem_addr; |
299 | int virtual_reg_addr; | 279 | int virtual_reg_addr; |
300 | 280 | ||
301 | struct wl1251_chip chip; | ||
302 | |||
303 | int cmd_box_addr; | 281 | int cmd_box_addr; |
304 | int event_box_addr; | 282 | int event_box_addr; |
305 | struct boot_attr boot_attr; | 283 | struct boot_attr boot_attr; |
@@ -382,6 +360,9 @@ struct wl1251 { | |||
382 | /* PSM mode requested */ | 360 | /* PSM mode requested */ |
383 | bool psm_requested; | 361 | bool psm_requested; |
384 | 362 | ||
363 | u16 beacon_int; | ||
364 | u8 dtim_period; | ||
365 | |||
385 | /* in dBm */ | 366 | /* in dBm */ |
386 | int power_level; | 367 | int power_level; |
387 | 368 | ||
@@ -392,11 +373,20 @@ struct wl1251 { | |||
392 | u32 buffer_cmd; | 373 | u32 buffer_cmd; |
393 | u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; | 374 | u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; |
394 | struct wl1251_rx_descriptor *rx_descriptor; | 375 | struct wl1251_rx_descriptor *rx_descriptor; |
376 | |||
377 | u32 chip_id; | ||
378 | char fw_ver[21]; | ||
395 | }; | 379 | }; |
396 | 380 | ||
397 | int wl1251_plt_start(struct wl1251 *wl); | 381 | int wl1251_plt_start(struct wl1251 *wl); |
398 | int wl1251_plt_stop(struct wl1251 *wl); | 382 | int wl1251_plt_stop(struct wl1251 *wl); |
399 | 383 | ||
384 | struct ieee80211_hw *wl1251_alloc_hw(void); | ||
385 | int wl1251_free_hw(struct wl1251 *wl); | ||
386 | int wl1251_init_ieee80211(struct wl1251 *wl); | ||
387 | void wl1251_enable_interrupts(struct wl1251 *wl); | ||
388 | void wl1251_disable_interrupts(struct wl1251 *wl); | ||
389 | |||
400 | #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ | 390 | #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ |
401 | #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS | 391 | #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS |
402 | #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ | 392 | #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ |
@@ -405,11 +395,10 @@ int wl1251_plt_stop(struct wl1251 *wl); | |||
405 | 395 | ||
406 | #define WL1251_TX_QUEUE_MAX_LENGTH 20 | 396 | #define WL1251_TX_QUEUE_MAX_LENGTH 20 |
407 | 397 | ||
408 | /* Different chips need different sleep times after power on. WL1271 needs | 398 | #define WL1251_DEFAULT_BEACON_INT 100 |
409 | * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we | 399 | #define WL1251_DEFAULT_DTIM_PERIOD 1 |
410 | * know the chip ID, we change the sleep value in the wl1251 chip structure, | 400 | |
411 | * so in subsequent power ons, we don't waste more time then needed. */ | 401 | #define WL1251_DEFAULT_CHANNEL 0 |
412 | #define WL1251_DEFAULT_POWER_ON_SLEEP 200 | ||
413 | 402 | ||
414 | #define CHIP_ID_1251_PG10 (0x7010101) | 403 | #define CHIP_ID_1251_PG10 (0x7010101) |
415 | #define CHIP_ID_1251_PG11 (0x7020101) | 404 | #define CHIP_ID_1251_PG11 (0x7020101) |
@@ -417,4 +406,19 @@ int wl1251_plt_stop(struct wl1251 *wl); | |||
417 | #define CHIP_ID_1271_PG10 (0x4030101) | 406 | #define CHIP_ID_1271_PG10 (0x4030101) |
418 | #define CHIP_ID_1271_PG20 (0x4030111) | 407 | #define CHIP_ID_1271_PG20 (0x4030111) |
419 | 408 | ||
409 | #define WL1251_FW_NAME "wl1251-fw.bin" | ||
410 | #define WL1251_NVS_NAME "wl1251-nvs.bin" | ||
411 | |||
412 | #define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ | ||
413 | |||
414 | #define WL1251_PART_DOWN_MEM_START 0x0 | ||
415 | #define WL1251_PART_DOWN_MEM_SIZE 0x16800 | ||
416 | #define WL1251_PART_DOWN_REG_START REGISTERS_BASE | ||
417 | #define WL1251_PART_DOWN_REG_SIZE REGISTERS_DOWN_SIZE | ||
418 | |||
419 | #define WL1251_PART_WORK_MEM_START 0x28000 | ||
420 | #define WL1251_PART_WORK_MEM_SIZE 0x14000 | ||
421 | #define WL1251_PART_WORK_REG_START REGISTERS_BASE | ||
422 | #define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE | ||
423 | |||
420 | #endif | 424 | #endif |
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index a46c92a29526..10b26c4532c9 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c | |||
@@ -2,11 +2,10 @@ | |||
2 | 2 | ||
3 | #include <linux/module.h> | 3 | #include <linux/module.h> |
4 | #include <linux/crc7.h> | 4 | #include <linux/crc7.h> |
5 | #include <linux/spi/spi.h> | ||
6 | 5 | ||
7 | #include "wl1251.h" | 6 | #include "wl1251.h" |
8 | #include "reg.h" | 7 | #include "wl1251_reg.h" |
9 | #include "wl1251_spi.h" | 8 | #include "wl1251_cmd.h" |
10 | #include "wl1251_ps.h" | 9 | #include "wl1251_ps.h" |
11 | 10 | ||
12 | int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, | 11 | int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, |
@@ -838,3 +837,82 @@ int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) | |||
838 | 837 | ||
839 | return 0; | 838 | return 0; |
840 | } | 839 | } |
840 | |||
841 | int wl1251_acx_rate_policies(struct wl1251 *wl) | ||
842 | { | ||
843 | struct acx_rate_policy *acx; | ||
844 | int ret = 0; | ||
845 | |||
846 | wl1251_debug(DEBUG_ACX, "acx rate policies"); | ||
847 | |||
848 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
849 | |||
850 | if (!acx) { | ||
851 | ret = -ENOMEM; | ||
852 | goto out; | ||
853 | } | ||
854 | |||
855 | /* configure one default (one-size-fits-all) rate class */ | ||
856 | acx->rate_class_cnt = 1; | ||
857 | acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; | ||
858 | acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
859 | acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
860 | acx->rate_class[0].aflags = 0; | ||
861 | |||
862 | ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); | ||
863 | if (ret < 0) { | ||
864 | wl1251_warning("Setting of rate policies failed: %d", ret); | ||
865 | goto out; | ||
866 | } | ||
867 | |||
868 | out: | ||
869 | kfree(acx); | ||
870 | return ret; | ||
871 | } | ||
872 | |||
873 | int wl1251_acx_mem_cfg(struct wl1251 *wl) | ||
874 | { | ||
875 | struct wl1251_acx_config_memory *mem_conf; | ||
876 | int ret, i; | ||
877 | |||
878 | wl1251_debug(DEBUG_ACX, "acx mem cfg"); | ||
879 | |||
880 | mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); | ||
881 | if (!mem_conf) { | ||
882 | ret = -ENOMEM; | ||
883 | goto out; | ||
884 | } | ||
885 | |||
886 | /* memory config */ | ||
887 | mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); | ||
888 | mem_conf->mem_config.rx_mem_block_num = 35; | ||
889 | mem_conf->mem_config.tx_min_mem_block_num = 64; | ||
890 | mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; | ||
891 | mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; | ||
892 | mem_conf->mem_config.num_ssid_profiles = 1; | ||
893 | mem_conf->mem_config.debug_buffer_size = | ||
894 | cpu_to_le16(TRACE_BUFFER_MAX_SIZE); | ||
895 | |||
896 | /* RX queue config */ | ||
897 | mem_conf->rx_queue_config.dma_address = 0; | ||
898 | mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; | ||
899 | mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; | ||
900 | mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; | ||
901 | |||
902 | /* TX queue config */ | ||
903 | for (i = 0; i < MAX_TX_QUEUES; i++) { | ||
904 | mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; | ||
905 | mem_conf->tx_queue_config[i].attributes = i; | ||
906 | } | ||
907 | |||
908 | ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, | ||
909 | sizeof(*mem_conf)); | ||
910 | if (ret < 0) { | ||
911 | wl1251_warning("wl1251 mem config failed: %d", ret); | ||
912 | goto out; | ||
913 | } | ||
914 | |||
915 | out: | ||
916 | kfree(mem_conf); | ||
917 | return ret; | ||
918 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index 2e7b1933a8f9..cafb91459504 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h | |||
@@ -1031,6 +1031,150 @@ struct acx_statistics { | |||
1031 | struct acx_rxpipe_statistics rxpipe; | 1031 | struct acx_rxpipe_statistics rxpipe; |
1032 | } __attribute__ ((packed)); | 1032 | } __attribute__ ((packed)); |
1033 | 1033 | ||
1034 | #define ACX_MAX_RATE_CLASSES 8 | ||
1035 | #define ACX_RATE_MASK_UNSPECIFIED 0 | ||
1036 | #define ACX_RATE_RETRY_LIMIT 10 | ||
1037 | |||
1038 | struct acx_rate_class { | ||
1039 | u32 enabled_rates; | ||
1040 | u8 short_retry_limit; | ||
1041 | u8 long_retry_limit; | ||
1042 | u8 aflags; | ||
1043 | u8 reserved; | ||
1044 | }; | ||
1045 | |||
1046 | struct acx_rate_policy { | ||
1047 | struct acx_header header; | ||
1048 | |||
1049 | u32 rate_class_cnt; | ||
1050 | struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; | ||
1051 | } __attribute__ ((packed)); | ||
1052 | |||
1053 | struct wl1251_acx_memory { | ||
1054 | __le16 num_stations; /* number of STAs to be supported. */ | ||
1055 | u16 reserved_1; | ||
1056 | |||
1057 | /* | ||
1058 | * Nmber of memory buffers for the RX mem pool. | ||
1059 | * The actual number may be less if there are | ||
1060 | * not enough blocks left for the minimum num | ||
1061 | * of TX ones. | ||
1062 | */ | ||
1063 | u8 rx_mem_block_num; | ||
1064 | u8 reserved_2; | ||
1065 | u8 num_tx_queues; /* From 1 to 16 */ | ||
1066 | u8 host_if_options; /* HOST_IF* */ | ||
1067 | u8 tx_min_mem_block_num; | ||
1068 | u8 num_ssid_profiles; | ||
1069 | __le16 debug_buffer_size; | ||
1070 | } __attribute__ ((packed)); | ||
1071 | |||
1072 | |||
1073 | #define ACX_RX_DESC_MIN 1 | ||
1074 | #define ACX_RX_DESC_MAX 127 | ||
1075 | #define ACX_RX_DESC_DEF 32 | ||
1076 | struct wl1251_acx_rx_queue_config { | ||
1077 | u8 num_descs; | ||
1078 | u8 pad; | ||
1079 | u8 type; | ||
1080 | u8 priority; | ||
1081 | __le32 dma_address; | ||
1082 | } __attribute__ ((packed)); | ||
1083 | |||
1084 | #define ACX_TX_DESC_MIN 1 | ||
1085 | #define ACX_TX_DESC_MAX 127 | ||
1086 | #define ACX_TX_DESC_DEF 16 | ||
1087 | struct wl1251_acx_tx_queue_config { | ||
1088 | u8 num_descs; | ||
1089 | u8 pad[2]; | ||
1090 | u8 attributes; | ||
1091 | } __attribute__ ((packed)); | ||
1092 | |||
1093 | #define MAX_TX_QUEUE_CONFIGS 5 | ||
1094 | #define MAX_TX_QUEUES 4 | ||
1095 | struct wl1251_acx_config_memory { | ||
1096 | struct acx_header header; | ||
1097 | |||
1098 | struct wl1251_acx_memory mem_config; | ||
1099 | struct wl1251_acx_rx_queue_config rx_queue_config; | ||
1100 | struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; | ||
1101 | } __attribute__ ((packed)); | ||
1102 | |||
1103 | struct wl1251_acx_mem_map { | ||
1104 | struct acx_header header; | ||
1105 | |||
1106 | void *code_start; | ||
1107 | void *code_end; | ||
1108 | |||
1109 | void *wep_defkey_start; | ||
1110 | void *wep_defkey_end; | ||
1111 | |||
1112 | void *sta_table_start; | ||
1113 | void *sta_table_end; | ||
1114 | |||
1115 | void *packet_template_start; | ||
1116 | void *packet_template_end; | ||
1117 | |||
1118 | void *queue_memory_start; | ||
1119 | void *queue_memory_end; | ||
1120 | |||
1121 | void *packet_memory_pool_start; | ||
1122 | void *packet_memory_pool_end; | ||
1123 | |||
1124 | void *debug_buffer1_start; | ||
1125 | void *debug_buffer1_end; | ||
1126 | |||
1127 | void *debug_buffer2_start; | ||
1128 | void *debug_buffer2_end; | ||
1129 | |||
1130 | /* Number of blocks FW allocated for TX packets */ | ||
1131 | u32 num_tx_mem_blocks; | ||
1132 | |||
1133 | /* Number of blocks FW allocated for RX packets */ | ||
1134 | u32 num_rx_mem_blocks; | ||
1135 | } __attribute__ ((packed)); | ||
1136 | |||
1137 | /************************************************************************* | ||
1138 | |||
1139 | Host Interrupt Register (WiLink -> Host) | ||
1140 | |||
1141 | **************************************************************************/ | ||
1142 | |||
1143 | /* RX packet is ready in Xfer buffer #0 */ | ||
1144 | #define WL1251_ACX_INTR_RX0_DATA BIT(0) | ||
1145 | |||
1146 | /* TX result(s) are in the TX complete buffer */ | ||
1147 | #define WL1251_ACX_INTR_TX_RESULT BIT(1) | ||
1148 | |||
1149 | /* OBSOLETE */ | ||
1150 | #define WL1251_ACX_INTR_TX_XFR BIT(2) | ||
1151 | |||
1152 | /* RX packet is ready in Xfer buffer #1 */ | ||
1153 | #define WL1251_ACX_INTR_RX1_DATA BIT(3) | ||
1154 | |||
1155 | /* Event was entered to Event MBOX #A */ | ||
1156 | #define WL1251_ACX_INTR_EVENT_A BIT(4) | ||
1157 | |||
1158 | /* Event was entered to Event MBOX #B */ | ||
1159 | #define WL1251_ACX_INTR_EVENT_B BIT(5) | ||
1160 | |||
1161 | /* OBSOLETE */ | ||
1162 | #define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) | ||
1163 | |||
1164 | /* Trace meassge on MBOX #A */ | ||
1165 | #define WL1251_ACX_INTR_TRACE_A BIT(7) | ||
1166 | |||
1167 | /* Trace meassge on MBOX #B */ | ||
1168 | #define WL1251_ACX_INTR_TRACE_B BIT(8) | ||
1169 | |||
1170 | /* Command processing completion */ | ||
1171 | #define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) | ||
1172 | |||
1173 | /* Init sequence is done */ | ||
1174 | #define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) | ||
1175 | |||
1176 | #define WL1251_ACX_INTR_ALL 0xFFFFFFFF | ||
1177 | |||
1034 | enum { | 1178 | enum { |
1035 | ACX_WAKE_UP_CONDITIONS = 0x0002, | 1179 | ACX_WAKE_UP_CONDITIONS = 0x0002, |
1036 | ACX_MEM_CFG = 0x0003, | 1180 | ACX_MEM_CFG = 0x0003, |
@@ -1142,5 +1286,7 @@ int wl1251_acx_cts_protect(struct wl1251 *wl, | |||
1142 | enum acx_ctsprotect_type ctsprotect); | 1286 | enum acx_ctsprotect_type ctsprotect); |
1143 | int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); | 1287 | int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); |
1144 | int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); | 1288 | int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); |
1289 | int wl1251_acx_rate_policies(struct wl1251 *wl); | ||
1290 | int wl1251_acx_mem_cfg(struct wl1251 *wl); | ||
1145 | 1291 | ||
1146 | #endif /* __WL1251_ACX_H__ */ | 1292 | #endif /* __WL1251_ACX_H__ */ |
diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index d8a155dc2fa1..592c3b5cc8f8 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c | |||
@@ -23,15 +23,12 @@ | |||
23 | 23 | ||
24 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
25 | 25 | ||
26 | #include "reg.h" | 26 | #include "wl1251_reg.h" |
27 | #include "wl1251_boot.h" | 27 | #include "wl1251_boot.h" |
28 | #include "wl1251_io.h" | ||
28 | #include "wl1251_spi.h" | 29 | #include "wl1251_spi.h" |
29 | #include "wl1251_event.h" | 30 | #include "wl1251_event.h" |
30 | 31 | #include "wl1251_acx.h" | |
31 | static void wl1251_boot_enable_interrupts(struct wl1251 *wl) | ||
32 | { | ||
33 | enable_irq(wl->irq); | ||
34 | } | ||
35 | 32 | ||
36 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) | 33 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) |
37 | { | 34 | { |
@@ -212,18 +209,30 @@ int wl1251_boot_init_seq(struct wl1251 *wl) | |||
212 | return 0; | 209 | return 0; |
213 | } | 210 | } |
214 | 211 | ||
212 | static void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) | ||
213 | { | ||
214 | u32 cpu_ctrl; | ||
215 | |||
216 | /* 10.5.0 run the firmware (I) */ | ||
217 | cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
218 | |||
219 | /* 10.5.1 run the firmware (II) */ | ||
220 | cpu_ctrl &= ~flag; | ||
221 | wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); | ||
222 | } | ||
223 | |||
215 | int wl1251_boot_run_firmware(struct wl1251 *wl) | 224 | int wl1251_boot_run_firmware(struct wl1251 *wl) |
216 | { | 225 | { |
217 | int loop, ret; | 226 | int loop, ret; |
218 | u32 chip_id, interrupt; | 227 | u32 chip_id, interrupt; |
219 | 228 | ||
220 | wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); | 229 | wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); |
221 | 230 | ||
222 | chip_id = wl1251_reg_read32(wl, CHIP_ID_B); | 231 | chip_id = wl1251_reg_read32(wl, CHIP_ID_B); |
223 | 232 | ||
224 | wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); | 233 | wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); |
225 | 234 | ||
226 | if (chip_id != wl->chip.id) { | 235 | if (chip_id != wl->chip_id) { |
227 | wl1251_error("chip id doesn't match after firmware boot"); | 236 | wl1251_error("chip id doesn't match after firmware boot"); |
228 | return -EIO; | 237 | return -EIO; |
229 | } | 238 | } |
@@ -240,9 +249,9 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) | |||
240 | return -EIO; | 249 | return -EIO; |
241 | } | 250 | } |
242 | /* check that ACX_INTR_INIT_COMPLETE is enabled */ | 251 | /* check that ACX_INTR_INIT_COMPLETE is enabled */ |
243 | else if (interrupt & wl->chip.intr_init_complete) { | 252 | else if (interrupt & WL1251_ACX_INTR_INIT_COMPLETE) { |
244 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | 253 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, |
245 | wl->chip.intr_init_complete); | 254 | WL1251_ACX_INTR_INIT_COMPLETE); |
246 | break; | 255 | break; |
247 | } | 256 | } |
248 | } | 257 | } |
@@ -260,16 +269,15 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) | |||
260 | wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); | 269 | wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); |
261 | 270 | ||
262 | /* set the working partition to its "running" mode offset */ | 271 | /* set the working partition to its "running" mode offset */ |
263 | wl1251_set_partition(wl, | 272 | wl1251_set_partition(wl, WL1251_PART_WORK_MEM_START, |
264 | wl->chip.p_table[PART_WORK].mem.start, | 273 | WL1251_PART_WORK_MEM_SIZE, |
265 | wl->chip.p_table[PART_WORK].mem.size, | 274 | WL1251_PART_WORK_REG_START, |
266 | wl->chip.p_table[PART_WORK].reg.start, | 275 | WL1251_PART_WORK_REG_SIZE); |
267 | wl->chip.p_table[PART_WORK].reg.size); | ||
268 | 276 | ||
269 | wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", | 277 | wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", |
270 | wl->cmd_box_addr, wl->event_box_addr); | 278 | wl->cmd_box_addr, wl->event_box_addr); |
271 | 279 | ||
272 | wl->chip.op_fw_version(wl); | 280 | wl1251_acx_fw_version(wl, wl->fw_ver, sizeof(wl->fw_ver)); |
273 | 281 | ||
274 | /* | 282 | /* |
275 | * in case of full asynchronous mode the firmware event must be | 283 | * in case of full asynchronous mode the firmware event must be |
@@ -277,9 +285,16 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) | |||
277 | */ | 285 | */ |
278 | 286 | ||
279 | /* enable gpio interrupts */ | 287 | /* enable gpio interrupts */ |
280 | wl1251_boot_enable_interrupts(wl); | 288 | wl1251_enable_interrupts(wl); |
281 | 289 | ||
282 | wl->chip.op_target_enable_interrupts(wl); | 290 | /* Enable target's interrupts */ |
291 | wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | | ||
292 | WL1251_ACX_INTR_RX1_DATA | | ||
293 | WL1251_ACX_INTR_TX_RESULT | | ||
294 | WL1251_ACX_INTR_EVENT_A | | ||
295 | WL1251_ACX_INTR_EVENT_B | | ||
296 | WL1251_ACX_INTR_INIT_COMPLETE; | ||
297 | wl1251_boot_target_enable_interrupts(wl); | ||
283 | 298 | ||
284 | /* unmask all mbox events */ | 299 | /* unmask all mbox events */ |
285 | wl->event_mask = 0xffffffff; | 300 | wl->event_mask = 0xffffffff; |
@@ -295,3 +310,218 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) | |||
295 | /* firmware startup completed */ | 310 | /* firmware startup completed */ |
296 | return 0; | 311 | return 0; |
297 | } | 312 | } |
313 | |||
314 | static int wl1251_boot_upload_firmware(struct wl1251 *wl) | ||
315 | { | ||
316 | int addr, chunk_num, partition_limit; | ||
317 | size_t fw_data_len; | ||
318 | u8 *p; | ||
319 | |||
320 | /* whal_FwCtrl_LoadFwImageSm() */ | ||
321 | |||
322 | wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", | ||
323 | wl1251_reg_read32(wl, CHIP_ID_B)); | ||
324 | |||
325 | /* 10.0 check firmware length and set partition */ | ||
326 | fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | | ||
327 | (wl->fw[6] << 8) | (wl->fw[7]); | ||
328 | |||
329 | wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, | ||
330 | CHUNK_SIZE); | ||
331 | |||
332 | if ((fw_data_len % 4) != 0) { | ||
333 | wl1251_error("firmware length not multiple of four"); | ||
334 | return -EIO; | ||
335 | } | ||
336 | |||
337 | wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START, | ||
338 | WL1251_PART_DOWN_MEM_SIZE, | ||
339 | WL1251_PART_DOWN_REG_START, | ||
340 | WL1251_PART_DOWN_REG_SIZE); | ||
341 | |||
342 | /* 10.1 set partition limit and chunk num */ | ||
343 | chunk_num = 0; | ||
344 | partition_limit = WL1251_PART_DOWN_MEM_SIZE; | ||
345 | |||
346 | while (chunk_num < fw_data_len / CHUNK_SIZE) { | ||
347 | /* 10.2 update partition, if needed */ | ||
348 | addr = WL1251_PART_DOWN_MEM_START + | ||
349 | (chunk_num + 2) * CHUNK_SIZE; | ||
350 | if (addr > partition_limit) { | ||
351 | addr = WL1251_PART_DOWN_MEM_START + | ||
352 | chunk_num * CHUNK_SIZE; | ||
353 | partition_limit = chunk_num * CHUNK_SIZE + | ||
354 | WL1251_PART_DOWN_MEM_SIZE; | ||
355 | wl1251_set_partition(wl, | ||
356 | addr, | ||
357 | WL1251_PART_DOWN_MEM_SIZE, | ||
358 | WL1251_PART_DOWN_REG_START, | ||
359 | WL1251_PART_DOWN_REG_SIZE); | ||
360 | } | ||
361 | |||
362 | /* 10.3 upload the chunk */ | ||
363 | addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; | ||
364 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
365 | wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", | ||
366 | p, addr); | ||
367 | wl1251_mem_write(wl, addr, p, CHUNK_SIZE); | ||
368 | |||
369 | chunk_num++; | ||
370 | } | ||
371 | |||
372 | /* 10.4 upload the last chunk */ | ||
373 | addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; | ||
374 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
375 | wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", | ||
376 | fw_data_len % CHUNK_SIZE, p, addr); | ||
377 | wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static int wl1251_boot_upload_nvs(struct wl1251 *wl) | ||
383 | { | ||
384 | size_t nvs_len, nvs_bytes_written, burst_len; | ||
385 | int nvs_start, i; | ||
386 | u32 dest_addr, val; | ||
387 | u8 *nvs_ptr, *nvs; | ||
388 | |||
389 | nvs = wl->nvs; | ||
390 | if (nvs == NULL) | ||
391 | return -ENODEV; | ||
392 | |||
393 | nvs_ptr = nvs; | ||
394 | |||
395 | nvs_len = wl->nvs_len; | ||
396 | nvs_start = wl->fw_len; | ||
397 | |||
398 | /* | ||
399 | * Layout before the actual NVS tables: | ||
400 | * 1 byte : burst length. | ||
401 | * 2 bytes: destination address. | ||
402 | * n bytes: data to burst copy. | ||
403 | * | ||
404 | * This is ended by a 0 length, then the NVS tables. | ||
405 | */ | ||
406 | |||
407 | while (nvs_ptr[0]) { | ||
408 | burst_len = nvs_ptr[0]; | ||
409 | dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); | ||
410 | |||
411 | /* We move our pointer to the data */ | ||
412 | nvs_ptr += 3; | ||
413 | |||
414 | for (i = 0; i < burst_len; i++) { | ||
415 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
416 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
417 | |||
418 | wl1251_debug(DEBUG_BOOT, | ||
419 | "nvs burst write 0x%x: 0x%x", | ||
420 | dest_addr, val); | ||
421 | wl1251_mem_write32(wl, dest_addr, val); | ||
422 | |||
423 | nvs_ptr += 4; | ||
424 | dest_addr += 4; | ||
425 | } | ||
426 | } | ||
427 | |||
428 | /* | ||
429 | * We've reached the first zero length, the first NVS table | ||
430 | * is 7 bytes further. | ||
431 | */ | ||
432 | nvs_ptr += 7; | ||
433 | nvs_len -= nvs_ptr - nvs; | ||
434 | nvs_len = ALIGN(nvs_len, 4); | ||
435 | |||
436 | /* Now we must set the partition correctly */ | ||
437 | wl1251_set_partition(wl, nvs_start, | ||
438 | WL1251_PART_DOWN_MEM_SIZE, | ||
439 | WL1251_PART_DOWN_REG_START, | ||
440 | WL1251_PART_DOWN_REG_SIZE); | ||
441 | |||
442 | /* And finally we upload the NVS tables */ | ||
443 | nvs_bytes_written = 0; | ||
444 | while (nvs_bytes_written < nvs_len) { | ||
445 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
446 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
447 | |||
448 | val = cpu_to_le32(val); | ||
449 | |||
450 | wl1251_debug(DEBUG_BOOT, | ||
451 | "nvs write table 0x%x: 0x%x", | ||
452 | nvs_start, val); | ||
453 | wl1251_mem_write32(wl, nvs_start, val); | ||
454 | |||
455 | nvs_ptr += 4; | ||
456 | nvs_bytes_written += 4; | ||
457 | nvs_start += 4; | ||
458 | } | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | int wl1251_boot(struct wl1251 *wl) | ||
464 | { | ||
465 | int ret = 0, minor_minor_e2_ver; | ||
466 | u32 tmp, boot_data; | ||
467 | |||
468 | ret = wl1251_boot_soft_reset(wl); | ||
469 | if (ret < 0) | ||
470 | goto out; | ||
471 | |||
472 | /* 2. start processing NVS file */ | ||
473 | ret = wl1251_boot_upload_nvs(wl); | ||
474 | if (ret < 0) | ||
475 | goto out; | ||
476 | |||
477 | /* write firmware's last address (ie. it's length) to | ||
478 | * ACX_EEPROMLESS_IND_REG */ | ||
479 | wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); | ||
480 | |||
481 | /* 6. read the EEPROM parameters */ | ||
482 | tmp = wl1251_reg_read32(wl, SCR_PAD2); | ||
483 | |||
484 | /* 7. read bootdata */ | ||
485 | wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; | ||
486 | wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; | ||
487 | tmp = wl1251_reg_read32(wl, SCR_PAD3); | ||
488 | |||
489 | /* 8. check bootdata and call restart sequence */ | ||
490 | wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; | ||
491 | minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; | ||
492 | |||
493 | wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " | ||
494 | "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", | ||
495 | wl->boot_attr.radio_type, wl->boot_attr.major, | ||
496 | wl->boot_attr.minor, minor_minor_e2_ver); | ||
497 | |||
498 | ret = wl1251_boot_init_seq(wl); | ||
499 | if (ret < 0) | ||
500 | goto out; | ||
501 | |||
502 | /* 9. NVS processing done */ | ||
503 | boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
504 | |||
505 | wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); | ||
506 | |||
507 | /* 10. check that ECPU_CONTROL_HALT bits are set in | ||
508 | * pWhalBus->uBootData and start uploading firmware | ||
509 | */ | ||
510 | if ((boot_data & ECPU_CONTROL_HALT) == 0) { | ||
511 | wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); | ||
512 | ret = -EIO; | ||
513 | goto out; | ||
514 | } | ||
515 | |||
516 | ret = wl1251_boot_upload_firmware(wl); | ||
517 | if (ret < 0) | ||
518 | goto out; | ||
519 | |||
520 | /* 10.5 start firmware */ | ||
521 | ret = wl1251_boot_run_firmware(wl); | ||
522 | if (ret < 0) | ||
523 | goto out; | ||
524 | |||
525 | out: | ||
526 | return ret; | ||
527 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h index 798362d71e3f..90063697e8f2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.h +++ b/drivers/net/wireless/wl12xx/wl1251_boot.h | |||
@@ -30,6 +30,7 @@ int wl1251_boot_soft_reset(struct wl1251 *wl); | |||
30 | int wl1251_boot_init_seq(struct wl1251 *wl); | 30 | int wl1251_boot_init_seq(struct wl1251 *wl); |
31 | int wl1251_boot_run_firmware(struct wl1251 *wl); | 31 | int wl1251_boot_run_firmware(struct wl1251 *wl); |
32 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl); | 32 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl); |
33 | int wl1251_boot(struct wl1251 *wl); | ||
33 | 34 | ||
34 | /* number of times we try to read the INIT interrupt */ | 35 | /* number of times we try to read the INIT interrupt */ |
35 | #define INIT_LOOP 20000 | 36 | #define INIT_LOOP 20000 |
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index dc04d1fc2ee4..770f260726bd 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c | |||
@@ -2,11 +2,10 @@ | |||
2 | 2 | ||
3 | #include <linux/module.h> | 3 | #include <linux/module.h> |
4 | #include <linux/crc7.h> | 4 | #include <linux/crc7.h> |
5 | #include <linux/spi/spi.h> | ||
6 | 5 | ||
7 | #include "wl1251.h" | 6 | #include "wl1251.h" |
8 | #include "reg.h" | 7 | #include "wl1251_reg.h" |
9 | #include "wl1251_spi.h" | 8 | #include "wl1251_io.h" |
10 | #include "wl1251_ps.h" | 9 | #include "wl1251_ps.h" |
11 | #include "wl1251_acx.h" | 10 | #include "wl1251_acx.h" |
12 | 11 | ||
@@ -31,14 +30,14 @@ int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) | |||
31 | 30 | ||
32 | WARN_ON(len % 4 != 0); | 31 | WARN_ON(len % 4 != 0); |
33 | 32 | ||
34 | wl1251_spi_mem_write(wl, wl->cmd_box_addr, buf, len); | 33 | wl1251_mem_write(wl, wl->cmd_box_addr, buf, len); |
35 | 34 | ||
36 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); | 35 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); |
37 | 36 | ||
38 | timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT); | 37 | timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT); |
39 | 38 | ||
40 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | 39 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); |
41 | while (!(intr & wl->chip.intr_cmd_complete)) { | 40 | while (!(intr & WL1251_ACX_INTR_CMD_COMPLETE)) { |
42 | if (time_after(jiffies, timeout)) { | 41 | if (time_after(jiffies, timeout)) { |
43 | wl1251_error("command complete timeout"); | 42 | wl1251_error("command complete timeout"); |
44 | ret = -ETIMEDOUT; | 43 | ret = -ETIMEDOUT; |
@@ -51,7 +50,7 @@ int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) | |||
51 | } | 50 | } |
52 | 51 | ||
53 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | 52 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, |
54 | wl->chip.intr_cmd_complete); | 53 | WL1251_ACX_INTR_CMD_COMPLETE); |
55 | 54 | ||
56 | out: | 55 | out: |
57 | return ret; | 56 | return ret; |
@@ -86,7 +85,7 @@ int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) | |||
86 | * The answer would be a wl1251_command, where the | 85 | * The answer would be a wl1251_command, where the |
87 | * parameter array contains the actual answer. | 86 | * parameter array contains the actual answer. |
88 | */ | 87 | */ |
89 | wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); | 88 | wl1251_mem_read(wl, wl->cmd_box_addr, buf, buf_len); |
90 | 89 | ||
91 | cmd_answer = buf; | 90 | cmd_answer = buf; |
92 | 91 | ||
@@ -125,7 +124,7 @@ int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len) | |||
125 | } | 124 | } |
126 | 125 | ||
127 | /* the interrogate command got in, we can read the answer */ | 126 | /* the interrogate command got in, we can read the answer */ |
128 | wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, len); | 127 | wl1251_mem_read(wl, wl->cmd_box_addr, buf, len); |
129 | 128 | ||
130 | acx = buf; | 129 | acx = buf; |
131 | if (acx->cmd.status != CMD_STATUS_SUCCESS) | 130 | if (acx->cmd.status != CMD_STATUS_SUCCESS) |
@@ -252,10 +251,9 @@ out: | |||
252 | return ret; | 251 | return ret; |
253 | } | 252 | } |
254 | 253 | ||
255 | int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, | 254 | int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, |
256 | u16 beacon_interval, u8 wait) | 255 | u16 beacon_interval, u8 dtim_interval) |
257 | { | 256 | { |
258 | unsigned long timeout; | ||
259 | struct cmd_join *join; | 257 | struct cmd_join *join; |
260 | int ret, i; | 258 | int ret, i; |
261 | u8 *bssid; | 259 | u8 *bssid; |
@@ -266,15 +264,9 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, | |||
266 | goto out; | 264 | goto out; |
267 | } | 265 | } |
268 | 266 | ||
269 | /* FIXME: this should be in main.c */ | 267 | wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d", |
270 | ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, | 268 | bss_type == BSS_TYPE_IBSS ? " ibss" : "", |
271 | DEFAULT_HW_GEN_MODULATION_TYPE, | 269 | channel, beacon_interval, dtim_interval); |
272 | wl->tx_mgmt_frm_rate, | ||
273 | wl->tx_mgmt_frm_mod); | ||
274 | if (ret < 0) | ||
275 | goto out; | ||
276 | |||
277 | wl1251_debug(DEBUG_CMD, "cmd join"); | ||
278 | 270 | ||
279 | /* Reverse order BSSID */ | 271 | /* Reverse order BSSID */ |
280 | bssid = (u8 *) &join->bssid_lsb; | 272 | bssid = (u8 *) &join->bssid_lsb; |
@@ -284,13 +276,22 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, | |||
284 | join->rx_config_options = wl->rx_config; | 276 | join->rx_config_options = wl->rx_config; |
285 | join->rx_filter_options = wl->rx_filter; | 277 | join->rx_filter_options = wl->rx_filter; |
286 | 278 | ||
279 | /* | ||
280 | * FIXME: disable temporarily all filters because after commit | ||
281 | * 9cef8737 "mac80211: fix managed mode BSSID handling" broke | ||
282 | * association. The filter logic needs to be implemented properly | ||
283 | * and once that is done, this hack can be removed. | ||
284 | */ | ||
285 | join->rx_config_options = 0; | ||
286 | join->rx_filter_options = WL1251_DEFAULT_RX_FILTER; | ||
287 | |||
287 | join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | | 288 | join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | |
288 | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; | 289 | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; |
289 | 290 | ||
290 | join->beacon_interval = beacon_interval; | 291 | join->beacon_interval = beacon_interval; |
291 | join->dtim_interval = dtim_interval; | 292 | join->dtim_interval = dtim_interval; |
292 | join->bss_type = bss_type; | 293 | join->bss_type = bss_type; |
293 | join->channel = wl->channel; | 294 | join->channel = channel; |
294 | join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; | 295 | join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; |
295 | 296 | ||
296 | ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); | 297 | ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); |
@@ -299,15 +300,6 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, | |||
299 | goto out; | 300 | goto out; |
300 | } | 301 | } |
301 | 302 | ||
302 | timeout = msecs_to_jiffies(JOIN_TIMEOUT); | ||
303 | |||
304 | /* | ||
305 | * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to | ||
306 | * simplify locking we just sleep instead, for now | ||
307 | */ | ||
308 | if (wait) | ||
309 | msleep(10); | ||
310 | |||
311 | out: | 303 | out: |
312 | kfree(join); | 304 | kfree(join); |
313 | return ret; | 305 | return ret; |
@@ -318,14 +310,6 @@ int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode) | |||
318 | struct wl1251_cmd_ps_params *ps_params = NULL; | 310 | struct wl1251_cmd_ps_params *ps_params = NULL; |
319 | int ret = 0; | 311 | int ret = 0; |
320 | 312 | ||
321 | /* FIXME: this should be in ps.c */ | ||
322 | ret = wl1251_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, | ||
323 | wl->listen_int); | ||
324 | if (ret < 0) { | ||
325 | wl1251_error("couldn't set wake up conditions"); | ||
326 | goto out; | ||
327 | } | ||
328 | |||
329 | wl1251_debug(DEBUG_CMD, "cmd set ps mode"); | 313 | wl1251_debug(DEBUG_CMD, "cmd set ps mode"); |
330 | 314 | ||
331 | ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); | 315 | ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); |
@@ -379,7 +363,7 @@ int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, | |||
379 | } | 363 | } |
380 | 364 | ||
381 | /* the read command got in, we can now read the answer */ | 365 | /* the read command got in, we can now read the answer */ |
382 | wl1251_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); | 366 | wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); |
383 | 367 | ||
384 | if (cmd->header.status != CMD_STATUS_SUCCESS) | 368 | if (cmd->header.status != CMD_STATUS_SUCCESS) |
385 | wl1251_error("error in read command result: %d", | 369 | wl1251_error("error in read command result: %d", |
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index 64f228dd9a9b..dff798ad0ef5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h | |||
@@ -36,8 +36,8 @@ int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); | |||
36 | int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, | 36 | int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, |
37 | void *bitmap, u16 bitmap_len, u8 bitmap_control); | 37 | void *bitmap, u16 bitmap_len, u8 bitmap_control); |
38 | int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); | 38 | int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); |
39 | int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, | 39 | int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, |
40 | u16 beacon_interval, u8 wait); | 40 | u16 beacon_interval, u8 dtim_interval); |
41 | int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); | 41 | int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); |
42 | int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, | 42 | int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, |
43 | size_t len); | 43 | size_t len); |
diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index 1a0a0bc1a31f..00076c4a8a21 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c | |||
@@ -23,8 +23,8 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "wl1251.h" | 25 | #include "wl1251.h" |
26 | #include "reg.h" | 26 | #include "wl1251_reg.h" |
27 | #include "wl1251_spi.h" | 27 | #include "wl1251_io.h" |
28 | #include "wl1251_event.h" | 28 | #include "wl1251_event.h" |
29 | #include "wl1251_ps.h" | 29 | #include "wl1251_ps.h" |
30 | 30 | ||
@@ -39,6 +39,7 @@ static int wl1251_event_scan_complete(struct wl1251 *wl, | |||
39 | mutex_unlock(&wl->mutex); | 39 | mutex_unlock(&wl->mutex); |
40 | ieee80211_scan_completed(wl->hw, false); | 40 | ieee80211_scan_completed(wl->hw, false); |
41 | mutex_lock(&wl->mutex); | 41 | mutex_lock(&wl->mutex); |
42 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); | ||
42 | wl->scanning = false; | 43 | wl->scanning = false; |
43 | } | 44 | } |
44 | 45 | ||
@@ -112,7 +113,7 @@ int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num) | |||
112 | return -EINVAL; | 113 | return -EINVAL; |
113 | 114 | ||
114 | /* first we read the mbox descriptor */ | 115 | /* first we read the mbox descriptor */ |
115 | wl1251_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, | 116 | wl1251_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, |
116 | sizeof(struct event_mailbox)); | 117 | sizeof(struct event_mailbox)); |
117 | 118 | ||
118 | /* process the descriptor */ | 119 | /* process the descriptor */ |
diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index df6c60f0fd66..b2ee4f468fc4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "wl12xx_80211.h" | 28 | #include "wl12xx_80211.h" |
29 | #include "wl1251_acx.h" | 29 | #include "wl1251_acx.h" |
30 | #include "wl1251_cmd.h" | 30 | #include "wl1251_cmd.h" |
31 | #include "wl1251_reg.h" | ||
31 | 32 | ||
32 | int wl1251_hw_init_hwenc_config(struct wl1251 *wl) | 33 | int wl1251_hw_init_hwenc_config(struct wl1251 *wl) |
33 | { | 34 | { |
@@ -198,3 +199,215 @@ int wl1251_hw_init_power_auth(struct wl1251 *wl) | |||
198 | { | 199 | { |
199 | return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); | 200 | return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); |
200 | } | 201 | } |
202 | |||
203 | int wl1251_hw_init_mem_config(struct wl1251 *wl) | ||
204 | { | ||
205 | int ret; | ||
206 | |||
207 | ret = wl1251_acx_mem_cfg(wl); | ||
208 | if (ret < 0) | ||
209 | return ret; | ||
210 | |||
211 | wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), | ||
212 | GFP_KERNEL); | ||
213 | if (!wl->target_mem_map) { | ||
214 | wl1251_error("couldn't allocate target memory map"); | ||
215 | return -ENOMEM; | ||
216 | } | ||
217 | |||
218 | /* we now ask for the firmware built memory map */ | ||
219 | ret = wl1251_acx_mem_map(wl, wl->target_mem_map, | ||
220 | sizeof(struct wl1251_acx_mem_map)); | ||
221 | if (ret < 0) { | ||
222 | wl1251_error("couldn't retrieve firmware memory map"); | ||
223 | kfree(wl->target_mem_map); | ||
224 | wl->target_mem_map = NULL; | ||
225 | return ret; | ||
226 | } | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static int wl1251_hw_init_txq_fill(u8 qid, | ||
232 | struct acx_tx_queue_qos_config *config, | ||
233 | u32 num_blocks) | ||
234 | { | ||
235 | config->qid = qid; | ||
236 | |||
237 | switch (qid) { | ||
238 | case QOS_AC_BE: | ||
239 | config->high_threshold = | ||
240 | (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; | ||
241 | config->low_threshold = | ||
242 | (QOS_TX_LOW_BE_DEF * num_blocks) / 100; | ||
243 | break; | ||
244 | case QOS_AC_BK: | ||
245 | config->high_threshold = | ||
246 | (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; | ||
247 | config->low_threshold = | ||
248 | (QOS_TX_LOW_BK_DEF * num_blocks) / 100; | ||
249 | break; | ||
250 | case QOS_AC_VI: | ||
251 | config->high_threshold = | ||
252 | (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; | ||
253 | config->low_threshold = | ||
254 | (QOS_TX_LOW_VI_DEF * num_blocks) / 100; | ||
255 | break; | ||
256 | case QOS_AC_VO: | ||
257 | config->high_threshold = | ||
258 | (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; | ||
259 | config->low_threshold = | ||
260 | (QOS_TX_LOW_VO_DEF * num_blocks) / 100; | ||
261 | break; | ||
262 | default: | ||
263 | wl1251_error("Invalid TX queue id: %d", qid); | ||
264 | return -EINVAL; | ||
265 | } | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) | ||
271 | { | ||
272 | struct acx_tx_queue_qos_config *config; | ||
273 | struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; | ||
274 | int ret, i; | ||
275 | |||
276 | wl1251_debug(DEBUG_ACX, "acx tx queue config"); | ||
277 | |||
278 | config = kzalloc(sizeof(*config), GFP_KERNEL); | ||
279 | if (!config) { | ||
280 | ret = -ENOMEM; | ||
281 | goto out; | ||
282 | } | ||
283 | |||
284 | for (i = 0; i < MAX_NUM_OF_AC; i++) { | ||
285 | ret = wl1251_hw_init_txq_fill(i, config, | ||
286 | wl_mem_map->num_tx_mem_blocks); | ||
287 | if (ret < 0) | ||
288 | goto out; | ||
289 | |||
290 | ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, | ||
291 | config, sizeof(*config)); | ||
292 | if (ret < 0) | ||
293 | goto out; | ||
294 | } | ||
295 | |||
296 | out: | ||
297 | kfree(config); | ||
298 | return ret; | ||
299 | } | ||
300 | |||
301 | static int wl1251_hw_init_data_path_config(struct wl1251 *wl) | ||
302 | { | ||
303 | int ret; | ||
304 | |||
305 | /* asking for the data path parameters */ | ||
306 | wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), | ||
307 | GFP_KERNEL); | ||
308 | if (!wl->data_path) { | ||
309 | wl1251_error("Couldnt allocate data path parameters"); | ||
310 | return -ENOMEM; | ||
311 | } | ||
312 | |||
313 | ret = wl1251_acx_data_path_params(wl, wl->data_path); | ||
314 | if (ret < 0) { | ||
315 | kfree(wl->data_path); | ||
316 | wl->data_path = NULL; | ||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | |||
324 | int wl1251_hw_init(struct wl1251 *wl) | ||
325 | { | ||
326 | struct wl1251_acx_mem_map *wl_mem_map; | ||
327 | int ret; | ||
328 | |||
329 | ret = wl1251_hw_init_hwenc_config(wl); | ||
330 | if (ret < 0) | ||
331 | return ret; | ||
332 | |||
333 | /* Template settings */ | ||
334 | ret = wl1251_hw_init_templates_config(wl); | ||
335 | if (ret < 0) | ||
336 | return ret; | ||
337 | |||
338 | /* Default memory configuration */ | ||
339 | ret = wl1251_hw_init_mem_config(wl); | ||
340 | if (ret < 0) | ||
341 | return ret; | ||
342 | |||
343 | /* Default data path configuration */ | ||
344 | ret = wl1251_hw_init_data_path_config(wl); | ||
345 | if (ret < 0) | ||
346 | goto out_free_memmap; | ||
347 | |||
348 | /* RX config */ | ||
349 | ret = wl1251_hw_init_rx_config(wl, | ||
350 | RX_CFG_PROMISCUOUS | RX_CFG_TSF, | ||
351 | RX_FILTER_OPTION_DEF); | ||
352 | /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, | ||
353 | RX_FILTER_OPTION_FILTER_ALL); */ | ||
354 | if (ret < 0) | ||
355 | goto out_free_data_path; | ||
356 | |||
357 | /* TX queues config */ | ||
358 | ret = wl1251_hw_init_tx_queue_config(wl); | ||
359 | if (ret < 0) | ||
360 | goto out_free_data_path; | ||
361 | |||
362 | /* PHY layer config */ | ||
363 | ret = wl1251_hw_init_phy_config(wl); | ||
364 | if (ret < 0) | ||
365 | goto out_free_data_path; | ||
366 | |||
367 | /* Beacon filtering */ | ||
368 | ret = wl1251_hw_init_beacon_filter(wl); | ||
369 | if (ret < 0) | ||
370 | goto out_free_data_path; | ||
371 | |||
372 | /* Bluetooth WLAN coexistence */ | ||
373 | ret = wl1251_hw_init_pta(wl); | ||
374 | if (ret < 0) | ||
375 | goto out_free_data_path; | ||
376 | |||
377 | /* Energy detection */ | ||
378 | ret = wl1251_hw_init_energy_detection(wl); | ||
379 | if (ret < 0) | ||
380 | goto out_free_data_path; | ||
381 | |||
382 | /* Beacons and boradcast settings */ | ||
383 | ret = wl1251_hw_init_beacon_broadcast(wl); | ||
384 | if (ret < 0) | ||
385 | goto out_free_data_path; | ||
386 | |||
387 | /* Enable data path */ | ||
388 | ret = wl1251_cmd_data_path(wl, wl->channel, 1); | ||
389 | if (ret < 0) | ||
390 | goto out_free_data_path; | ||
391 | |||
392 | /* Default power state */ | ||
393 | ret = wl1251_hw_init_power_auth(wl); | ||
394 | if (ret < 0) | ||
395 | goto out_free_data_path; | ||
396 | |||
397 | wl_mem_map = wl->target_mem_map; | ||
398 | wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", | ||
399 | wl_mem_map->num_tx_mem_blocks, | ||
400 | wl->data_path->tx_control_addr, | ||
401 | wl_mem_map->num_rx_mem_blocks, | ||
402 | wl->data_path->rx_control_addr); | ||
403 | |||
404 | return 0; | ||
405 | |||
406 | out_free_data_path: | ||
407 | kfree(wl->data_path); | ||
408 | |||
409 | out_free_memmap: | ||
410 | kfree(wl->target_mem_map); | ||
411 | |||
412 | return ret; | ||
413 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h index 8596188e834e..b3b25ec885ea 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl12xx/wl1251_init.h | |||
@@ -35,5 +35,7 @@ int wl1251_hw_init_pta(struct wl1251 *wl); | |||
35 | int wl1251_hw_init_energy_detection(struct wl1251 *wl); | 35 | int wl1251_hw_init_energy_detection(struct wl1251 *wl); |
36 | int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl); | 36 | int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl); |
37 | int wl1251_hw_init_power_auth(struct wl1251 *wl); | 37 | int wl1251_hw_init_power_auth(struct wl1251 *wl); |
38 | int wl1251_hw_init_mem_config(struct wl1251 *wl); | ||
39 | int wl1251_hw_init(struct wl1251 *wl); | ||
38 | 40 | ||
39 | #endif | 41 | #endif |
diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c new file mode 100644 index 000000000000..f1c232e0887f --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_io.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "wl1251.h" | ||
25 | #include "wl1251_reg.h" | ||
26 | #include "wl1251_io.h" | ||
27 | |||
28 | /* FIXME: this is static data nowadays and the table can be removed */ | ||
29 | static enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = { | ||
30 | [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), | ||
31 | [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), | ||
32 | [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), | ||
33 | [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), | ||
34 | [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), | ||
35 | [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), | ||
36 | [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), | ||
37 | [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), | ||
38 | [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), | ||
39 | [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), | ||
40 | [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) | ||
41 | }; | ||
42 | |||
43 | static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) | ||
44 | { | ||
45 | /* If the address is lower than REGISTERS_BASE, it means that this is | ||
46 | * a chip-specific register address, so look it up in the registers | ||
47 | * table */ | ||
48 | if (addr < REGISTERS_BASE) { | ||
49 | /* Make sure we don't go over the table */ | ||
50 | if (addr >= ACX_REG_TABLE_LEN) { | ||
51 | wl1251_error("address out of range (%d)", addr); | ||
52 | return -EINVAL; | ||
53 | } | ||
54 | addr = wl1251_io_reg_table[addr]; | ||
55 | } | ||
56 | |||
57 | return addr - wl->physical_reg_addr + wl->virtual_reg_addr; | ||
58 | } | ||
59 | |||
60 | static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) | ||
61 | { | ||
62 | return addr - wl->physical_mem_addr + wl->virtual_mem_addr; | ||
63 | } | ||
64 | |||
65 | void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) | ||
66 | { | ||
67 | int physical; | ||
68 | |||
69 | physical = wl1251_translate_mem_addr(wl, addr); | ||
70 | |||
71 | wl->if_ops->read(wl, physical, buf, len); | ||
72 | } | ||
73 | |||
74 | void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) | ||
75 | { | ||
76 | int physical; | ||
77 | |||
78 | physical = wl1251_translate_mem_addr(wl, addr); | ||
79 | |||
80 | wl->if_ops->write(wl, physical, buf, len); | ||
81 | } | ||
82 | |||
83 | u32 wl1251_mem_read32(struct wl1251 *wl, int addr) | ||
84 | { | ||
85 | return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); | ||
86 | } | ||
87 | |||
88 | void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) | ||
89 | { | ||
90 | wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); | ||
91 | } | ||
92 | |||
93 | u32 wl1251_reg_read32(struct wl1251 *wl, int addr) | ||
94 | { | ||
95 | return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); | ||
96 | } | ||
97 | |||
98 | void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) | ||
99 | { | ||
100 | wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); | ||
101 | } | ||
102 | |||
103 | /* Set the partitions to access the chip addresses. | ||
104 | * | ||
105 | * There are two VIRTUAL partitions (the memory partition and the | ||
106 | * registers partition), which are mapped to two different areas of the | ||
107 | * PHYSICAL (hardware) memory. This function also makes other checks to | ||
108 | * ensure that the partitions are not overlapping. In the diagram below, the | ||
109 | * memory partition comes before the register partition, but the opposite is | ||
110 | * also supported. | ||
111 | * | ||
112 | * PHYSICAL address | ||
113 | * space | ||
114 | * | ||
115 | * | | | ||
116 | * ...+----+--> mem_start | ||
117 | * VIRTUAL address ... | | | ||
118 | * space ... | | [PART_0] | ||
119 | * ... | | | ||
120 | * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size | ||
121 | * | | ... | | | ||
122 | * |MEM | ... | | | ||
123 | * | | ... | | | ||
124 | * part_size <--+----+... | | {unused area) | ||
125 | * | | ... | | | ||
126 | * |REG | ... | | | ||
127 | * part_size | | ... | | | ||
128 | * + <--+----+... ...+----+--> reg_start | ||
129 | * reg_size ... | | | ||
130 | * ... | | [PART_1] | ||
131 | * ... | | | ||
132 | * ...+----+--> reg_start + reg_size | ||
133 | * | | | ||
134 | * | ||
135 | */ | ||
136 | void wl1251_set_partition(struct wl1251 *wl, | ||
137 | u32 mem_start, u32 mem_size, | ||
138 | u32 reg_start, u32 reg_size) | ||
139 | { | ||
140 | struct wl1251_partition partition[2]; | ||
141 | |||
142 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
143 | mem_start, mem_size); | ||
144 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
145 | reg_start, reg_size); | ||
146 | |||
147 | /* Make sure that the two partitions together don't exceed the | ||
148 | * address range */ | ||
149 | if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { | ||
150 | wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" | ||
151 | " address range. Truncating partition[0]."); | ||
152 | mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; | ||
153 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
154 | mem_start, mem_size); | ||
155 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
156 | reg_start, reg_size); | ||
157 | } | ||
158 | |||
159 | if ((mem_start < reg_start) && | ||
160 | ((mem_start + mem_size) > reg_start)) { | ||
161 | /* Guarantee that the memory partition doesn't overlap the | ||
162 | * registers partition */ | ||
163 | wl1251_debug(DEBUG_SPI, "End of partition[0] is " | ||
164 | "overlapping partition[1]. Adjusted."); | ||
165 | mem_size = reg_start - mem_start; | ||
166 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
167 | mem_start, mem_size); | ||
168 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
169 | reg_start, reg_size); | ||
170 | } else if ((reg_start < mem_start) && | ||
171 | ((reg_start + reg_size) > mem_start)) { | ||
172 | /* Guarantee that the register partition doesn't overlap the | ||
173 | * memory partition */ | ||
174 | wl1251_debug(DEBUG_SPI, "End of partition[1] is" | ||
175 | " overlapping partition[0]. Adjusted."); | ||
176 | reg_size = mem_start - reg_start; | ||
177 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
178 | mem_start, mem_size); | ||
179 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
180 | reg_start, reg_size); | ||
181 | } | ||
182 | |||
183 | partition[0].start = mem_start; | ||
184 | partition[0].size = mem_size; | ||
185 | partition[1].start = reg_start; | ||
186 | partition[1].size = reg_size; | ||
187 | |||
188 | wl->physical_mem_addr = mem_start; | ||
189 | wl->physical_reg_addr = reg_start; | ||
190 | |||
191 | wl->virtual_mem_addr = 0; | ||
192 | wl->virtual_reg_addr = mem_size; | ||
193 | |||
194 | wl->if_ops->write(wl, HW_ACCESS_PART0_SIZE_ADDR, partition, | ||
195 | sizeof(partition)); | ||
196 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_io.h b/drivers/net/wireless/wl12xx/wl1251_io.h new file mode 100644 index 000000000000..b89d2ac62efb --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_io.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __WL1251_IO_H__ | ||
22 | #define __WL1251_IO_H__ | ||
23 | |||
24 | #include "wl1251.h" | ||
25 | |||
26 | #define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 | ||
27 | |||
28 | #define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 | ||
29 | #define HW_ACCESS_PART0_START_ADDR 0x1FFC4 | ||
30 | #define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 | ||
31 | #define HW_ACCESS_PART1_START_ADDR 0x1FFCC | ||
32 | |||
33 | #define HW_ACCESS_REGISTER_SIZE 4 | ||
34 | |||
35 | #define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 | ||
36 | |||
37 | static inline u32 wl1251_read32(struct wl1251 *wl, int addr) | ||
38 | { | ||
39 | u32 response; | ||
40 | |||
41 | wl->if_ops->read(wl, addr, &response, sizeof(u32)); | ||
42 | |||
43 | return response; | ||
44 | } | ||
45 | |||
46 | static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) | ||
47 | { | ||
48 | wl->if_ops->write(wl, addr, &val, sizeof(u32)); | ||
49 | } | ||
50 | |||
51 | /* Memory target IO, address is translated to partition 0 */ | ||
52 | void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
53 | void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
54 | u32 wl1251_mem_read32(struct wl1251 *wl, int addr); | ||
55 | void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); | ||
56 | /* Registers IO */ | ||
57 | u32 wl1251_reg_read32(struct wl1251 *wl, int addr); | ||
58 | void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); | ||
59 | |||
60 | void wl1251_set_partition(struct wl1251 *wl, | ||
61 | u32 part_start, u32 part_size, | ||
62 | u32 reg_start, u32 reg_size); | ||
63 | |||
64 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index da4c688c46af..7148934e464d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c | |||
@@ -26,26 +26,30 @@ | |||
26 | #include <linux/firmware.h> | 26 | #include <linux/firmware.h> |
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | #include <linux/irq.h> | 28 | #include <linux/irq.h> |
29 | #include <linux/spi/spi.h> | ||
30 | #include <linux/crc32.h> | 29 | #include <linux/crc32.h> |
31 | #include <linux/etherdevice.h> | 30 | #include <linux/etherdevice.h> |
32 | #include <linux/spi/wl12xx.h> | ||
33 | 31 | ||
34 | #include "wl1251.h" | 32 | #include "wl1251.h" |
35 | #include "wl12xx_80211.h" | 33 | #include "wl12xx_80211.h" |
36 | #include "reg.h" | 34 | #include "wl1251_reg.h" |
37 | #include "wl1251_ops.h" | 35 | #include "wl1251_io.h" |
38 | #include "wl1251_spi.h" | 36 | #include "wl1251_cmd.h" |
39 | #include "wl1251_event.h" | 37 | #include "wl1251_event.h" |
40 | #include "wl1251_tx.h" | 38 | #include "wl1251_tx.h" |
41 | #include "wl1251_rx.h" | 39 | #include "wl1251_rx.h" |
42 | #include "wl1251_ps.h" | 40 | #include "wl1251_ps.h" |
43 | #include "wl1251_init.h" | 41 | #include "wl1251_init.h" |
44 | #include "wl1251_debugfs.h" | 42 | #include "wl1251_debugfs.h" |
43 | #include "wl1251_boot.h" | ||
45 | 44 | ||
46 | static void wl1251_disable_interrupts(struct wl1251 *wl) | 45 | void wl1251_enable_interrupts(struct wl1251 *wl) |
47 | { | 46 | { |
48 | disable_irq(wl->irq); | 47 | wl->if_ops->enable_irq(wl); |
48 | } | ||
49 | |||
50 | void wl1251_disable_interrupts(struct wl1251 *wl) | ||
51 | { | ||
52 | wl->if_ops->disable_irq(wl); | ||
49 | } | 53 | } |
50 | 54 | ||
51 | static void wl1251_power_off(struct wl1251 *wl) | 55 | static void wl1251_power_off(struct wl1251 *wl) |
@@ -58,25 +62,13 @@ static void wl1251_power_on(struct wl1251 *wl) | |||
58 | wl->set_power(true); | 62 | wl->set_power(true); |
59 | } | 63 | } |
60 | 64 | ||
61 | static irqreturn_t wl1251_irq(int irq, void *cookie) | ||
62 | { | ||
63 | struct wl1251 *wl; | ||
64 | |||
65 | wl1251_debug(DEBUG_IRQ, "IRQ"); | ||
66 | |||
67 | wl = cookie; | ||
68 | |||
69 | schedule_work(&wl->irq_work); | ||
70 | |||
71 | return IRQ_HANDLED; | ||
72 | } | ||
73 | |||
74 | static int wl1251_fetch_firmware(struct wl1251 *wl) | 65 | static int wl1251_fetch_firmware(struct wl1251 *wl) |
75 | { | 66 | { |
76 | const struct firmware *fw; | 67 | const struct firmware *fw; |
68 | struct device *dev = wiphy_dev(wl->hw->wiphy); | ||
77 | int ret; | 69 | int ret; |
78 | 70 | ||
79 | ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); | 71 | ret = request_firmware(&fw, WL1251_FW_NAME, dev); |
80 | 72 | ||
81 | if (ret < 0) { | 73 | if (ret < 0) { |
82 | wl1251_error("could not get firmware: %d", ret); | 74 | wl1251_error("could not get firmware: %d", ret); |
@@ -112,9 +104,10 @@ out: | |||
112 | static int wl1251_fetch_nvs(struct wl1251 *wl) | 104 | static int wl1251_fetch_nvs(struct wl1251 *wl) |
113 | { | 105 | { |
114 | const struct firmware *fw; | 106 | const struct firmware *fw; |
107 | struct device *dev = wiphy_dev(wl->hw->wiphy); | ||
115 | int ret; | 108 | int ret; |
116 | 109 | ||
117 | ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); | 110 | ret = request_firmware(&fw, WL1251_NVS_NAME, dev); |
118 | 111 | ||
119 | if (ret < 0) { | 112 | if (ret < 0) { |
120 | wl1251_error("could not get nvs file: %d", ret); | 113 | wl1251_error("could not get nvs file: %d", ret); |
@@ -164,9 +157,8 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) | |||
164 | int ret = 0; | 157 | int ret = 0; |
165 | 158 | ||
166 | wl1251_power_on(wl); | 159 | wl1251_power_on(wl); |
167 | msleep(wl->chip.power_on_sleep); | 160 | msleep(WL1251_POWER_ON_SLEEP); |
168 | wl1251_spi_reset(wl); | 161 | wl->if_ops->reset(wl); |
169 | wl1251_spi_init(wl); | ||
170 | 162 | ||
171 | /* We don't need a real memory partition here, because we only want | 163 | /* We don't need a real memory partition here, because we only want |
172 | * to use the registers at this point. */ | 164 | * to use the registers at this point. */ |
@@ -182,22 +174,19 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) | |||
182 | /* whal_FwCtrl_BootSm() */ | 174 | /* whal_FwCtrl_BootSm() */ |
183 | 175 | ||
184 | /* 0. read chip id from CHIP_ID */ | 176 | /* 0. read chip id from CHIP_ID */ |
185 | wl->chip.id = wl1251_reg_read32(wl, CHIP_ID_B); | 177 | wl->chip_id = wl1251_reg_read32(wl, CHIP_ID_B); |
186 | 178 | ||
187 | /* 1. check if chip id is valid */ | 179 | /* 1. check if chip id is valid */ |
188 | 180 | ||
189 | switch (wl->chip.id) { | 181 | switch (wl->chip_id) { |
190 | case CHIP_ID_1251_PG12: | 182 | case CHIP_ID_1251_PG12: |
191 | wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", | 183 | wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", |
192 | wl->chip.id); | 184 | wl->chip_id); |
193 | |||
194 | wl1251_setup(wl); | ||
195 | |||
196 | break; | 185 | break; |
197 | case CHIP_ID_1251_PG10: | 186 | case CHIP_ID_1251_PG10: |
198 | case CHIP_ID_1251_PG11: | 187 | case CHIP_ID_1251_PG11: |
199 | default: | 188 | default: |
200 | wl1251_error("unsupported chip id: 0x%x", wl->chip.id); | 189 | wl1251_error("unsupported chip id: 0x%x", wl->chip_id); |
201 | ret = -ENODEV; | 190 | ret = -ENODEV; |
202 | goto out; | 191 | goto out; |
203 | } | 192 | } |
@@ -219,6 +208,135 @@ out: | |||
219 | return ret; | 208 | return ret; |
220 | } | 209 | } |
221 | 210 | ||
211 | static void wl1251_irq_work(struct work_struct *work) | ||
212 | { | ||
213 | u32 intr; | ||
214 | struct wl1251 *wl = | ||
215 | container_of(work, struct wl1251, irq_work); | ||
216 | int ret; | ||
217 | |||
218 | mutex_lock(&wl->mutex); | ||
219 | |||
220 | wl1251_debug(DEBUG_IRQ, "IRQ work"); | ||
221 | |||
222 | if (wl->state == WL1251_STATE_OFF) | ||
223 | goto out; | ||
224 | |||
225 | ret = wl1251_ps_elp_wakeup(wl); | ||
226 | if (ret < 0) | ||
227 | goto out; | ||
228 | |||
229 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); | ||
230 | |||
231 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
232 | wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); | ||
233 | |||
234 | if (wl->data_path) { | ||
235 | wl->rx_counter = | ||
236 | wl1251_mem_read32(wl, wl->data_path->rx_control_addr); | ||
237 | |||
238 | /* We handle a frmware bug here */ | ||
239 | switch ((wl->rx_counter - wl->rx_handled) & 0xf) { | ||
240 | case 0: | ||
241 | wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); | ||
242 | intr &= ~WL1251_ACX_INTR_RX0_DATA; | ||
243 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
244 | break; | ||
245 | case 1: | ||
246 | wl1251_debug(DEBUG_IRQ, "RX: FW +1"); | ||
247 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
248 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
249 | break; | ||
250 | case 2: | ||
251 | wl1251_debug(DEBUG_IRQ, "RX: FW +2"); | ||
252 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
253 | intr |= WL1251_ACX_INTR_RX1_DATA; | ||
254 | break; | ||
255 | default: | ||
256 | wl1251_warning("RX: FW and host out of sync: %d", | ||
257 | wl->rx_counter - wl->rx_handled); | ||
258 | break; | ||
259 | } | ||
260 | |||
261 | wl->rx_handled = wl->rx_counter; | ||
262 | |||
263 | |||
264 | wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); | ||
265 | } | ||
266 | |||
267 | intr &= wl->intr_mask; | ||
268 | |||
269 | if (intr == 0) { | ||
270 | wl1251_debug(DEBUG_IRQ, "INTR is 0"); | ||
271 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
272 | ~(wl->intr_mask)); | ||
273 | |||
274 | goto out_sleep; | ||
275 | } | ||
276 | |||
277 | if (intr & WL1251_ACX_INTR_RX0_DATA) { | ||
278 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); | ||
279 | wl1251_rx(wl); | ||
280 | } | ||
281 | |||
282 | if (intr & WL1251_ACX_INTR_RX1_DATA) { | ||
283 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); | ||
284 | wl1251_rx(wl); | ||
285 | } | ||
286 | |||
287 | if (intr & WL1251_ACX_INTR_TX_RESULT) { | ||
288 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); | ||
289 | wl1251_tx_complete(wl); | ||
290 | } | ||
291 | |||
292 | if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { | ||
293 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); | ||
294 | if (intr & WL1251_ACX_INTR_EVENT_A) | ||
295 | wl1251_event_handle(wl, 0); | ||
296 | else | ||
297 | wl1251_event_handle(wl, 1); | ||
298 | } | ||
299 | |||
300 | if (intr & WL1251_ACX_INTR_INIT_COMPLETE) | ||
301 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); | ||
302 | |||
303 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | ||
304 | |||
305 | out_sleep: | ||
306 | wl1251_ps_elp_sleep(wl); | ||
307 | |||
308 | out: | ||
309 | mutex_unlock(&wl->mutex); | ||
310 | } | ||
311 | |||
312 | static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel, | ||
313 | u16 beacon_interval, u8 dtim_period) | ||
314 | { | ||
315 | int ret; | ||
316 | |||
317 | ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, | ||
318 | DEFAULT_HW_GEN_MODULATION_TYPE, | ||
319 | wl->tx_mgmt_frm_rate, | ||
320 | wl->tx_mgmt_frm_mod); | ||
321 | if (ret < 0) | ||
322 | goto out; | ||
323 | |||
324 | |||
325 | ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval, | ||
326 | dtim_period); | ||
327 | if (ret < 0) | ||
328 | goto out; | ||
329 | |||
330 | /* | ||
331 | * FIXME: we should wait for JOIN_EVENT_COMPLETE_ID but to simplify | ||
332 | * locking we just sleep instead, for now | ||
333 | */ | ||
334 | msleep(10); | ||
335 | |||
336 | out: | ||
337 | return ret; | ||
338 | } | ||
339 | |||
222 | static void wl1251_filter_work(struct work_struct *work) | 340 | static void wl1251_filter_work(struct work_struct *work) |
223 | { | 341 | { |
224 | struct wl1251 *wl = | 342 | struct wl1251 *wl = |
@@ -234,8 +352,8 @@ static void wl1251_filter_work(struct work_struct *work) | |||
234 | if (ret < 0) | 352 | if (ret < 0) |
235 | goto out; | 353 | goto out; |
236 | 354 | ||
237 | /* FIXME: replace the magic numbers with proper definitions */ | 355 | ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, |
238 | ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); | 356 | wl->dtim_period); |
239 | if (ret < 0) | 357 | if (ret < 0) |
240 | goto out_sleep; | 358 | goto out_sleep; |
241 | 359 | ||
@@ -257,7 +375,7 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
257 | * before that, the tx_work will not be initialized! | 375 | * before that, the tx_work will not be initialized! |
258 | */ | 376 | */ |
259 | 377 | ||
260 | schedule_work(&wl->tx_work); | 378 | ieee80211_queue_work(wl->hw, &wl->tx_work); |
261 | 379 | ||
262 | /* | 380 | /* |
263 | * The workqueue is slow to process the tx_queue and we need stop | 381 | * The workqueue is slow to process the tx_queue and we need stop |
@@ -297,11 +415,11 @@ static int wl1251_op_start(struct ieee80211_hw *hw) | |||
297 | if (ret < 0) | 415 | if (ret < 0) |
298 | goto out; | 416 | goto out; |
299 | 417 | ||
300 | ret = wl->chip.op_boot(wl); | 418 | ret = wl1251_boot(wl); |
301 | if (ret < 0) | 419 | if (ret < 0) |
302 | goto out; | 420 | goto out; |
303 | 421 | ||
304 | ret = wl->chip.op_hw_init(wl); | 422 | ret = wl1251_hw_init(wl); |
305 | if (ret < 0) | 423 | if (ret < 0) |
306 | goto out; | 424 | goto out; |
307 | 425 | ||
@@ -311,7 +429,7 @@ static int wl1251_op_start(struct ieee80211_hw *hw) | |||
311 | 429 | ||
312 | wl->state = WL1251_STATE_ON; | 430 | wl->state = WL1251_STATE_ON; |
313 | 431 | ||
314 | wl1251_info("firmware booted (%s)", wl->chip.fw_ver); | 432 | wl1251_info("firmware booted (%s)", wl->fw_ver); |
315 | 433 | ||
316 | out: | 434 | out: |
317 | if (ret < 0) | 435 | if (ret < 0) |
@@ -354,7 +472,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) | |||
354 | mutex_lock(&wl->mutex); | 472 | mutex_lock(&wl->mutex); |
355 | 473 | ||
356 | /* let's notify MAC80211 about the remaining pending TX frames */ | 474 | /* let's notify MAC80211 about the remaining pending TX frames */ |
357 | wl->chip.op_tx_flush(wl); | 475 | wl1251_tx_flush(wl); |
358 | wl1251_power_off(wl); | 476 | wl1251_power_off(wl); |
359 | 477 | ||
360 | memset(wl->bssid, 0, ETH_ALEN); | 478 | memset(wl->bssid, 0, ETH_ALEN); |
@@ -371,6 +489,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) | |||
371 | wl->psm = 0; | 489 | wl->psm = 0; |
372 | wl->tx_queue_stopped = false; | 490 | wl->tx_queue_stopped = false; |
373 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; | 491 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; |
492 | wl->channel = WL1251_DEFAULT_CHANNEL; | ||
374 | 493 | ||
375 | wl1251_debugfs_reset(wl); | 494 | wl1251_debugfs_reset(wl); |
376 | 495 | ||
@@ -474,12 +593,12 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) | |||
474 | goto out; | 593 | goto out; |
475 | 594 | ||
476 | if (channel != wl->channel) { | 595 | if (channel != wl->channel) { |
477 | /* FIXME: use beacon interval provided by mac80211 */ | 596 | wl->channel = channel; |
478 | ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); | 597 | |
598 | ret = wl1251_join(wl, wl->bss_type, wl->channel, | ||
599 | wl->beacon_int, wl->dtim_period); | ||
479 | if (ret < 0) | 600 | if (ret < 0) |
480 | goto out_sleep; | 601 | goto out_sleep; |
481 | |||
482 | wl->channel = channel; | ||
483 | } | 602 | } |
484 | 603 | ||
485 | ret = wl1251_build_null_data(wl); | 604 | ret = wl1251_build_null_data(wl); |
@@ -877,7 +996,7 @@ static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len, | |||
877 | if (ret < 0) | 996 | if (ret < 0) |
878 | wl1251_error("SCAN failed"); | 997 | wl1251_error("SCAN failed"); |
879 | 998 | ||
880 | wl1251_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); | 999 | wl1251_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); |
881 | 1000 | ||
882 | if (params->header.status != CMD_STATUS_SUCCESS) { | 1001 | if (params->header.status != CMD_STATUS_SUCCESS) { |
883 | wl1251_error("TEST command answer error: %d", | 1002 | wl1251_error("TEST command answer error: %d", |
@@ -967,6 +1086,11 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
967 | 1086 | ||
968 | if (changed & BSS_CHANGED_ASSOC) { | 1087 | if (changed & BSS_CHANGED_ASSOC) { |
969 | if (bss_conf->assoc) { | 1088 | if (bss_conf->assoc) { |
1089 | wl->beacon_int = bss_conf->beacon_int; | ||
1090 | wl->dtim_period = bss_conf->dtim_period; | ||
1091 | |||
1092 | /* FIXME: call join */ | ||
1093 | |||
970 | wl->aid = bss_conf->aid; | 1094 | wl->aid = bss_conf->aid; |
971 | 1095 | ||
972 | ret = wl1251_build_ps_poll(wl, wl->aid); | 1096 | ret = wl1251_build_ps_poll(wl, wl->aid); |
@@ -984,6 +1108,10 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
984 | if (ret < 0) | 1108 | if (ret < 0) |
985 | goto out_sleep; | 1109 | goto out_sleep; |
986 | } | 1110 | } |
1111 | } else { | ||
1112 | /* use defaults when not associated */ | ||
1113 | wl->beacon_int = WL1251_DEFAULT_BEACON_INT; | ||
1114 | wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; | ||
987 | } | 1115 | } |
988 | } | 1116 | } |
989 | if (changed & BSS_CHANGED_ERP_SLOT) { | 1117 | if (changed & BSS_CHANGED_ERP_SLOT) { |
@@ -1023,7 +1151,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1023 | goto out; | 1151 | goto out; |
1024 | 1152 | ||
1025 | if (wl->bss_type != BSS_TYPE_IBSS) { | 1153 | if (wl->bss_type != BSS_TYPE_IBSS) { |
1026 | ret = wl1251_cmd_join(wl, wl->bss_type, 5, 100, 1); | 1154 | ret = wl1251_join(wl, wl->bss_type, wl->channel, |
1155 | wl->beacon_int, wl->dtim_period); | ||
1027 | if (ret < 0) | 1156 | if (ret < 0) |
1028 | goto out_sleep; | 1157 | goto out_sleep; |
1029 | wl1251_warning("Set ctsprotect failed %d", ret); | 1158 | wl1251_warning("Set ctsprotect failed %d", ret); |
@@ -1049,7 +1178,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1049 | if (ret < 0) | 1178 | if (ret < 0) |
1050 | goto out; | 1179 | goto out; |
1051 | 1180 | ||
1052 | ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); | 1181 | ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, |
1182 | wl->channel, wl->dtim_period); | ||
1053 | 1183 | ||
1054 | if (ret < 0) | 1184 | if (ret < 0) |
1055 | goto out; | 1185 | goto out; |
@@ -1167,8 +1297,10 @@ static int wl1251_register_hw(struct wl1251 *wl) | |||
1167 | return 0; | 1297 | return 0; |
1168 | } | 1298 | } |
1169 | 1299 | ||
1170 | static int wl1251_init_ieee80211(struct wl1251 *wl) | 1300 | int wl1251_init_ieee80211(struct wl1251 *wl) |
1171 | { | 1301 | { |
1302 | int ret; | ||
1303 | |||
1172 | /* The tx descriptor buffer and the TKIP space */ | 1304 | /* The tx descriptor buffer and the TKIP space */ |
1173 | wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) | 1305 | wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) |
1174 | + WL1251_TKIP_IV_SPACE; | 1306 | + WL1251_TKIP_IV_SPACE; |
@@ -1184,38 +1316,37 @@ static int wl1251_init_ieee80211(struct wl1251 *wl) | |||
1184 | wl->hw->wiphy->max_scan_ssids = 1; | 1316 | wl->hw->wiphy->max_scan_ssids = 1; |
1185 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; | 1317 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; |
1186 | 1318 | ||
1187 | SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); | 1319 | ret = wl1251_register_hw(wl); |
1320 | if (ret) | ||
1321 | goto out; | ||
1188 | 1322 | ||
1189 | return 0; | 1323 | wl1251_debugfs_init(wl); |
1324 | wl1251_notice("initialized"); | ||
1325 | |||
1326 | ret = 0; | ||
1327 | |||
1328 | out: | ||
1329 | return ret; | ||
1190 | } | 1330 | } |
1331 | EXPORT_SYMBOL_GPL(wl1251_init_ieee80211); | ||
1191 | 1332 | ||
1192 | #define WL1251_DEFAULT_CHANNEL 1 | 1333 | struct ieee80211_hw *wl1251_alloc_hw(void) |
1193 | static int __devinit wl1251_probe(struct spi_device *spi) | ||
1194 | { | 1334 | { |
1195 | struct wl12xx_platform_data *pdata; | ||
1196 | struct ieee80211_hw *hw; | 1335 | struct ieee80211_hw *hw; |
1197 | struct wl1251 *wl; | 1336 | struct wl1251 *wl; |
1198 | int ret, i; | 1337 | int i; |
1199 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | 1338 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; |
1200 | 1339 | ||
1201 | pdata = spi->dev.platform_data; | ||
1202 | if (!pdata) { | ||
1203 | wl1251_error("no platform data"); | ||
1204 | return -ENODEV; | ||
1205 | } | ||
1206 | |||
1207 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); | 1340 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); |
1208 | if (!hw) { | 1341 | if (!hw) { |
1209 | wl1251_error("could not alloc ieee80211_hw"); | 1342 | wl1251_error("could not alloc ieee80211_hw"); |
1210 | return -ENOMEM; | 1343 | return ERR_PTR(-ENOMEM); |
1211 | } | 1344 | } |
1212 | 1345 | ||
1213 | wl = hw->priv; | 1346 | wl = hw->priv; |
1214 | memset(wl, 0, sizeof(*wl)); | 1347 | memset(wl, 0, sizeof(*wl)); |
1215 | 1348 | ||
1216 | wl->hw = hw; | 1349 | wl->hw = hw; |
1217 | dev_set_drvdata(&spi->dev, wl); | ||
1218 | wl->spi = spi; | ||
1219 | 1350 | ||
1220 | wl->data_in_count = 0; | 1351 | wl->data_in_count = 0; |
1221 | 1352 | ||
@@ -1237,16 +1368,17 @@ static int __devinit wl1251_probe(struct spi_device *spi) | |||
1237 | wl->psm_requested = false; | 1368 | wl->psm_requested = false; |
1238 | wl->tx_queue_stopped = false; | 1369 | wl->tx_queue_stopped = false; |
1239 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; | 1370 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; |
1240 | 1371 | wl->beacon_int = WL1251_DEFAULT_BEACON_INT; | |
1241 | /* We use the default power on sleep time until we know which chip | 1372 | wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; |
1242 | * we're using */ | ||
1243 | wl->chip.power_on_sleep = WL1251_DEFAULT_POWER_ON_SLEEP; | ||
1244 | 1373 | ||
1245 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | 1374 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) |
1246 | wl->tx_frames[i] = NULL; | 1375 | wl->tx_frames[i] = NULL; |
1247 | 1376 | ||
1248 | wl->next_tx_complete = 0; | 1377 | wl->next_tx_complete = 0; |
1249 | 1378 | ||
1379 | INIT_WORK(&wl->irq_work, wl1251_irq_work); | ||
1380 | INIT_WORK(&wl->tx_work, wl1251_tx_work); | ||
1381 | |||
1250 | /* | 1382 | /* |
1251 | * In case our MAC address is not correctly set, | 1383 | * In case our MAC address is not correctly set, |
1252 | * we use a random but Nokia MAC. | 1384 | * we use a random but Nokia MAC. |
@@ -1263,79 +1395,20 @@ static int __devinit wl1251_probe(struct spi_device *spi) | |||
1263 | wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); | 1395 | wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); |
1264 | if (!wl->rx_descriptor) { | 1396 | if (!wl->rx_descriptor) { |
1265 | wl1251_error("could not allocate memory for rx descriptor"); | 1397 | wl1251_error("could not allocate memory for rx descriptor"); |
1266 | ret = -ENOMEM; | 1398 | ieee80211_free_hw(hw); |
1267 | goto out_free; | 1399 | return ERR_PTR(-ENOMEM); |
1268 | } | ||
1269 | |||
1270 | /* This is the only SPI value that we need to set here, the rest | ||
1271 | * comes from the board-peripherals file */ | ||
1272 | spi->bits_per_word = 32; | ||
1273 | |||
1274 | ret = spi_setup(spi); | ||
1275 | if (ret < 0) { | ||
1276 | wl1251_error("spi_setup failed"); | ||
1277 | goto out_free; | ||
1278 | } | 1400 | } |
1279 | 1401 | ||
1280 | wl->set_power = pdata->set_power; | 1402 | return hw; |
1281 | if (!wl->set_power) { | ||
1282 | wl1251_error("set power function missing in platform data"); | ||
1283 | ret = -ENODEV; | ||
1284 | goto out_free; | ||
1285 | } | ||
1286 | |||
1287 | wl->irq = spi->irq; | ||
1288 | if (wl->irq < 0) { | ||
1289 | wl1251_error("irq missing in platform data"); | ||
1290 | ret = -ENODEV; | ||
1291 | goto out_free; | ||
1292 | } | ||
1293 | |||
1294 | ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); | ||
1295 | if (ret < 0) { | ||
1296 | wl1251_error("request_irq() failed: %d", ret); | ||
1297 | goto out_free; | ||
1298 | } | ||
1299 | |||
1300 | set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | ||
1301 | |||
1302 | disable_irq(wl->irq); | ||
1303 | |||
1304 | ret = wl1251_init_ieee80211(wl); | ||
1305 | if (ret) | ||
1306 | goto out_irq; | ||
1307 | |||
1308 | ret = wl1251_register_hw(wl); | ||
1309 | if (ret) | ||
1310 | goto out_irq; | ||
1311 | |||
1312 | wl1251_debugfs_init(wl); | ||
1313 | |||
1314 | wl1251_notice("initialized"); | ||
1315 | |||
1316 | return 0; | ||
1317 | |||
1318 | out_irq: | ||
1319 | free_irq(wl->irq, wl); | ||
1320 | |||
1321 | out_free: | ||
1322 | kfree(wl->rx_descriptor); | ||
1323 | wl->rx_descriptor = NULL; | ||
1324 | |||
1325 | ieee80211_free_hw(hw); | ||
1326 | |||
1327 | return ret; | ||
1328 | } | 1403 | } |
1404 | EXPORT_SYMBOL_GPL(wl1251_alloc_hw); | ||
1329 | 1405 | ||
1330 | static int __devexit wl1251_remove(struct spi_device *spi) | 1406 | int wl1251_free_hw(struct wl1251 *wl) |
1331 | { | 1407 | { |
1332 | struct wl1251 *wl = dev_get_drvdata(&spi->dev); | ||
1333 | |||
1334 | ieee80211_unregister_hw(wl->hw); | 1408 | ieee80211_unregister_hw(wl->hw); |
1335 | 1409 | ||
1336 | wl1251_debugfs_exit(wl); | 1410 | wl1251_debugfs_exit(wl); |
1337 | 1411 | ||
1338 | free_irq(wl->irq, wl); | ||
1339 | kfree(wl->target_mem_map); | 1412 | kfree(wl->target_mem_map); |
1340 | kfree(wl->data_path); | 1413 | kfree(wl->data_path); |
1341 | kfree(wl->fw); | 1414 | kfree(wl->fw); |
@@ -1350,44 +1423,8 @@ static int __devexit wl1251_remove(struct spi_device *spi) | |||
1350 | 1423 | ||
1351 | return 0; | 1424 | return 0; |
1352 | } | 1425 | } |
1426 | EXPORT_SYMBOL_GPL(wl1251_free_hw); | ||
1353 | 1427 | ||
1354 | 1428 | MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); | |
1355 | static struct spi_driver wl1251_spi_driver = { | ||
1356 | .driver = { | ||
1357 | /* FIXME: use wl12xx name to not break the user space */ | ||
1358 | .name = "wl12xx", | ||
1359 | .bus = &spi_bus_type, | ||
1360 | .owner = THIS_MODULE, | ||
1361 | }, | ||
1362 | |||
1363 | .probe = wl1251_probe, | ||
1364 | .remove = __devexit_p(wl1251_remove), | ||
1365 | }; | ||
1366 | |||
1367 | static int __init wl1251_init(void) | ||
1368 | { | ||
1369 | int ret; | ||
1370 | |||
1371 | ret = spi_register_driver(&wl1251_spi_driver); | ||
1372 | if (ret < 0) { | ||
1373 | wl1251_error("failed to register spi driver: %d", ret); | ||
1374 | goto out; | ||
1375 | } | ||
1376 | |||
1377 | out: | ||
1378 | return ret; | ||
1379 | } | ||
1380 | |||
1381 | static void __exit wl1251_exit(void) | ||
1382 | { | ||
1383 | spi_unregister_driver(&wl1251_spi_driver); | ||
1384 | |||
1385 | wl1251_notice("unloaded"); | ||
1386 | } | ||
1387 | |||
1388 | module_init(wl1251_init); | ||
1389 | module_exit(wl1251_exit); | ||
1390 | |||
1391 | MODULE_LICENSE("GPL"); | 1429 | MODULE_LICENSE("GPL"); |
1392 | MODULE_AUTHOR("Kalle Valo <Kalle.Valo@nokia.com>, " | 1430 | MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>"); |
1393 | "Luciano Coelho <luciano.coelho@nokia.com>"); | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c deleted file mode 100644 index e7b9aab3682f..000000000000 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ /dev/null | |||
@@ -1,728 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | |||
27 | #include "wl1251_ops.h" | ||
28 | #include "reg.h" | ||
29 | #include "wl1251_spi.h" | ||
30 | #include "wl1251_boot.h" | ||
31 | #include "wl1251_event.h" | ||
32 | #include "wl1251_acx.h" | ||
33 | #include "wl1251_tx.h" | ||
34 | #include "wl1251_rx.h" | ||
35 | #include "wl1251_ps.h" | ||
36 | #include "wl1251_init.h" | ||
37 | |||
38 | static struct wl1251_partition_set wl1251_part_table[PART_TABLE_LEN] = { | ||
39 | [PART_DOWN] = { | ||
40 | .mem = { | ||
41 | .start = 0x00000000, | ||
42 | .size = 0x00016800 | ||
43 | }, | ||
44 | .reg = { | ||
45 | .start = REGISTERS_BASE, | ||
46 | .size = REGISTERS_DOWN_SIZE | ||
47 | }, | ||
48 | }, | ||
49 | |||
50 | [PART_WORK] = { | ||
51 | .mem = { | ||
52 | .start = 0x00028000, | ||
53 | .size = 0x00014000 | ||
54 | }, | ||
55 | .reg = { | ||
56 | .start = REGISTERS_BASE, | ||
57 | .size = REGISTERS_WORK_SIZE | ||
58 | }, | ||
59 | }, | ||
60 | |||
61 | /* WL1251 doesn't use the DRPW partition, so we don't set it here */ | ||
62 | }; | ||
63 | |||
64 | static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { | ||
65 | [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), | ||
66 | [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), | ||
67 | [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), | ||
68 | [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), | ||
69 | [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), | ||
70 | [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), | ||
71 | [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), | ||
72 | [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), | ||
73 | [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), | ||
74 | [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), | ||
75 | [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) | ||
76 | }; | ||
77 | |||
78 | static int wl1251_upload_firmware(struct wl1251 *wl) | ||
79 | { | ||
80 | struct wl1251_partition_set *p_table = wl->chip.p_table; | ||
81 | int addr, chunk_num, partition_limit; | ||
82 | size_t fw_data_len; | ||
83 | u8 *p; | ||
84 | |||
85 | /* whal_FwCtrl_LoadFwImageSm() */ | ||
86 | |||
87 | wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", | ||
88 | wl1251_reg_read32(wl, CHIP_ID_B)); | ||
89 | |||
90 | /* 10.0 check firmware length and set partition */ | ||
91 | fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | | ||
92 | (wl->fw[6] << 8) | (wl->fw[7]); | ||
93 | |||
94 | wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, | ||
95 | CHUNK_SIZE); | ||
96 | |||
97 | if ((fw_data_len % 4) != 0) { | ||
98 | wl1251_error("firmware length not multiple of four"); | ||
99 | return -EIO; | ||
100 | } | ||
101 | |||
102 | wl1251_set_partition(wl, | ||
103 | p_table[PART_DOWN].mem.start, | ||
104 | p_table[PART_DOWN].mem.size, | ||
105 | p_table[PART_DOWN].reg.start, | ||
106 | p_table[PART_DOWN].reg.size); | ||
107 | |||
108 | /* 10.1 set partition limit and chunk num */ | ||
109 | chunk_num = 0; | ||
110 | partition_limit = p_table[PART_DOWN].mem.size; | ||
111 | |||
112 | while (chunk_num < fw_data_len / CHUNK_SIZE) { | ||
113 | /* 10.2 update partition, if needed */ | ||
114 | addr = p_table[PART_DOWN].mem.start + | ||
115 | (chunk_num + 2) * CHUNK_SIZE; | ||
116 | if (addr > partition_limit) { | ||
117 | addr = p_table[PART_DOWN].mem.start + | ||
118 | chunk_num * CHUNK_SIZE; | ||
119 | partition_limit = chunk_num * CHUNK_SIZE + | ||
120 | p_table[PART_DOWN].mem.size; | ||
121 | wl1251_set_partition(wl, | ||
122 | addr, | ||
123 | p_table[PART_DOWN].mem.size, | ||
124 | p_table[PART_DOWN].reg.start, | ||
125 | p_table[PART_DOWN].reg.size); | ||
126 | } | ||
127 | |||
128 | /* 10.3 upload the chunk */ | ||
129 | addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; | ||
130 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
131 | wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", | ||
132 | p, addr); | ||
133 | wl1251_spi_mem_write(wl, addr, p, CHUNK_SIZE); | ||
134 | |||
135 | chunk_num++; | ||
136 | } | ||
137 | |||
138 | /* 10.4 upload the last chunk */ | ||
139 | addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; | ||
140 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
141 | wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", | ||
142 | fw_data_len % CHUNK_SIZE, p, addr); | ||
143 | wl1251_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int wl1251_upload_nvs(struct wl1251 *wl) | ||
149 | { | ||
150 | size_t nvs_len, nvs_bytes_written, burst_len; | ||
151 | int nvs_start, i; | ||
152 | u32 dest_addr, val; | ||
153 | u8 *nvs_ptr, *nvs; | ||
154 | |||
155 | nvs = wl->nvs; | ||
156 | if (nvs == NULL) | ||
157 | return -ENODEV; | ||
158 | |||
159 | nvs_ptr = nvs; | ||
160 | |||
161 | nvs_len = wl->nvs_len; | ||
162 | nvs_start = wl->fw_len; | ||
163 | |||
164 | /* | ||
165 | * Layout before the actual NVS tables: | ||
166 | * 1 byte : burst length. | ||
167 | * 2 bytes: destination address. | ||
168 | * n bytes: data to burst copy. | ||
169 | * | ||
170 | * This is ended by a 0 length, then the NVS tables. | ||
171 | */ | ||
172 | |||
173 | while (nvs_ptr[0]) { | ||
174 | burst_len = nvs_ptr[0]; | ||
175 | dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); | ||
176 | |||
177 | /* We move our pointer to the data */ | ||
178 | nvs_ptr += 3; | ||
179 | |||
180 | for (i = 0; i < burst_len; i++) { | ||
181 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
182 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
183 | |||
184 | wl1251_debug(DEBUG_BOOT, | ||
185 | "nvs burst write 0x%x: 0x%x", | ||
186 | dest_addr, val); | ||
187 | wl1251_mem_write32(wl, dest_addr, val); | ||
188 | |||
189 | nvs_ptr += 4; | ||
190 | dest_addr += 4; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * We've reached the first zero length, the first NVS table | ||
196 | * is 7 bytes further. | ||
197 | */ | ||
198 | nvs_ptr += 7; | ||
199 | nvs_len -= nvs_ptr - nvs; | ||
200 | nvs_len = ALIGN(nvs_len, 4); | ||
201 | |||
202 | /* Now we must set the partition correctly */ | ||
203 | wl1251_set_partition(wl, nvs_start, | ||
204 | wl->chip.p_table[PART_DOWN].mem.size, | ||
205 | wl->chip.p_table[PART_DOWN].reg.start, | ||
206 | wl->chip.p_table[PART_DOWN].reg.size); | ||
207 | |||
208 | /* And finally we upload the NVS tables */ | ||
209 | nvs_bytes_written = 0; | ||
210 | while (nvs_bytes_written < nvs_len) { | ||
211 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
212 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
213 | |||
214 | val = cpu_to_le32(val); | ||
215 | |||
216 | wl1251_debug(DEBUG_BOOT, | ||
217 | "nvs write table 0x%x: 0x%x", | ||
218 | nvs_start, val); | ||
219 | wl1251_mem_write32(wl, nvs_start, val); | ||
220 | |||
221 | nvs_ptr += 4; | ||
222 | nvs_bytes_written += 4; | ||
223 | nvs_start += 4; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int wl1251_boot(struct wl1251 *wl) | ||
230 | { | ||
231 | int ret = 0, minor_minor_e2_ver; | ||
232 | u32 tmp, boot_data; | ||
233 | |||
234 | ret = wl1251_boot_soft_reset(wl); | ||
235 | if (ret < 0) | ||
236 | goto out; | ||
237 | |||
238 | /* 2. start processing NVS file */ | ||
239 | ret = wl->chip.op_upload_nvs(wl); | ||
240 | if (ret < 0) | ||
241 | goto out; | ||
242 | |||
243 | /* write firmware's last address (ie. it's length) to | ||
244 | * ACX_EEPROMLESS_IND_REG */ | ||
245 | wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); | ||
246 | |||
247 | /* 6. read the EEPROM parameters */ | ||
248 | tmp = wl1251_reg_read32(wl, SCR_PAD2); | ||
249 | |||
250 | /* 7. read bootdata */ | ||
251 | wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; | ||
252 | wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; | ||
253 | tmp = wl1251_reg_read32(wl, SCR_PAD3); | ||
254 | |||
255 | /* 8. check bootdata and call restart sequence */ | ||
256 | wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; | ||
257 | minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; | ||
258 | |||
259 | wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " | ||
260 | "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", | ||
261 | wl->boot_attr.radio_type, wl->boot_attr.major, | ||
262 | wl->boot_attr.minor, minor_minor_e2_ver); | ||
263 | |||
264 | ret = wl1251_boot_init_seq(wl); | ||
265 | if (ret < 0) | ||
266 | goto out; | ||
267 | |||
268 | /* 9. NVS processing done */ | ||
269 | boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
270 | |||
271 | wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); | ||
272 | |||
273 | /* 10. check that ECPU_CONTROL_HALT bits are set in | ||
274 | * pWhalBus->uBootData and start uploading firmware | ||
275 | */ | ||
276 | if ((boot_data & ECPU_CONTROL_HALT) == 0) { | ||
277 | wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); | ||
278 | ret = -EIO; | ||
279 | goto out; | ||
280 | } | ||
281 | |||
282 | ret = wl->chip.op_upload_fw(wl); | ||
283 | if (ret < 0) | ||
284 | goto out; | ||
285 | |||
286 | /* 10.5 start firmware */ | ||
287 | ret = wl1251_boot_run_firmware(wl); | ||
288 | if (ret < 0) | ||
289 | goto out; | ||
290 | |||
291 | out: | ||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | static int wl1251_mem_cfg(struct wl1251 *wl) | ||
296 | { | ||
297 | struct wl1251_acx_config_memory *mem_conf; | ||
298 | int ret, i; | ||
299 | |||
300 | wl1251_debug(DEBUG_ACX, "wl1251 mem cfg"); | ||
301 | |||
302 | mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); | ||
303 | if (!mem_conf) { | ||
304 | ret = -ENOMEM; | ||
305 | goto out; | ||
306 | } | ||
307 | |||
308 | /* memory config */ | ||
309 | mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); | ||
310 | mem_conf->mem_config.rx_mem_block_num = 35; | ||
311 | mem_conf->mem_config.tx_min_mem_block_num = 64; | ||
312 | mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; | ||
313 | mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; | ||
314 | mem_conf->mem_config.num_ssid_profiles = 1; | ||
315 | mem_conf->mem_config.debug_buffer_size = | ||
316 | cpu_to_le16(TRACE_BUFFER_MAX_SIZE); | ||
317 | |||
318 | /* RX queue config */ | ||
319 | mem_conf->rx_queue_config.dma_address = 0; | ||
320 | mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; | ||
321 | mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; | ||
322 | mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; | ||
323 | |||
324 | /* TX queue config */ | ||
325 | for (i = 0; i < MAX_TX_QUEUES; i++) { | ||
326 | mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; | ||
327 | mem_conf->tx_queue_config[i].attributes = i; | ||
328 | } | ||
329 | |||
330 | ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, | ||
331 | sizeof(*mem_conf)); | ||
332 | if (ret < 0) { | ||
333 | wl1251_warning("wl1251 mem config failed: %d", ret); | ||
334 | goto out; | ||
335 | } | ||
336 | |||
337 | out: | ||
338 | kfree(mem_conf); | ||
339 | return ret; | ||
340 | } | ||
341 | |||
342 | static int wl1251_hw_init_mem_config(struct wl1251 *wl) | ||
343 | { | ||
344 | int ret; | ||
345 | |||
346 | ret = wl1251_mem_cfg(wl); | ||
347 | if (ret < 0) | ||
348 | return ret; | ||
349 | |||
350 | wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), | ||
351 | GFP_KERNEL); | ||
352 | if (!wl->target_mem_map) { | ||
353 | wl1251_error("couldn't allocate target memory map"); | ||
354 | return -ENOMEM; | ||
355 | } | ||
356 | |||
357 | /* we now ask for the firmware built memory map */ | ||
358 | ret = wl1251_acx_mem_map(wl, wl->target_mem_map, | ||
359 | sizeof(struct wl1251_acx_mem_map)); | ||
360 | if (ret < 0) { | ||
361 | wl1251_error("couldn't retrieve firmware memory map"); | ||
362 | kfree(wl->target_mem_map); | ||
363 | wl->target_mem_map = NULL; | ||
364 | return ret; | ||
365 | } | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static void wl1251_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) | ||
371 | { | ||
372 | u32 cpu_ctrl; | ||
373 | |||
374 | /* 10.5.0 run the firmware (I) */ | ||
375 | cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
376 | |||
377 | /* 10.5.1 run the firmware (II) */ | ||
378 | cpu_ctrl &= ~flag; | ||
379 | wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); | ||
380 | } | ||
381 | |||
382 | static void wl1251_target_enable_interrupts(struct wl1251 *wl) | ||
383 | { | ||
384 | /* Enable target's interrupts */ | ||
385 | wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | | ||
386 | WL1251_ACX_INTR_RX1_DATA | | ||
387 | WL1251_ACX_INTR_TX_RESULT | | ||
388 | WL1251_ACX_INTR_EVENT_A | | ||
389 | WL1251_ACX_INTR_EVENT_B | | ||
390 | WL1251_ACX_INTR_INIT_COMPLETE; | ||
391 | wl1251_boot_target_enable_interrupts(wl); | ||
392 | } | ||
393 | |||
394 | static void wl1251_fw_version(struct wl1251 *wl) | ||
395 | { | ||
396 | wl1251_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); | ||
397 | } | ||
398 | |||
399 | static void wl1251_irq_work(struct work_struct *work) | ||
400 | { | ||
401 | u32 intr; | ||
402 | struct wl1251 *wl = | ||
403 | container_of(work, struct wl1251, irq_work); | ||
404 | int ret; | ||
405 | |||
406 | mutex_lock(&wl->mutex); | ||
407 | |||
408 | wl1251_debug(DEBUG_IRQ, "IRQ work"); | ||
409 | |||
410 | if (wl->state == WL1251_STATE_OFF) | ||
411 | goto out; | ||
412 | |||
413 | ret = wl1251_ps_elp_wakeup(wl); | ||
414 | if (ret < 0) | ||
415 | goto out; | ||
416 | |||
417 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); | ||
418 | |||
419 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
420 | wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); | ||
421 | |||
422 | if (wl->data_path) { | ||
423 | wl->rx_counter = | ||
424 | wl1251_mem_read32(wl, wl->data_path->rx_control_addr); | ||
425 | |||
426 | /* We handle a firmware bug here */ | ||
427 | switch ((wl->rx_counter - wl->rx_handled) & 0xf) { | ||
428 | case 0: | ||
429 | wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); | ||
430 | intr &= ~WL1251_ACX_INTR_RX0_DATA; | ||
431 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
432 | break; | ||
433 | case 1: | ||
434 | wl1251_debug(DEBUG_IRQ, "RX: FW +1"); | ||
435 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
436 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
437 | break; | ||
438 | case 2: | ||
439 | wl1251_debug(DEBUG_IRQ, "RX: FW +2"); | ||
440 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
441 | intr |= WL1251_ACX_INTR_RX1_DATA; | ||
442 | break; | ||
443 | default: | ||
444 | wl1251_warning("RX: FW and host out of sync: %d", | ||
445 | wl->rx_counter - wl->rx_handled); | ||
446 | break; | ||
447 | } | ||
448 | |||
449 | wl->rx_handled = wl->rx_counter; | ||
450 | |||
451 | |||
452 | wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); | ||
453 | } | ||
454 | |||
455 | intr &= wl->intr_mask; | ||
456 | |||
457 | if (intr == 0) { | ||
458 | wl1251_debug(DEBUG_IRQ, "INTR is 0"); | ||
459 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
460 | ~(wl->intr_mask)); | ||
461 | |||
462 | goto out_sleep; | ||
463 | } | ||
464 | |||
465 | if (intr & WL1251_ACX_INTR_RX0_DATA) { | ||
466 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); | ||
467 | wl1251_rx(wl); | ||
468 | } | ||
469 | |||
470 | if (intr & WL1251_ACX_INTR_RX1_DATA) { | ||
471 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); | ||
472 | wl1251_rx(wl); | ||
473 | } | ||
474 | |||
475 | if (intr & WL1251_ACX_INTR_TX_RESULT) { | ||
476 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); | ||
477 | wl1251_tx_complete(wl); | ||
478 | } | ||
479 | |||
480 | if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { | ||
481 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); | ||
482 | if (intr & WL1251_ACX_INTR_EVENT_A) | ||
483 | wl1251_event_handle(wl, 0); | ||
484 | else | ||
485 | wl1251_event_handle(wl, 1); | ||
486 | } | ||
487 | |||
488 | if (intr & WL1251_ACX_INTR_INIT_COMPLETE) | ||
489 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); | ||
490 | |||
491 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | ||
492 | |||
493 | out_sleep: | ||
494 | wl1251_ps_elp_sleep(wl); | ||
495 | |||
496 | out: | ||
497 | mutex_unlock(&wl->mutex); | ||
498 | } | ||
499 | |||
500 | static int wl1251_hw_init_txq_fill(u8 qid, | ||
501 | struct acx_tx_queue_qos_config *config, | ||
502 | u32 num_blocks) | ||
503 | { | ||
504 | config->qid = qid; | ||
505 | |||
506 | switch (qid) { | ||
507 | case QOS_AC_BE: | ||
508 | config->high_threshold = | ||
509 | (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; | ||
510 | config->low_threshold = | ||
511 | (QOS_TX_LOW_BE_DEF * num_blocks) / 100; | ||
512 | break; | ||
513 | case QOS_AC_BK: | ||
514 | config->high_threshold = | ||
515 | (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; | ||
516 | config->low_threshold = | ||
517 | (QOS_TX_LOW_BK_DEF * num_blocks) / 100; | ||
518 | break; | ||
519 | case QOS_AC_VI: | ||
520 | config->high_threshold = | ||
521 | (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; | ||
522 | config->low_threshold = | ||
523 | (QOS_TX_LOW_VI_DEF * num_blocks) / 100; | ||
524 | break; | ||
525 | case QOS_AC_VO: | ||
526 | config->high_threshold = | ||
527 | (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; | ||
528 | config->low_threshold = | ||
529 | (QOS_TX_LOW_VO_DEF * num_blocks) / 100; | ||
530 | break; | ||
531 | default: | ||
532 | wl1251_error("Invalid TX queue id: %d", qid); | ||
533 | return -EINVAL; | ||
534 | } | ||
535 | |||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) | ||
540 | { | ||
541 | struct acx_tx_queue_qos_config *config; | ||
542 | struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; | ||
543 | int ret, i; | ||
544 | |||
545 | wl1251_debug(DEBUG_ACX, "acx tx queue config"); | ||
546 | |||
547 | config = kzalloc(sizeof(*config), GFP_KERNEL); | ||
548 | if (!config) { | ||
549 | ret = -ENOMEM; | ||
550 | goto out; | ||
551 | } | ||
552 | |||
553 | for (i = 0; i < MAX_NUM_OF_AC; i++) { | ||
554 | ret = wl1251_hw_init_txq_fill(i, config, | ||
555 | wl_mem_map->num_tx_mem_blocks); | ||
556 | if (ret < 0) | ||
557 | goto out; | ||
558 | |||
559 | ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, | ||
560 | config, sizeof(*config)); | ||
561 | if (ret < 0) | ||
562 | goto out; | ||
563 | } | ||
564 | |||
565 | out: | ||
566 | kfree(config); | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | static int wl1251_hw_init_data_path_config(struct wl1251 *wl) | ||
571 | { | ||
572 | int ret; | ||
573 | |||
574 | /* asking for the data path parameters */ | ||
575 | wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), | ||
576 | GFP_KERNEL); | ||
577 | if (!wl->data_path) { | ||
578 | wl1251_error("Couldn't allocate data path parameters"); | ||
579 | return -ENOMEM; | ||
580 | } | ||
581 | |||
582 | ret = wl1251_acx_data_path_params(wl, wl->data_path); | ||
583 | if (ret < 0) { | ||
584 | kfree(wl->data_path); | ||
585 | wl->data_path = NULL; | ||
586 | return ret; | ||
587 | } | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int wl1251_hw_init(struct wl1251 *wl) | ||
593 | { | ||
594 | struct wl1251_acx_mem_map *wl_mem_map; | ||
595 | int ret; | ||
596 | |||
597 | ret = wl1251_hw_init_hwenc_config(wl); | ||
598 | if (ret < 0) | ||
599 | return ret; | ||
600 | |||
601 | /* Template settings */ | ||
602 | ret = wl1251_hw_init_templates_config(wl); | ||
603 | if (ret < 0) | ||
604 | return ret; | ||
605 | |||
606 | /* Default memory configuration */ | ||
607 | ret = wl1251_hw_init_mem_config(wl); | ||
608 | if (ret < 0) | ||
609 | return ret; | ||
610 | |||
611 | /* Default data path configuration */ | ||
612 | ret = wl1251_hw_init_data_path_config(wl); | ||
613 | if (ret < 0) | ||
614 | goto out_free_memmap; | ||
615 | |||
616 | /* RX config */ | ||
617 | ret = wl1251_hw_init_rx_config(wl, | ||
618 | RX_CFG_PROMISCUOUS | RX_CFG_TSF, | ||
619 | RX_FILTER_OPTION_DEF); | ||
620 | /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, | ||
621 | RX_FILTER_OPTION_FILTER_ALL); */ | ||
622 | if (ret < 0) | ||
623 | goto out_free_data_path; | ||
624 | |||
625 | /* TX queues config */ | ||
626 | ret = wl1251_hw_init_tx_queue_config(wl); | ||
627 | if (ret < 0) | ||
628 | goto out_free_data_path; | ||
629 | |||
630 | /* PHY layer config */ | ||
631 | ret = wl1251_hw_init_phy_config(wl); | ||
632 | if (ret < 0) | ||
633 | goto out_free_data_path; | ||
634 | |||
635 | /* Beacon filtering */ | ||
636 | ret = wl1251_hw_init_beacon_filter(wl); | ||
637 | if (ret < 0) | ||
638 | goto out_free_data_path; | ||
639 | |||
640 | /* Bluetooth WLAN coexistence */ | ||
641 | ret = wl1251_hw_init_pta(wl); | ||
642 | if (ret < 0) | ||
643 | goto out_free_data_path; | ||
644 | |||
645 | /* Energy detection */ | ||
646 | ret = wl1251_hw_init_energy_detection(wl); | ||
647 | if (ret < 0) | ||
648 | goto out_free_data_path; | ||
649 | |||
650 | /* Beacons and boradcast settings */ | ||
651 | ret = wl1251_hw_init_beacon_broadcast(wl); | ||
652 | if (ret < 0) | ||
653 | goto out_free_data_path; | ||
654 | |||
655 | /* Enable data path */ | ||
656 | ret = wl1251_cmd_data_path(wl, wl->channel, 1); | ||
657 | if (ret < 0) | ||
658 | goto out_free_data_path; | ||
659 | |||
660 | /* Default power state */ | ||
661 | ret = wl1251_hw_init_power_auth(wl); | ||
662 | if (ret < 0) | ||
663 | goto out_free_data_path; | ||
664 | |||
665 | wl_mem_map = wl->target_mem_map; | ||
666 | wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", | ||
667 | wl_mem_map->num_tx_mem_blocks, | ||
668 | wl->data_path->tx_control_addr, | ||
669 | wl_mem_map->num_rx_mem_blocks, | ||
670 | wl->data_path->rx_control_addr); | ||
671 | |||
672 | return 0; | ||
673 | |||
674 | out_free_data_path: | ||
675 | kfree(wl->data_path); | ||
676 | |||
677 | out_free_memmap: | ||
678 | kfree(wl->target_mem_map); | ||
679 | |||
680 | return ret; | ||
681 | } | ||
682 | |||
683 | static int wl1251_plt_init(struct wl1251 *wl) | ||
684 | { | ||
685 | int ret; | ||
686 | |||
687 | ret = wl1251_hw_init_mem_config(wl); | ||
688 | if (ret < 0) | ||
689 | return ret; | ||
690 | |||
691 | ret = wl1251_cmd_data_path(wl, wl->channel, 1); | ||
692 | if (ret < 0) | ||
693 | return ret; | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | void wl1251_setup(struct wl1251 *wl) | ||
699 | { | ||
700 | /* FIXME: Is it better to use strncpy here or is this ok? */ | ||
701 | wl->chip.fw_filename = WL1251_FW_NAME; | ||
702 | wl->chip.nvs_filename = WL1251_NVS_NAME; | ||
703 | |||
704 | /* Now we know what chip we're using, so adjust the power on sleep | ||
705 | * time accordingly */ | ||
706 | wl->chip.power_on_sleep = WL1251_POWER_ON_SLEEP; | ||
707 | |||
708 | wl->chip.intr_cmd_complete = WL1251_ACX_INTR_CMD_COMPLETE; | ||
709 | wl->chip.intr_init_complete = WL1251_ACX_INTR_INIT_COMPLETE; | ||
710 | |||
711 | wl->chip.op_upload_nvs = wl1251_upload_nvs; | ||
712 | wl->chip.op_upload_fw = wl1251_upload_firmware; | ||
713 | wl->chip.op_boot = wl1251_boot; | ||
714 | wl->chip.op_set_ecpu_ctrl = wl1251_set_ecpu_ctrl; | ||
715 | wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; | ||
716 | wl->chip.op_hw_init = wl1251_hw_init; | ||
717 | wl->chip.op_plt_init = wl1251_plt_init; | ||
718 | wl->chip.op_fw_version = wl1251_fw_version; | ||
719 | wl->chip.op_tx_flush = wl1251_tx_flush; | ||
720 | wl->chip.op_cmd_join = wl1251_cmd_join; | ||
721 | |||
722 | wl->chip.p_table = wl1251_part_table; | ||
723 | wl->chip.acx_reg_table = wl1251_acx_reg_table; | ||
724 | |||
725 | INIT_WORK(&wl->irq_work, wl1251_irq_work); | ||
726 | INIT_WORK(&wl->tx_work, wl1251_tx_work); | ||
727 | |||
728 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h deleted file mode 100644 index 68183c472e43..000000000000 --- a/drivers/net/wireless/wl12xx/wl1251_ops.h +++ /dev/null | |||
@@ -1,165 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __WL1251_OPS_H__ | ||
25 | #define __WL1251_OPS_H__ | ||
26 | |||
27 | #include <linux/bitops.h> | ||
28 | |||
29 | #include "wl1251.h" | ||
30 | #include "wl1251_acx.h" | ||
31 | |||
32 | #define WL1251_FW_NAME "wl1251-fw.bin" | ||
33 | #define WL1251_NVS_NAME "wl1251-nvs.bin" | ||
34 | |||
35 | #define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ | ||
36 | |||
37 | void wl1251_setup(struct wl1251 *wl); | ||
38 | |||
39 | |||
40 | struct wl1251_acx_memory { | ||
41 | __le16 num_stations; /* number of STAs to be supported. */ | ||
42 | u16 reserved_1; | ||
43 | |||
44 | /* | ||
45 | * Nmber of memory buffers for the RX mem pool. | ||
46 | * The actual number may be less if there are | ||
47 | * not enough blocks left for the minimum num | ||
48 | * of TX ones. | ||
49 | */ | ||
50 | u8 rx_mem_block_num; | ||
51 | u8 reserved_2; | ||
52 | u8 num_tx_queues; /* From 1 to 16 */ | ||
53 | u8 host_if_options; /* HOST_IF* */ | ||
54 | u8 tx_min_mem_block_num; | ||
55 | u8 num_ssid_profiles; | ||
56 | __le16 debug_buffer_size; | ||
57 | } __attribute__ ((packed)); | ||
58 | |||
59 | |||
60 | #define ACX_RX_DESC_MIN 1 | ||
61 | #define ACX_RX_DESC_MAX 127 | ||
62 | #define ACX_RX_DESC_DEF 32 | ||
63 | struct wl1251_acx_rx_queue_config { | ||
64 | u8 num_descs; | ||
65 | u8 pad; | ||
66 | u8 type; | ||
67 | u8 priority; | ||
68 | __le32 dma_address; | ||
69 | } __attribute__ ((packed)); | ||
70 | |||
71 | #define ACX_TX_DESC_MIN 1 | ||
72 | #define ACX_TX_DESC_MAX 127 | ||
73 | #define ACX_TX_DESC_DEF 16 | ||
74 | struct wl1251_acx_tx_queue_config { | ||
75 | u8 num_descs; | ||
76 | u8 pad[2]; | ||
77 | u8 attributes; | ||
78 | } __attribute__ ((packed)); | ||
79 | |||
80 | #define MAX_TX_QUEUE_CONFIGS 5 | ||
81 | #define MAX_TX_QUEUES 4 | ||
82 | struct wl1251_acx_config_memory { | ||
83 | struct acx_header header; | ||
84 | |||
85 | struct wl1251_acx_memory mem_config; | ||
86 | struct wl1251_acx_rx_queue_config rx_queue_config; | ||
87 | struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; | ||
88 | } __attribute__ ((packed)); | ||
89 | |||
90 | struct wl1251_acx_mem_map { | ||
91 | struct acx_header header; | ||
92 | |||
93 | void *code_start; | ||
94 | void *code_end; | ||
95 | |||
96 | void *wep_defkey_start; | ||
97 | void *wep_defkey_end; | ||
98 | |||
99 | void *sta_table_start; | ||
100 | void *sta_table_end; | ||
101 | |||
102 | void *packet_template_start; | ||
103 | void *packet_template_end; | ||
104 | |||
105 | void *queue_memory_start; | ||
106 | void *queue_memory_end; | ||
107 | |||
108 | void *packet_memory_pool_start; | ||
109 | void *packet_memory_pool_end; | ||
110 | |||
111 | void *debug_buffer1_start; | ||
112 | void *debug_buffer1_end; | ||
113 | |||
114 | void *debug_buffer2_start; | ||
115 | void *debug_buffer2_end; | ||
116 | |||
117 | /* Number of blocks FW allocated for TX packets */ | ||
118 | u32 num_tx_mem_blocks; | ||
119 | |||
120 | /* Number of blocks FW allocated for RX packets */ | ||
121 | u32 num_rx_mem_blocks; | ||
122 | } __attribute__ ((packed)); | ||
123 | |||
124 | /************************************************************************* | ||
125 | |||
126 | Host Interrupt Register (WiLink -> Host) | ||
127 | |||
128 | **************************************************************************/ | ||
129 | |||
130 | /* RX packet is ready in Xfer buffer #0 */ | ||
131 | #define WL1251_ACX_INTR_RX0_DATA BIT(0) | ||
132 | |||
133 | /* TX result(s) are in the TX complete buffer */ | ||
134 | #define WL1251_ACX_INTR_TX_RESULT BIT(1) | ||
135 | |||
136 | /* OBSOLETE */ | ||
137 | #define WL1251_ACX_INTR_TX_XFR BIT(2) | ||
138 | |||
139 | /* RX packet is ready in Xfer buffer #1 */ | ||
140 | #define WL1251_ACX_INTR_RX1_DATA BIT(3) | ||
141 | |||
142 | /* Event was entered to Event MBOX #A */ | ||
143 | #define WL1251_ACX_INTR_EVENT_A BIT(4) | ||
144 | |||
145 | /* Event was entered to Event MBOX #B */ | ||
146 | #define WL1251_ACX_INTR_EVENT_B BIT(5) | ||
147 | |||
148 | /* OBSOLETE */ | ||
149 | #define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) | ||
150 | |||
151 | /* Trace meassge on MBOX #A */ | ||
152 | #define WL1251_ACX_INTR_TRACE_A BIT(7) | ||
153 | |||
154 | /* Trace meassge on MBOX #B */ | ||
155 | #define WL1251_ACX_INTR_TRACE_B BIT(8) | ||
156 | |||
157 | /* Command processing completion */ | ||
158 | #define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) | ||
159 | |||
160 | /* Init sequence is done */ | ||
161 | #define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) | ||
162 | |||
163 | #define WL1251_ACX_INTR_ALL 0xFFFFFFFF | ||
164 | |||
165 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 68ff7f1900ed..c53e28727ed4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c | |||
@@ -21,9 +21,10 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include "reg.h" | 24 | #include "wl1251_reg.h" |
25 | #include "wl1251_ps.h" | 25 | #include "wl1251_ps.h" |
26 | #include "wl1251_spi.h" | 26 | #include "wl1251_cmd.h" |
27 | #include "wl1251_io.h" | ||
27 | 28 | ||
28 | #define WL1251_WAKEUP_TIMEOUT 2000 | 29 | #define WL1251_WAKEUP_TIMEOUT 2000 |
29 | 30 | ||
@@ -117,6 +118,13 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) | |||
117 | switch (mode) { | 118 | switch (mode) { |
118 | case STATION_POWER_SAVE_MODE: | 119 | case STATION_POWER_SAVE_MODE: |
119 | wl1251_debug(DEBUG_PSM, "entering psm"); | 120 | wl1251_debug(DEBUG_PSM, "entering psm"); |
121 | |||
122 | ret = wl1251_acx_wake_up_conditions(wl, | ||
123 | WAKE_UP_EVENT_DTIM_BITMAP, | ||
124 | wl->listen_int); | ||
125 | if (ret < 0) | ||
126 | return ret; | ||
127 | |||
120 | ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); | 128 | ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); |
121 | if (ret < 0) | 129 | if (ret < 0) |
122 | return ret; | 130 | return ret; |
@@ -134,6 +142,12 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) | |||
134 | if (ret < 0) | 142 | if (ret < 0) |
135 | return ret; | 143 | return ret; |
136 | 144 | ||
145 | ret = wl1251_acx_wake_up_conditions(wl, | ||
146 | WAKE_UP_EVENT_DTIM_BITMAP, | ||
147 | wl->listen_int); | ||
148 | if (ret < 0) | ||
149 | return ret; | ||
150 | |||
137 | ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); | 151 | ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); |
138 | if (ret < 0) | 152 | if (ret < 0) |
139 | return ret; | 153 | return ret; |
diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h new file mode 100644 index 000000000000..bdd561001dcb --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_reg.h | |||
@@ -0,0 +1,644 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __REG_H__ | ||
26 | #define __REG_H__ | ||
27 | |||
28 | #include <linux/bitops.h> | ||
29 | |||
30 | #define REGISTERS_BASE 0x00300000 | ||
31 | #define DRPW_BASE 0x00310000 | ||
32 | |||
33 | #define REGISTERS_DOWN_SIZE 0x00008800 | ||
34 | #define REGISTERS_WORK_SIZE 0x0000b000 | ||
35 | |||
36 | #define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC | ||
37 | |||
38 | /* ELP register commands */ | ||
39 | #define ELPCTRL_WAKE_UP 0x1 | ||
40 | #define ELPCTRL_WAKE_UP_WLAN_READY 0x5 | ||
41 | #define ELPCTRL_SLEEP 0x0 | ||
42 | /* ELP WLAN_READY bit */ | ||
43 | #define ELPCTRL_WLAN_READY 0x2 | ||
44 | |||
45 | /* Device Configuration registers*/ | ||
46 | #define SOR_CFG (REGISTERS_BASE + 0x0800) | ||
47 | #define ECPU_CTRL (REGISTERS_BASE + 0x0804) | ||
48 | #define HI_CFG (REGISTERS_BASE + 0x0808) | ||
49 | #define EE_START (REGISTERS_BASE + 0x080C) | ||
50 | |||
51 | #define CHIP_ID_B (REGISTERS_BASE + 0x5674) | ||
52 | |||
53 | #define CHIP_ID_1251_PG10 (0x7010101) | ||
54 | #define CHIP_ID_1251_PG11 (0x7020101) | ||
55 | #define CHIP_ID_1251_PG12 (0x7030101) | ||
56 | |||
57 | #define ENABLE (REGISTERS_BASE + 0x5450) | ||
58 | |||
59 | /* Power Management registers */ | ||
60 | #define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) | ||
61 | #define ELP_CMD (REGISTERS_BASE + 0x5808) | ||
62 | #define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) | ||
63 | #define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) | ||
64 | #define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) | ||
65 | |||
66 | #define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) | ||
67 | |||
68 | /* Scratch Pad registers*/ | ||
69 | #define SCR_PAD0 (REGISTERS_BASE + 0x5608) | ||
70 | #define SCR_PAD1 (REGISTERS_BASE + 0x560C) | ||
71 | #define SCR_PAD2 (REGISTERS_BASE + 0x5610) | ||
72 | #define SCR_PAD3 (REGISTERS_BASE + 0x5614) | ||
73 | #define SCR_PAD4 (REGISTERS_BASE + 0x5618) | ||
74 | #define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) | ||
75 | #define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) | ||
76 | #define SCR_PAD5 (REGISTERS_BASE + 0x5624) | ||
77 | #define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) | ||
78 | #define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) | ||
79 | #define SCR_PAD6 (REGISTERS_BASE + 0x5630) | ||
80 | #define SCR_PAD7 (REGISTERS_BASE + 0x5634) | ||
81 | #define SCR_PAD8 (REGISTERS_BASE + 0x5638) | ||
82 | #define SCR_PAD9 (REGISTERS_BASE + 0x563C) | ||
83 | |||
84 | /* Spare registers*/ | ||
85 | #define SPARE_A1 (REGISTERS_BASE + 0x0994) | ||
86 | #define SPARE_A2 (REGISTERS_BASE + 0x0998) | ||
87 | #define SPARE_A3 (REGISTERS_BASE + 0x099C) | ||
88 | #define SPARE_A4 (REGISTERS_BASE + 0x09A0) | ||
89 | #define SPARE_A5 (REGISTERS_BASE + 0x09A4) | ||
90 | #define SPARE_A6 (REGISTERS_BASE + 0x09A8) | ||
91 | #define SPARE_A7 (REGISTERS_BASE + 0x09AC) | ||
92 | #define SPARE_A8 (REGISTERS_BASE + 0x09B0) | ||
93 | #define SPARE_B1 (REGISTERS_BASE + 0x5420) | ||
94 | #define SPARE_B2 (REGISTERS_BASE + 0x5424) | ||
95 | #define SPARE_B3 (REGISTERS_BASE + 0x5428) | ||
96 | #define SPARE_B4 (REGISTERS_BASE + 0x542C) | ||
97 | #define SPARE_B5 (REGISTERS_BASE + 0x5430) | ||
98 | #define SPARE_B6 (REGISTERS_BASE + 0x5434) | ||
99 | #define SPARE_B7 (REGISTERS_BASE + 0x5438) | ||
100 | #define SPARE_B8 (REGISTERS_BASE + 0x543C) | ||
101 | |||
102 | enum wl12xx_acx_int_reg { | ||
103 | ACX_REG_INTERRUPT_TRIG, | ||
104 | ACX_REG_INTERRUPT_TRIG_H, | ||
105 | |||
106 | /*============================================= | ||
107 | Host Interrupt Mask Register - 32bit (RW) | ||
108 | ------------------------------------------ | ||
109 | Setting a bit in this register masks the | ||
110 | corresponding interrupt to the host. | ||
111 | 0 - RX0 - Rx first dubble buffer Data Interrupt | ||
112 | 1 - TXD - Tx Data Interrupt | ||
113 | 2 - TXXFR - Tx Transfer Interrupt | ||
114 | 3 - RX1 - Rx second dubble buffer Data Interrupt | ||
115 | 4 - RXXFR - Rx Transfer Interrupt | ||
116 | 5 - EVENT_A - Event Mailbox interrupt | ||
117 | 6 - EVENT_B - Event Mailbox interrupt | ||
118 | 7 - WNONHST - Wake On Host Interrupt | ||
119 | 8 - TRACE_A - Debug Trace interrupt | ||
120 | 9 - TRACE_B - Debug Trace interrupt | ||
121 | 10 - CDCMP - Command Complete Interrupt | ||
122 | 11 - | ||
123 | 12 - | ||
124 | 13 - | ||
125 | 14 - ICOMP - Initialization Complete Interrupt | ||
126 | 16 - SG SE - Soft Gemini - Sense enable interrupt | ||
127 | 17 - SG SD - Soft Gemini - Sense disable interrupt | ||
128 | 18 - - | ||
129 | 19 - - | ||
130 | 20 - - | ||
131 | 21- - | ||
132 | Default: 0x0001 | ||
133 | *==============================================*/ | ||
134 | ACX_REG_INTERRUPT_MASK, | ||
135 | |||
136 | /*============================================= | ||
137 | Host Interrupt Mask Set 16bit, (Write only) | ||
138 | ------------------------------------------ | ||
139 | Setting a bit in this register sets | ||
140 | the corresponding bin in ACX_HINT_MASK register | ||
141 | without effecting the mask | ||
142 | state of other bits (0 = no effect). | ||
143 | ==============================================*/ | ||
144 | ACX_REG_HINT_MASK_SET, | ||
145 | |||
146 | /*============================================= | ||
147 | Host Interrupt Mask Clear 16bit,(Write only) | ||
148 | ------------------------------------------ | ||
149 | Setting a bit in this register clears | ||
150 | the corresponding bin in ACX_HINT_MASK register | ||
151 | without effecting the mask | ||
152 | state of other bits (0 = no effect). | ||
153 | =============================================*/ | ||
154 | ACX_REG_HINT_MASK_CLR, | ||
155 | |||
156 | /*============================================= | ||
157 | Host Interrupt Status Nondestructive Read | ||
158 | 16bit,(Read only) | ||
159 | ------------------------------------------ | ||
160 | The host can read this register to determine | ||
161 | which interrupts are active. | ||
162 | Reading this register doesn't | ||
163 | effect its content. | ||
164 | =============================================*/ | ||
165 | ACX_REG_INTERRUPT_NO_CLEAR, | ||
166 | |||
167 | /*============================================= | ||
168 | Host Interrupt Status Clear on Read Register | ||
169 | 16bit,(Read only) | ||
170 | ------------------------------------------ | ||
171 | The host can read this register to determine | ||
172 | which interrupts are active. | ||
173 | Reading this register clears it, | ||
174 | thus making all interrupts inactive. | ||
175 | ==============================================*/ | ||
176 | ACX_REG_INTERRUPT_CLEAR, | ||
177 | |||
178 | /*============================================= | ||
179 | Host Interrupt Acknowledge Register | ||
180 | 16bit,(Write only) | ||
181 | ------------------------------------------ | ||
182 | The host can set individual bits in this | ||
183 | register to clear (acknowledge) the corresp. | ||
184 | interrupt status bits in the HINT_STS_CLR and | ||
185 | HINT_STS_ND registers, thus making the | ||
186 | assotiated interrupt inactive. (0-no effect) | ||
187 | ==============================================*/ | ||
188 | ACX_REG_INTERRUPT_ACK, | ||
189 | |||
190 | /*=============================================== | ||
191 | Host Software Reset - 32bit RW | ||
192 | ------------------------------------------ | ||
193 | [31:1] Reserved | ||
194 | 0 SOFT_RESET Soft Reset - When this bit is set, | ||
195 | it holds the Wlan hardware in a soft reset state. | ||
196 | This reset disables all MAC and baseband processor | ||
197 | clocks except the CardBus/PCI interface clock. | ||
198 | It also initializes all MAC state machines except | ||
199 | the host interface. It does not reload the | ||
200 | contents of the EEPROM. When this bit is cleared | ||
201 | (not self-clearing), the Wlan hardware | ||
202 | exits the software reset state. | ||
203 | ===============================================*/ | ||
204 | ACX_REG_SLV_SOFT_RESET, | ||
205 | |||
206 | /*=============================================== | ||
207 | EEPROM Burst Read Start - 32bit RW | ||
208 | ------------------------------------------ | ||
209 | [31:1] Reserved | ||
210 | 0 ACX_EE_START - EEPROM Burst Read Start 0 | ||
211 | Setting this bit starts a burst read from | ||
212 | the external EEPROM. | ||
213 | If this bit is set (after reset) before an EEPROM read/write, | ||
214 | the burst read starts at EEPROM address 0. | ||
215 | Otherwise, it starts at the address | ||
216 | following the address of the previous access. | ||
217 | TheWlan hardware hardware clears this bit automatically. | ||
218 | |||
219 | Default: 0x00000000 | ||
220 | *================================================*/ | ||
221 | ACX_REG_EE_START, | ||
222 | |||
223 | /* Embedded ARM CPU Control */ | ||
224 | |||
225 | /*=============================================== | ||
226 | Halt eCPU - 32bit RW | ||
227 | ------------------------------------------ | ||
228 | 0 HALT_ECPU Halt Embedded CPU - This bit is the | ||
229 | compliment of bit 1 (MDATA2) in the SOR_CFG register. | ||
230 | During a hardware reset, this bit holds | ||
231 | the inverse of MDATA2. | ||
232 | When downloading firmware from the host, | ||
233 | set this bit (pull down MDATA2). | ||
234 | The host clears this bit after downloading the firmware into | ||
235 | zero-wait-state SSRAM. | ||
236 | When loading firmware from Flash, clear this bit (pull up MDATA2) | ||
237 | so that the eCPU can run the bootloader code in Flash | ||
238 | HALT_ECPU eCPU State | ||
239 | -------------------- | ||
240 | 1 halt eCPU | ||
241 | 0 enable eCPU | ||
242 | ===============================================*/ | ||
243 | ACX_REG_ECPU_CONTROL, | ||
244 | |||
245 | ACX_REG_TABLE_LEN | ||
246 | }; | ||
247 | |||
248 | #define ACX_SLV_SOFT_RESET_BIT BIT(1) | ||
249 | #define ACX_REG_EEPROM_START_BIT BIT(1) | ||
250 | |||
251 | /* Command/Information Mailbox Pointers */ | ||
252 | |||
253 | /*=============================================== | ||
254 | Command Mailbox Pointer - 32bit RW | ||
255 | ------------------------------------------ | ||
256 | This register holds the start address of | ||
257 | the command mailbox located in the Wlan hardware memory. | ||
258 | The host must read this pointer after a reset to | ||
259 | find the location of the command mailbox. | ||
260 | The Wlan hardware initializes the command mailbox | ||
261 | pointer with the default address of the command mailbox. | ||
262 | The command mailbox pointer is not valid until after | ||
263 | the host receives the Init Complete interrupt from | ||
264 | the Wlan hardware. | ||
265 | ===============================================*/ | ||
266 | #define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) | ||
267 | |||
268 | /*=============================================== | ||
269 | Information Mailbox Pointer - 32bit RW | ||
270 | ------------------------------------------ | ||
271 | This register holds the start address of | ||
272 | the information mailbox located in the Wlan hardware memory. | ||
273 | The host must read this pointer after a reset to find | ||
274 | the location of the information mailbox. | ||
275 | The Wlan hardware initializes the information mailbox pointer | ||
276 | with the default address of the information mailbox. | ||
277 | The information mailbox pointer is not valid | ||
278 | until after the host receives the Init Complete interrupt from | ||
279 | the Wlan hardware. | ||
280 | ===============================================*/ | ||
281 | #define REG_EVENT_MAILBOX_PTR (SCR_PAD1) | ||
282 | |||
283 | |||
284 | /* Misc */ | ||
285 | |||
286 | #define REG_ENABLE_TX_RX (ENABLE) | ||
287 | /* | ||
288 | * Rx configuration (filter) information element | ||
289 | * --------------------------------------------- | ||
290 | */ | ||
291 | #define REG_RX_CONFIG (RX_CFG) | ||
292 | #define REG_RX_FILTER (RX_FILTER_CFG) | ||
293 | |||
294 | |||
295 | #define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 | ||
296 | |||
297 | /* promiscuous - receives all valid frames */ | ||
298 | #define RX_CFG_PROMISCUOUS 0x0008 | ||
299 | |||
300 | /* receives frames from any BSSID */ | ||
301 | #define RX_CFG_BSSID 0x0020 | ||
302 | |||
303 | /* receives frames destined to any MAC address */ | ||
304 | #define RX_CFG_MAC 0x0010 | ||
305 | |||
306 | #define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 | ||
307 | #define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 | ||
308 | #define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 | ||
309 | #define RX_CFG_ENABLE_ANY_BSSID 0x0000 | ||
310 | |||
311 | /* discards all broadcast frames */ | ||
312 | #define RX_CFG_DISABLE_BCAST 0x0200 | ||
313 | |||
314 | #define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 | ||
315 | #define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 | ||
316 | #define RX_CFG_COPY_RX_STATUS 0x2000 | ||
317 | #define RX_CFG_TSF 0x10000 | ||
318 | |||
319 | #define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ | ||
320 | RX_CFG_ENABLE_ONLY_MY_BSSID) | ||
321 | |||
322 | #define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ | ||
323 | | RX_CFG_ENABLE_ANY_BSSID) | ||
324 | |||
325 | #define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ | ||
326 | RX_CFG_ENABLE_ANY_BSSID) | ||
327 | |||
328 | #define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ | ||
329 | | RX_CFG_ENABLE_ONLY_MY_BSSID) | ||
330 | |||
331 | #define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ | ||
332 | | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ | ||
333 | | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) | ||
334 | |||
335 | #define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) | ||
336 | |||
337 | #define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ | ||
338 | RX_CFG_ENABLE_ONLY_MY_DEST_MAC) | ||
339 | |||
340 | #define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ | ||
341 | RX_CFG_ENABLE_ONLY_MY_DEST_MAC) | ||
342 | |||
343 | #define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ | ||
344 | | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ | ||
345 | | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) | ||
346 | |||
347 | #define RX_FILTER_OPTION_FILTER_ALL 0 | ||
348 | |||
349 | #define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ | ||
350 | | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) | ||
351 | |||
352 | #define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ | ||
353 | | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ | ||
354 | | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ | ||
355 | | CFG_RX_PRSP_EN) | ||
356 | |||
357 | |||
358 | /*=============================================== | ||
359 | EEPROM Read/Write Request 32bit RW | ||
360 | ------------------------------------------ | ||
361 | 1 EE_READ - EEPROM Read Request 1 - Setting this bit | ||
362 | loads a single byte of data into the EE_DATA | ||
363 | register from the EEPROM location specified in | ||
364 | the EE_ADDR register. | ||
365 | The Wlan hardware hardware clears this bit automatically. | ||
366 | EE_DATA is valid when this bit is cleared. | ||
367 | |||
368 | 0 EE_WRITE - EEPROM Write Request - Setting this bit | ||
369 | writes a single byte of data from the EE_DATA register into the | ||
370 | EEPROM location specified in the EE_ADDR register. | ||
371 | The Wlan hardware hardware clears this bit automatically. | ||
372 | *===============================================*/ | ||
373 | #define ACX_EE_CTL_REG EE_CTL | ||
374 | #define EE_WRITE 0x00000001ul | ||
375 | #define EE_READ 0x00000002ul | ||
376 | |||
377 | /*=============================================== | ||
378 | EEPROM Address - 32bit RW | ||
379 | ------------------------------------------ | ||
380 | This register specifies the address | ||
381 | within the EEPROM from/to which to read/write data. | ||
382 | ===============================================*/ | ||
383 | #define ACX_EE_ADDR_REG EE_ADDR | ||
384 | |||
385 | /*=============================================== | ||
386 | EEPROM Data - 32bit RW | ||
387 | ------------------------------------------ | ||
388 | This register either holds the read 8 bits of | ||
389 | data from the EEPROM or the write data | ||
390 | to be written to the EEPROM. | ||
391 | ===============================================*/ | ||
392 | #define ACX_EE_DATA_REG EE_DATA | ||
393 | |||
394 | /*=============================================== | ||
395 | EEPROM Base Address - 32bit RW | ||
396 | ------------------------------------------ | ||
397 | This register holds the upper nine bits | ||
398 | [23:15] of the 24-bit Wlan hardware memory | ||
399 | address for burst reads from EEPROM accesses. | ||
400 | The EEPROM provides the lower 15 bits of this address. | ||
401 | The MSB of the address from the EEPROM is ignored. | ||
402 | ===============================================*/ | ||
403 | #define ACX_EE_CFG EE_CFG | ||
404 | |||
405 | /*=============================================== | ||
406 | GPIO Output Values -32bit, RW | ||
407 | ------------------------------------------ | ||
408 | [31:16] Reserved | ||
409 | [15: 0] Specify the output values (at the output driver inputs) for | ||
410 | GPIO[15:0], respectively. | ||
411 | ===============================================*/ | ||
412 | #define ACX_GPIO_OUT_REG GPIO_OUT | ||
413 | #define ACX_MAX_GPIO_LINES 15 | ||
414 | |||
415 | /*=============================================== | ||
416 | Contention window -32bit, RW | ||
417 | ------------------------------------------ | ||
418 | [31:26] Reserved | ||
419 | [25:16] Max (0x3ff) | ||
420 | [15:07] Reserved | ||
421 | [06:00] Current contention window value - default is 0x1F | ||
422 | ===============================================*/ | ||
423 | #define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG | ||
424 | #define ACX_CONT_WIND_MIN_MASK 0x0000007f | ||
425 | #define ACX_CONT_WIND_MAX 0x03ff0000 | ||
426 | |||
427 | /*=============================================== | ||
428 | HI_CFG Interface Configuration Register Values | ||
429 | ------------------------------------------ | ||
430 | ===============================================*/ | ||
431 | #define HI_CFG_UART_ENABLE 0x00000004 | ||
432 | #define HI_CFG_RST232_ENABLE 0x00000008 | ||
433 | #define HI_CFG_CLOCK_REQ_SELECT 0x00000010 | ||
434 | #define HI_CFG_HOST_INT_ENABLE 0x00000020 | ||
435 | #define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 | ||
436 | #define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 | ||
437 | #define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 | ||
438 | #define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 | ||
439 | #define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 | ||
440 | |||
441 | /* | ||
442 | * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile | ||
443 | * for platforms using active high interrupt level | ||
444 | */ | ||
445 | #ifdef USE_ACTIVE_HIGH | ||
446 | #define HI_CFG_DEF_VAL \ | ||
447 | (HI_CFG_UART_ENABLE | \ | ||
448 | HI_CFG_RST232_ENABLE | \ | ||
449 | HI_CFG_CLOCK_REQ_SELECT | \ | ||
450 | HI_CFG_HOST_INT_ENABLE) | ||
451 | #else | ||
452 | #define HI_CFG_DEF_VAL \ | ||
453 | (HI_CFG_UART_ENABLE | \ | ||
454 | HI_CFG_RST232_ENABLE | \ | ||
455 | HI_CFG_CLOCK_REQ_SELECT | \ | ||
456 | HI_CFG_HOST_INT_ENABLE) | ||
457 | |||
458 | #endif | ||
459 | |||
460 | #define REF_FREQ_19_2 0 | ||
461 | #define REF_FREQ_26_0 1 | ||
462 | #define REF_FREQ_38_4 2 | ||
463 | #define REF_FREQ_40_0 3 | ||
464 | #define REF_FREQ_33_6 4 | ||
465 | #define REF_FREQ_NUM 5 | ||
466 | |||
467 | #define LUT_PARAM_INTEGER_DIVIDER 0 | ||
468 | #define LUT_PARAM_FRACTIONAL_DIVIDER 1 | ||
469 | #define LUT_PARAM_ATTN_BB 2 | ||
470 | #define LUT_PARAM_ALPHA_BB 3 | ||
471 | #define LUT_PARAM_STOP_TIME_BB 4 | ||
472 | #define LUT_PARAM_BB_PLL_LOOP_FILTER 5 | ||
473 | #define LUT_PARAM_NUM 6 | ||
474 | |||
475 | #define ACX_EEPROMLESS_IND_REG (SCR_PAD4) | ||
476 | #define USE_EEPROM 0 | ||
477 | #define SOFT_RESET_MAX_TIME 1000000 | ||
478 | #define SOFT_RESET_STALL_TIME 1000 | ||
479 | #define NVS_DATA_BUNDARY_ALIGNMENT 4 | ||
480 | |||
481 | |||
482 | /* Firmware image load chunk size */ | ||
483 | #define CHUNK_SIZE 512 | ||
484 | |||
485 | /* Firmware image header size */ | ||
486 | #define FW_HDR_SIZE 8 | ||
487 | |||
488 | #define ECPU_CONTROL_HALT 0x00000101 | ||
489 | |||
490 | |||
491 | /****************************************************************************** | ||
492 | |||
493 | CHANNELS, BAND & REG DOMAINS definitions | ||
494 | |||
495 | ******************************************************************************/ | ||
496 | |||
497 | |||
498 | enum { | ||
499 | RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ | ||
500 | RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ | ||
501 | RADIO_BAND_JAPAN_4_9_GHZ = 2, | ||
502 | DEFAULT_BAND = RADIO_BAND_2_4GHZ, | ||
503 | INVALID_BAND = 0xFE, | ||
504 | MAX_RADIO_BANDS = 0xFF | ||
505 | }; | ||
506 | |||
507 | enum { | ||
508 | NO_RATE = 0, | ||
509 | RATE_1MBPS = 0x0A, | ||
510 | RATE_2MBPS = 0x14, | ||
511 | RATE_5_5MBPS = 0x37, | ||
512 | RATE_6MBPS = 0x0B, | ||
513 | RATE_9MBPS = 0x0F, | ||
514 | RATE_11MBPS = 0x6E, | ||
515 | RATE_12MBPS = 0x0A, | ||
516 | RATE_18MBPS = 0x0E, | ||
517 | RATE_22MBPS = 0xDC, | ||
518 | RATE_24MBPS = 0x09, | ||
519 | RATE_36MBPS = 0x0D, | ||
520 | RATE_48MBPS = 0x08, | ||
521 | RATE_54MBPS = 0x0C | ||
522 | }; | ||
523 | |||
524 | enum { | ||
525 | RATE_INDEX_1MBPS = 0, | ||
526 | RATE_INDEX_2MBPS = 1, | ||
527 | RATE_INDEX_5_5MBPS = 2, | ||
528 | RATE_INDEX_6MBPS = 3, | ||
529 | RATE_INDEX_9MBPS = 4, | ||
530 | RATE_INDEX_11MBPS = 5, | ||
531 | RATE_INDEX_12MBPS = 6, | ||
532 | RATE_INDEX_18MBPS = 7, | ||
533 | RATE_INDEX_22MBPS = 8, | ||
534 | RATE_INDEX_24MBPS = 9, | ||
535 | RATE_INDEX_36MBPS = 10, | ||
536 | RATE_INDEX_48MBPS = 11, | ||
537 | RATE_INDEX_54MBPS = 12, | ||
538 | RATE_INDEX_MAX = RATE_INDEX_54MBPS, | ||
539 | MAX_RATE_INDEX, | ||
540 | INVALID_RATE_INDEX = MAX_RATE_INDEX, | ||
541 | RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF | ||
542 | }; | ||
543 | |||
544 | enum { | ||
545 | RATE_MASK_1MBPS = 0x1, | ||
546 | RATE_MASK_2MBPS = 0x2, | ||
547 | RATE_MASK_5_5MBPS = 0x4, | ||
548 | RATE_MASK_11MBPS = 0x20, | ||
549 | }; | ||
550 | |||
551 | #define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ | ||
552 | #define OFDM_RATE_BIT BIT(6) | ||
553 | #define PBCC_RATE_BIT BIT(7) | ||
554 | |||
555 | enum { | ||
556 | CCK_LONG = 0, | ||
557 | CCK_SHORT = SHORT_PREAMBLE_BIT, | ||
558 | PBCC_LONG = PBCC_RATE_BIT, | ||
559 | PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, | ||
560 | OFDM = OFDM_RATE_BIT | ||
561 | }; | ||
562 | |||
563 | /****************************************************************************** | ||
564 | |||
565 | Transmit-Descriptor RATE-SET field definitions... | ||
566 | |||
567 | Define a new "Rate-Set" for TX path that incorporates the | ||
568 | Rate & Modulation info into a single 16-bit field. | ||
569 | |||
570 | TxdRateSet_t: | ||
571 | b15 - Indicates Preamble type (1=SHORT, 0=LONG). | ||
572 | Notes: | ||
573 | Must be LONG (0) for 1Mbps rate. | ||
574 | Does not apply (set to 0) for RevG-OFDM rates. | ||
575 | b14 - Indicates PBCC encoding (1=PBCC, 0=not). | ||
576 | Notes: | ||
577 | Does not apply (set to 0) for rates 1 and 2 Mbps. | ||
578 | Does not apply (set to 0) for RevG-OFDM rates. | ||
579 | b13 - Unused (set to 0). | ||
580 | b12-b0 - Supported Rate indicator bits as defined below. | ||
581 | |||
582 | ******************************************************************************/ | ||
583 | |||
584 | |||
585 | /************************************************************************* | ||
586 | |||
587 | Interrupt Trigger Register (Host -> WiLink) | ||
588 | |||
589 | **************************************************************************/ | ||
590 | |||
591 | /* Hardware to Embedded CPU Interrupts - first 32-bit register set */ | ||
592 | |||
593 | /* | ||
594 | * Host Command Interrupt. Setting this bit masks | ||
595 | * the interrupt that the host issues to inform | ||
596 | * the FW that it has sent a command | ||
597 | * to the Wlan hardware Command Mailbox. | ||
598 | */ | ||
599 | #define INTR_TRIG_CMD BIT(0) | ||
600 | |||
601 | /* | ||
602 | * Host Event Acknowlegde Interrupt. The host | ||
603 | * sets this bit to acknowledge that it received | ||
604 | * the unsolicited information from the event | ||
605 | * mailbox. | ||
606 | */ | ||
607 | #define INTR_TRIG_EVENT_ACK BIT(1) | ||
608 | |||
609 | /* | ||
610 | * The host sets this bit to inform the Wlan | ||
611 | * FW that a TX packet is in the XFER | ||
612 | * Buffer #0. | ||
613 | */ | ||
614 | #define INTR_TRIG_TX_PROC0 BIT(2) | ||
615 | |||
616 | /* | ||
617 | * The host sets this bit to inform the FW | ||
618 | * that it read a packet from RX XFER | ||
619 | * Buffer #0. | ||
620 | */ | ||
621 | #define INTR_TRIG_RX_PROC0 BIT(3) | ||
622 | |||
623 | #define INTR_TRIG_DEBUG_ACK BIT(4) | ||
624 | |||
625 | #define INTR_TRIG_STATE_CHANGED BIT(5) | ||
626 | |||
627 | |||
628 | /* Hardware to Embedded CPU Interrupts - second 32-bit register set */ | ||
629 | |||
630 | /* | ||
631 | * The host sets this bit to inform the FW | ||
632 | * that it read a packet from RX XFER | ||
633 | * Buffer #1. | ||
634 | */ | ||
635 | #define INTR_TRIG_RX_PROC1 BIT(17) | ||
636 | |||
637 | /* | ||
638 | * The host sets this bit to inform the Wlan | ||
639 | * hardware that a TX packet is in the XFER | ||
640 | * Buffer #1. | ||
641 | */ | ||
642 | #define INTR_TRIG_TX_PROC1 BIT(18) | ||
643 | |||
644 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index 0dbb483a0973..17c54b59ef86 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c | |||
@@ -26,9 +26,10 @@ | |||
26 | #include <net/mac80211.h> | 26 | #include <net/mac80211.h> |
27 | 27 | ||
28 | #include "wl1251.h" | 28 | #include "wl1251.h" |
29 | #include "reg.h" | 29 | #include "wl1251_reg.h" |
30 | #include "wl1251_spi.h" | 30 | #include "wl1251_io.h" |
31 | #include "wl1251_rx.h" | 31 | #include "wl1251_rx.h" |
32 | #include "wl1251_cmd.h" | ||
32 | #include "wl1251_acx.h" | 33 | #include "wl1251_acx.h" |
33 | 34 | ||
34 | static void wl1251_rx_header(struct wl1251 *wl, | 35 | static void wl1251_rx_header(struct wl1251 *wl, |
@@ -40,7 +41,7 @@ static void wl1251_rx_header(struct wl1251 *wl, | |||
40 | if (wl->rx_current_buffer) | 41 | if (wl->rx_current_buffer) |
41 | rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; | 42 | rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; |
42 | 43 | ||
43 | wl1251_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); | 44 | wl1251_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); |
44 | } | 45 | } |
45 | 46 | ||
46 | static void wl1251_rx_status(struct wl1251 *wl, | 47 | static void wl1251_rx_status(struct wl1251 *wl, |
@@ -136,7 +137,7 @@ static void wl1251_rx_body(struct wl1251 *wl, | |||
136 | } | 137 | } |
137 | 138 | ||
138 | rx_buffer = skb_put(skb, length); | 139 | rx_buffer = skb_put(skb, length); |
139 | wl1251_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); | 140 | wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); |
140 | 141 | ||
141 | /* The actual lenght doesn't include the target's alignment */ | 142 | /* The actual lenght doesn't include the target's alignment */ |
142 | skb->len = desc->length - PLCP_HEADER_LENGTH; | 143 | skb->len = desc->length - PLCP_HEADER_LENGTH; |
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c new file mode 100644 index 000000000000..9423f22bdced --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | * wl12xx SDIO routines | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
11 | * General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
16 | * 02110-1301 USA | ||
17 | * | ||
18 | * Copyright (C) 2005 Texas Instruments Incorporated | ||
19 | * Copyright (C) 2008 Google Inc | ||
20 | * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com) | ||
21 | */ | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/crc7.h> | ||
24 | #include <linux/mod_devicetable.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/mmc/sdio_func.h> | ||
27 | #include <linux/mmc/sdio_ids.h> | ||
28 | #include <linux/platform_device.h> | ||
29 | |||
30 | #include "wl1251.h" | ||
31 | #include "wl12xx_80211.h" | ||
32 | #include "wl1251_reg.h" | ||
33 | #include "wl1251_ps.h" | ||
34 | #include "wl1251_io.h" | ||
35 | #include "wl1251_tx.h" | ||
36 | #include "wl1251_debugfs.h" | ||
37 | |||
38 | #ifndef SDIO_VENDOR_ID_TI | ||
39 | #define SDIO_VENDOR_ID_TI 0x104c | ||
40 | #endif | ||
41 | |||
42 | #ifndef SDIO_DEVICE_ID_TI_WL1251 | ||
43 | #define SDIO_DEVICE_ID_TI_WL1251 0x9066 | ||
44 | #endif | ||
45 | |||
46 | static struct sdio_func *wl_to_func(struct wl1251 *wl) | ||
47 | { | ||
48 | return wl->if_priv; | ||
49 | } | ||
50 | |||
51 | static void wl1251_sdio_interrupt(struct sdio_func *func) | ||
52 | { | ||
53 | struct wl1251 *wl = sdio_get_drvdata(func); | ||
54 | |||
55 | wl1251_debug(DEBUG_IRQ, "IRQ"); | ||
56 | |||
57 | /* FIXME should be synchronous for sdio */ | ||
58 | ieee80211_queue_work(wl->hw, &wl->irq_work); | ||
59 | } | ||
60 | |||
61 | static const struct sdio_device_id wl1251_devices[] = { | ||
62 | { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1251) }, | ||
63 | {} | ||
64 | }; | ||
65 | MODULE_DEVICE_TABLE(sdio, wl1251_devices); | ||
66 | |||
67 | |||
68 | void wl1251_sdio_read(struct wl1251 *wl, int addr, void *buf, size_t len) | ||
69 | { | ||
70 | int ret; | ||
71 | struct sdio_func *func = wl_to_func(wl); | ||
72 | |||
73 | sdio_claim_host(func); | ||
74 | ret = sdio_memcpy_fromio(func, buf, addr, len); | ||
75 | if (ret) | ||
76 | wl1251_error("sdio read failed (%d)", ret); | ||
77 | sdio_release_host(func); | ||
78 | } | ||
79 | |||
80 | void wl1251_sdio_write(struct wl1251 *wl, int addr, void *buf, size_t len) | ||
81 | { | ||
82 | int ret; | ||
83 | struct sdio_func *func = wl_to_func(wl); | ||
84 | |||
85 | sdio_claim_host(func); | ||
86 | ret = sdio_memcpy_toio(func, addr, buf, len); | ||
87 | if (ret) | ||
88 | wl1251_error("sdio write failed (%d)", ret); | ||
89 | sdio_release_host(func); | ||
90 | } | ||
91 | |||
92 | void wl1251_sdio_reset(struct wl1251 *wl) | ||
93 | { | ||
94 | } | ||
95 | |||
96 | static void wl1251_sdio_enable_irq(struct wl1251 *wl) | ||
97 | { | ||
98 | struct sdio_func *func = wl_to_func(wl); | ||
99 | |||
100 | sdio_claim_host(func); | ||
101 | sdio_claim_irq(func, wl1251_sdio_interrupt); | ||
102 | sdio_release_host(func); | ||
103 | } | ||
104 | |||
105 | static void wl1251_sdio_disable_irq(struct wl1251 *wl) | ||
106 | { | ||
107 | struct sdio_func *func = wl_to_func(wl); | ||
108 | |||
109 | sdio_claim_host(func); | ||
110 | sdio_release_irq(func); | ||
111 | sdio_release_host(func); | ||
112 | } | ||
113 | |||
114 | void wl1251_sdio_set_power(bool enable) | ||
115 | { | ||
116 | } | ||
117 | |||
118 | struct wl1251_if_operations wl1251_sdio_ops = { | ||
119 | .read = wl1251_sdio_read, | ||
120 | .write = wl1251_sdio_write, | ||
121 | .reset = wl1251_sdio_reset, | ||
122 | .enable_irq = wl1251_sdio_enable_irq, | ||
123 | .disable_irq = wl1251_sdio_disable_irq, | ||
124 | }; | ||
125 | |||
126 | int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) | ||
127 | { | ||
128 | int ret; | ||
129 | struct wl1251 *wl; | ||
130 | struct ieee80211_hw *hw; | ||
131 | |||
132 | hw = wl1251_alloc_hw(); | ||
133 | if (IS_ERR(hw)) | ||
134 | return PTR_ERR(hw); | ||
135 | |||
136 | wl = hw->priv; | ||
137 | |||
138 | sdio_claim_host(func); | ||
139 | ret = sdio_enable_func(func); | ||
140 | if (ret) | ||
141 | goto release; | ||
142 | |||
143 | sdio_set_block_size(func, 512); | ||
144 | |||
145 | SET_IEEE80211_DEV(hw, &func->dev); | ||
146 | wl->if_priv = func; | ||
147 | wl->if_ops = &wl1251_sdio_ops; | ||
148 | wl->set_power = wl1251_sdio_set_power; | ||
149 | |||
150 | sdio_release_host(func); | ||
151 | ret = wl1251_init_ieee80211(wl); | ||
152 | if (ret) | ||
153 | goto disable; | ||
154 | |||
155 | sdio_set_drvdata(func, wl); | ||
156 | return ret; | ||
157 | |||
158 | disable: | ||
159 | sdio_claim_host(func); | ||
160 | sdio_disable_func(func); | ||
161 | release: | ||
162 | sdio_release_host(func); | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | static void __devexit wl1251_sdio_remove(struct sdio_func *func) | ||
167 | { | ||
168 | struct wl1251 *wl = sdio_get_drvdata(func); | ||
169 | |||
170 | wl1251_free_hw(wl); | ||
171 | |||
172 | sdio_claim_host(func); | ||
173 | sdio_release_irq(func); | ||
174 | sdio_disable_func(func); | ||
175 | sdio_release_host(func); | ||
176 | } | ||
177 | |||
178 | static struct sdio_driver wl1251_sdio_driver = { | ||
179 | .name = "wl1251_sdio", | ||
180 | .id_table = wl1251_devices, | ||
181 | .probe = wl1251_sdio_probe, | ||
182 | .remove = __devexit_p(wl1251_sdio_remove), | ||
183 | }; | ||
184 | |||
185 | static int __init wl1251_sdio_init(void) | ||
186 | { | ||
187 | int err; | ||
188 | |||
189 | err = sdio_register_driver(&wl1251_sdio_driver); | ||
190 | if (err) | ||
191 | wl1251_error("failed to register sdio driver: %d", err); | ||
192 | return err; | ||
193 | } | ||
194 | |||
195 | static void __exit wl1251_sdio_exit(void) | ||
196 | { | ||
197 | sdio_unregister_driver(&wl1251_sdio_driver); | ||
198 | wl1251_notice("unloaded"); | ||
199 | } | ||
200 | |||
201 | module_init(wl1251_sdio_init); | ||
202 | module_exit(wl1251_sdio_exit); | ||
203 | |||
204 | MODULE_LICENSE("GPL"); | ||
205 | MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>"); | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index c5da79dbc49c..14eff2b3d4c6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c | |||
@@ -21,38 +21,35 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/irq.h> | ||
24 | #include <linux/module.h> | 25 | #include <linux/module.h> |
25 | #include <linux/crc7.h> | 26 | #include <linux/crc7.h> |
26 | #include <linux/spi/spi.h> | 27 | #include <linux/spi/spi.h> |
28 | #include <linux/spi/wl12xx.h> | ||
27 | 29 | ||
28 | #include "wl1251.h" | 30 | #include "wl1251.h" |
29 | #include "reg.h" | 31 | #include "wl1251_reg.h" |
30 | #include "wl1251_spi.h" | 32 | #include "wl1251_spi.h" |
31 | 33 | ||
32 | static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) | 34 | static irqreturn_t wl1251_irq(int irq, void *cookie) |
33 | { | 35 | { |
34 | /* If the address is lower than REGISTERS_BASE, it means that this is | 36 | struct wl1251 *wl; |
35 | * a chip-specific register address, so look it up in the registers | 37 | |
36 | * table */ | 38 | wl1251_debug(DEBUG_IRQ, "IRQ"); |
37 | if (addr < REGISTERS_BASE) { | 39 | |
38 | /* Make sure we don't go over the table */ | 40 | wl = cookie; |
39 | if (addr >= ACX_REG_TABLE_LEN) { | ||
40 | wl1251_error("address out of range (%d)", addr); | ||
41 | return -EINVAL; | ||
42 | } | ||
43 | addr = wl->chip.acx_reg_table[addr]; | ||
44 | } | ||
45 | 41 | ||
46 | return addr - wl->physical_reg_addr + wl->virtual_reg_addr; | 42 | ieee80211_queue_work(wl->hw, &wl->irq_work); |
43 | |||
44 | return IRQ_HANDLED; | ||
47 | } | 45 | } |
48 | 46 | ||
49 | static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) | 47 | static struct spi_device *wl_to_spi(struct wl1251 *wl) |
50 | { | 48 | { |
51 | return addr - wl->physical_mem_addr + wl->virtual_mem_addr; | 49 | return wl->if_priv; |
52 | } | 50 | } |
53 | 51 | ||
54 | 52 | static void wl1251_spi_reset(struct wl1251 *wl) | |
55 | void wl1251_spi_reset(struct wl1251 *wl) | ||
56 | { | 53 | { |
57 | u8 *cmd; | 54 | u8 *cmd; |
58 | struct spi_transfer t; | 55 | struct spi_transfer t; |
@@ -73,12 +70,12 @@ void wl1251_spi_reset(struct wl1251 *wl) | |||
73 | t.len = WSPI_INIT_CMD_LEN; | 70 | t.len = WSPI_INIT_CMD_LEN; |
74 | spi_message_add_tail(&t, &m); | 71 | spi_message_add_tail(&t, &m); |
75 | 72 | ||
76 | spi_sync(wl->spi, &m); | 73 | spi_sync(wl_to_spi(wl), &m); |
77 | 74 | ||
78 | wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); | 75 | wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); |
79 | } | 76 | } |
80 | 77 | ||
81 | void wl1251_spi_init(struct wl1251 *wl) | 78 | static void wl1251_spi_wake(struct wl1251 *wl) |
82 | { | 79 | { |
83 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; | 80 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; |
84 | struct spi_transfer t; | 81 | struct spi_transfer t; |
@@ -127,136 +124,19 @@ void wl1251_spi_init(struct wl1251 *wl) | |||
127 | t.len = WSPI_INIT_CMD_LEN; | 124 | t.len = WSPI_INIT_CMD_LEN; |
128 | spi_message_add_tail(&t, &m); | 125 | spi_message_add_tail(&t, &m); |
129 | 126 | ||
130 | spi_sync(wl->spi, &m); | 127 | spi_sync(wl_to_spi(wl), &m); |
131 | 128 | ||
132 | wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); | 129 | wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); |
133 | } | 130 | } |
134 | 131 | ||
135 | /* Set the SPI partitions to access the chip addresses | 132 | static void wl1251_spi_reset_wake(struct wl1251 *wl) |
136 | * | ||
137 | * There are two VIRTUAL (SPI) partitions (the memory partition and the | ||
138 | * registers partition), which are mapped to two different areas of the | ||
139 | * PHYSICAL (hardware) memory. This function also makes other checks to | ||
140 | * ensure that the partitions are not overlapping. In the diagram below, the | ||
141 | * memory partition comes before the register partition, but the opposite is | ||
142 | * also supported. | ||
143 | * | ||
144 | * PHYSICAL address | ||
145 | * space | ||
146 | * | ||
147 | * | | | ||
148 | * ...+----+--> mem_start | ||
149 | * VIRTUAL address ... | | | ||
150 | * space ... | | [PART_0] | ||
151 | * ... | | | ||
152 | * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size | ||
153 | * | | ... | | | ||
154 | * |MEM | ... | | | ||
155 | * | | ... | | | ||
156 | * part_size <--+----+... | | {unused area) | ||
157 | * | | ... | | | ||
158 | * |REG | ... | | | ||
159 | * part_size | | ... | | | ||
160 | * + <--+----+... ...+----+--> reg_start | ||
161 | * reg_size ... | | | ||
162 | * ... | | [PART_1] | ||
163 | * ... | | | ||
164 | * ...+----+--> reg_start + reg_size | ||
165 | * | | | ||
166 | * | ||
167 | */ | ||
168 | int wl1251_set_partition(struct wl1251 *wl, | ||
169 | u32 mem_start, u32 mem_size, | ||
170 | u32 reg_start, u32 reg_size) | ||
171 | { | 133 | { |
172 | struct wl1251_partition *partition; | 134 | wl1251_spi_reset(wl); |
173 | struct spi_transfer t; | 135 | wl1251_spi_wake(wl); |
174 | struct spi_message m; | ||
175 | size_t len, cmd_len; | ||
176 | u32 *cmd; | ||
177 | int addr; | ||
178 | |||
179 | cmd_len = sizeof(u32) + 2 * sizeof(struct wl1251_partition); | ||
180 | cmd = kzalloc(cmd_len, GFP_KERNEL); | ||
181 | if (!cmd) | ||
182 | return -ENOMEM; | ||
183 | |||
184 | spi_message_init(&m); | ||
185 | memset(&t, 0, sizeof(t)); | ||
186 | |||
187 | partition = (struct wl1251_partition *) (cmd + 1); | ||
188 | addr = HW_ACCESS_PART0_SIZE_ADDR; | ||
189 | len = 2 * sizeof(struct wl1251_partition); | ||
190 | |||
191 | *cmd |= WSPI_CMD_WRITE; | ||
192 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
193 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
194 | |||
195 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
196 | mem_start, mem_size); | ||
197 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
198 | reg_start, reg_size); | ||
199 | |||
200 | /* Make sure that the two partitions together don't exceed the | ||
201 | * address range */ | ||
202 | if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { | ||
203 | wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" | ||
204 | " address range. Truncating partition[0]."); | ||
205 | mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; | ||
206 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
207 | mem_start, mem_size); | ||
208 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
209 | reg_start, reg_size); | ||
210 | } | ||
211 | |||
212 | if ((mem_start < reg_start) && | ||
213 | ((mem_start + mem_size) > reg_start)) { | ||
214 | /* Guarantee that the memory partition doesn't overlap the | ||
215 | * registers partition */ | ||
216 | wl1251_debug(DEBUG_SPI, "End of partition[0] is " | ||
217 | "overlapping partition[1]. Adjusted."); | ||
218 | mem_size = reg_start - mem_start; | ||
219 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
220 | mem_start, mem_size); | ||
221 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
222 | reg_start, reg_size); | ||
223 | } else if ((reg_start < mem_start) && | ||
224 | ((reg_start + reg_size) > mem_start)) { | ||
225 | /* Guarantee that the register partition doesn't overlap the | ||
226 | * memory partition */ | ||
227 | wl1251_debug(DEBUG_SPI, "End of partition[1] is" | ||
228 | " overlapping partition[0]. Adjusted."); | ||
229 | reg_size = mem_start - reg_start; | ||
230 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
231 | mem_start, mem_size); | ||
232 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
233 | reg_start, reg_size); | ||
234 | } | ||
235 | |||
236 | partition[0].start = mem_start; | ||
237 | partition[0].size = mem_size; | ||
238 | partition[1].start = reg_start; | ||
239 | partition[1].size = reg_size; | ||
240 | |||
241 | wl->physical_mem_addr = mem_start; | ||
242 | wl->physical_reg_addr = reg_start; | ||
243 | |||
244 | wl->virtual_mem_addr = 0; | ||
245 | wl->virtual_reg_addr = mem_size; | ||
246 | |||
247 | t.tx_buf = cmd; | ||
248 | t.len = cmd_len; | ||
249 | spi_message_add_tail(&t, &m); | ||
250 | |||
251 | spi_sync(wl->spi, &m); | ||
252 | |||
253 | kfree(cmd); | ||
254 | |||
255 | return 0; | ||
256 | } | 136 | } |
257 | 137 | ||
258 | void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, | 138 | static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, |
259 | size_t len, bool fixed) | 139 | size_t len) |
260 | { | 140 | { |
261 | struct spi_transfer t[3]; | 141 | struct spi_transfer t[3]; |
262 | struct spi_message m; | 142 | struct spi_message m; |
@@ -271,9 +151,6 @@ void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, | |||
271 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | 151 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; |
272 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | 152 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; |
273 | 153 | ||
274 | if (fixed) | ||
275 | *cmd |= WSPI_CMD_FIXED; | ||
276 | |||
277 | spi_message_init(&m); | 154 | spi_message_init(&m); |
278 | memset(t, 0, sizeof(t)); | 155 | memset(t, 0, sizeof(t)); |
279 | 156 | ||
@@ -290,7 +167,7 @@ void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, | |||
290 | t[2].len = len; | 167 | t[2].len = len; |
291 | spi_message_add_tail(&t[2], &m); | 168 | spi_message_add_tail(&t[2], &m); |
292 | 169 | ||
293 | spi_sync(wl->spi, &m); | 170 | spi_sync(wl_to_spi(wl), &m); |
294 | 171 | ||
295 | /* FIXME: check busy words */ | 172 | /* FIXME: check busy words */ |
296 | 173 | ||
@@ -298,8 +175,8 @@ void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, | |||
298 | wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); | 175 | wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); |
299 | } | 176 | } |
300 | 177 | ||
301 | void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, | 178 | static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, |
302 | size_t len, bool fixed) | 179 | size_t len) |
303 | { | 180 | { |
304 | struct spi_transfer t[2]; | 181 | struct spi_transfer t[2]; |
305 | struct spi_message m; | 182 | struct spi_message m; |
@@ -312,9 +189,6 @@ void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, | |||
312 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | 189 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; |
313 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | 190 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; |
314 | 191 | ||
315 | if (fixed) | ||
316 | *cmd |= WSPI_CMD_FIXED; | ||
317 | |||
318 | spi_message_init(&m); | 192 | spi_message_init(&m); |
319 | memset(t, 0, sizeof(t)); | 193 | memset(t, 0, sizeof(t)); |
320 | 194 | ||
@@ -326,68 +200,145 @@ void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, | |||
326 | t[1].len = len; | 200 | t[1].len = len; |
327 | spi_message_add_tail(&t[1], &m); | 201 | spi_message_add_tail(&t[1], &m); |
328 | 202 | ||
329 | spi_sync(wl->spi, &m); | 203 | spi_sync(wl_to_spi(wl), &m); |
330 | 204 | ||
331 | wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); | 205 | wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); |
332 | wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); | 206 | wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); |
333 | } | 207 | } |
334 | 208 | ||
335 | void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, | 209 | static void wl1251_spi_enable_irq(struct wl1251 *wl) |
336 | size_t len) | ||
337 | { | 210 | { |
338 | int physical; | 211 | return enable_irq(wl->irq); |
339 | 212 | } | |
340 | physical = wl1251_translate_mem_addr(wl, addr); | ||
341 | 213 | ||
342 | wl1251_spi_read(wl, physical, buf, len, false); | 214 | static void wl1251_spi_disable_irq(struct wl1251 *wl) |
215 | { | ||
216 | return disable_irq(wl->irq); | ||
343 | } | 217 | } |
344 | 218 | ||
345 | void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, | 219 | static const struct wl1251_if_operations wl1251_spi_ops = { |
346 | size_t len) | 220 | .read = wl1251_spi_read, |
221 | .write = wl1251_spi_write, | ||
222 | .reset = wl1251_spi_reset_wake, | ||
223 | .enable_irq = wl1251_spi_enable_irq, | ||
224 | .disable_irq = wl1251_spi_disable_irq, | ||
225 | }; | ||
226 | |||
227 | static int __devinit wl1251_spi_probe(struct spi_device *spi) | ||
347 | { | 228 | { |
348 | int physical; | 229 | struct wl12xx_platform_data *pdata; |
230 | struct ieee80211_hw *hw; | ||
231 | struct wl1251 *wl; | ||
232 | int ret; | ||
233 | |||
234 | pdata = spi->dev.platform_data; | ||
235 | if (!pdata) { | ||
236 | wl1251_error("no platform data"); | ||
237 | return -ENODEV; | ||
238 | } | ||
349 | 239 | ||
350 | physical = wl1251_translate_mem_addr(wl, addr); | 240 | hw = wl1251_alloc_hw(); |
241 | if (IS_ERR(hw)) | ||
242 | return PTR_ERR(hw); | ||
351 | 243 | ||
352 | wl1251_spi_write(wl, physical, buf, len, false); | 244 | wl = hw->priv; |
353 | } | ||
354 | 245 | ||
355 | void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len, | 246 | SET_IEEE80211_DEV(hw, &spi->dev); |
356 | bool fixed) | 247 | dev_set_drvdata(&spi->dev, wl); |
357 | { | 248 | wl->if_priv = spi; |
358 | int physical; | 249 | wl->if_ops = &wl1251_spi_ops; |
359 | 250 | ||
360 | physical = wl1251_translate_reg_addr(wl, addr); | 251 | /* This is the only SPI value that we need to set here, the rest |
252 | * comes from the board-peripherals file */ | ||
253 | spi->bits_per_word = 32; | ||
361 | 254 | ||
362 | wl1251_spi_read(wl, physical, buf, len, fixed); | 255 | ret = spi_setup(spi); |
363 | } | 256 | if (ret < 0) { |
257 | wl1251_error("spi_setup failed"); | ||
258 | goto out_free; | ||
259 | } | ||
364 | 260 | ||
365 | void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len, | 261 | wl->set_power = pdata->set_power; |
366 | bool fixed) | 262 | if (!wl->set_power) { |
367 | { | 263 | wl1251_error("set power function missing in platform data"); |
368 | int physical; | 264 | return -ENODEV; |
265 | } | ||
369 | 266 | ||
370 | physical = wl1251_translate_reg_addr(wl, addr); | 267 | wl->irq = spi->irq; |
268 | if (wl->irq < 0) { | ||
269 | wl1251_error("irq missing in platform data"); | ||
270 | return -ENODEV; | ||
271 | } | ||
371 | 272 | ||
372 | wl1251_spi_write(wl, physical, buf, len, fixed); | 273 | ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); |
373 | } | 274 | if (ret < 0) { |
275 | wl1251_error("request_irq() failed: %d", ret); | ||
276 | goto out_free; | ||
277 | } | ||
374 | 278 | ||
375 | u32 wl1251_mem_read32(struct wl1251 *wl, int addr) | 279 | set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); |
376 | { | 280 | |
377 | return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); | 281 | disable_irq(wl->irq); |
282 | |||
283 | ret = wl1251_init_ieee80211(wl); | ||
284 | if (ret) | ||
285 | goto out_irq; | ||
286 | |||
287 | return 0; | ||
288 | |||
289 | out_irq: | ||
290 | free_irq(wl->irq, wl); | ||
291 | |||
292 | out_free: | ||
293 | ieee80211_free_hw(hw); | ||
294 | |||
295 | return ret; | ||
378 | } | 296 | } |
379 | 297 | ||
380 | void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) | 298 | static int __devexit wl1251_spi_remove(struct spi_device *spi) |
381 | { | 299 | { |
382 | wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); | 300 | struct wl1251 *wl = dev_get_drvdata(&spi->dev); |
301 | |||
302 | free_irq(wl->irq, wl); | ||
303 | wl1251_free_hw(wl); | ||
304 | |||
305 | return 0; | ||
383 | } | 306 | } |
384 | 307 | ||
385 | u32 wl1251_reg_read32(struct wl1251 *wl, int addr) | 308 | static struct spi_driver wl1251_spi_driver = { |
309 | .driver = { | ||
310 | .name = "wl12xx", | ||
311 | .bus = &spi_bus_type, | ||
312 | .owner = THIS_MODULE, | ||
313 | }, | ||
314 | |||
315 | .probe = wl1251_spi_probe, | ||
316 | .remove = __devexit_p(wl1251_spi_remove), | ||
317 | }; | ||
318 | |||
319 | static int __init wl1251_spi_init(void) | ||
386 | { | 320 | { |
387 | return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); | 321 | int ret; |
322 | |||
323 | ret = spi_register_driver(&wl1251_spi_driver); | ||
324 | if (ret < 0) { | ||
325 | wl1251_error("failed to register spi driver: %d", ret); | ||
326 | goto out; | ||
327 | } | ||
328 | |||
329 | out: | ||
330 | return ret; | ||
388 | } | 331 | } |
389 | 332 | ||
390 | void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) | 333 | static void __exit wl1251_spi_exit(void) |
391 | { | 334 | { |
392 | wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); | 335 | spi_unregister_driver(&wl1251_spi_driver); |
336 | |||
337 | wl1251_notice("unloaded"); | ||
393 | } | 338 | } |
339 | |||
340 | module_init(wl1251_spi_init); | ||
341 | module_exit(wl1251_spi_exit); | ||
342 | |||
343 | MODULE_LICENSE("GPL"); | ||
344 | MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>"); | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index 6e8daf4e1085..2e273a97e7f3 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h | |||
@@ -27,18 +27,7 @@ | |||
27 | 27 | ||
28 | #include "wl1251_cmd.h" | 28 | #include "wl1251_cmd.h" |
29 | #include "wl1251_acx.h" | 29 | #include "wl1251_acx.h" |
30 | #include "reg.h" | 30 | #include "wl1251_reg.h" |
31 | |||
32 | #define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 | ||
33 | |||
34 | #define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 | ||
35 | #define HW_ACCESS_PART0_START_ADDR 0x1FFC4 | ||
36 | #define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 | ||
37 | #define HW_ACCESS_PART1_START_ADDR 0x1FFCC | ||
38 | |||
39 | #define HW_ACCESS_REGISTER_SIZE 4 | ||
40 | |||
41 | #define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 | ||
42 | 31 | ||
43 | #define WSPI_CMD_READ 0x40000000 | 32 | #define WSPI_CMD_READ 0x40000000 |
44 | #define WSPI_CMD_WRITE 0x00000000 | 33 | #define WSPI_CMD_WRITE 0x00000000 |
@@ -69,47 +58,4 @@ | |||
69 | ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) | 58 | ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) |
70 | #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 | 59 | #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 |
71 | 60 | ||
72 | |||
73 | /* Raw target IO, address is not translated */ | ||
74 | void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, | ||
75 | size_t len, bool fixed); | ||
76 | void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, | ||
77 | size_t len, bool fixed); | ||
78 | |||
79 | /* Memory target IO, address is tranlated to partition 0 */ | ||
80 | void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
81 | void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
82 | u32 wl1251_mem_read32(struct wl1251 *wl, int addr); | ||
83 | void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); | ||
84 | |||
85 | /* Registers IO */ | ||
86 | void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len, | ||
87 | bool fixed); | ||
88 | void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len, | ||
89 | bool fixed); | ||
90 | u32 wl1251_reg_read32(struct wl1251 *wl, int addr); | ||
91 | void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); | ||
92 | |||
93 | /* INIT and RESET words */ | ||
94 | void wl1251_spi_reset(struct wl1251 *wl); | ||
95 | void wl1251_spi_init(struct wl1251 *wl); | ||
96 | int wl1251_set_partition(struct wl1251 *wl, | ||
97 | u32 part_start, u32 part_size, | ||
98 | u32 reg_start, u32 reg_size); | ||
99 | |||
100 | static inline u32 wl1251_read32(struct wl1251 *wl, int addr) | ||
101 | { | ||
102 | wl1251_spi_read(wl, addr, &wl->buffer_32, | ||
103 | sizeof(wl->buffer_32), false); | ||
104 | |||
105 | return wl->buffer_32; | ||
106 | } | ||
107 | |||
108 | static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) | ||
109 | { | ||
110 | wl->buffer_32 = val; | ||
111 | wl1251_spi_write(wl, addr, &wl->buffer_32, | ||
112 | sizeof(wl->buffer_32), false); | ||
113 | } | ||
114 | |||
115 | #endif /* __WL1251_SPI_H__ */ | 61 | #endif /* __WL1251_SPI_H__ */ |
diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index 2652a222383a..f85970615849 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c | |||
@@ -26,10 +26,10 @@ | |||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | 27 | ||
28 | #include "wl1251.h" | 28 | #include "wl1251.h" |
29 | #include "reg.h" | 29 | #include "wl1251_reg.h" |
30 | #include "wl1251_spi.h" | ||
31 | #include "wl1251_tx.h" | 30 | #include "wl1251_tx.h" |
32 | #include "wl1251_ps.h" | 31 | #include "wl1251_ps.h" |
32 | #include "wl1251_io.h" | ||
33 | 33 | ||
34 | static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) | 34 | static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) |
35 | { | 35 | { |
@@ -235,7 +235,7 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, | |||
235 | else | 235 | else |
236 | addr = wl->data_path->tx_packet_ring_addr; | 236 | addr = wl->data_path->tx_packet_ring_addr; |
237 | 237 | ||
238 | wl1251_spi_mem_write(wl, addr, skb->data, len); | 238 | wl1251_mem_write(wl, addr, skb->data, len); |
239 | 239 | ||
240 | wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", | 240 | wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", |
241 | tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); | 241 | tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); |
@@ -451,7 +451,7 @@ void wl1251_tx_complete(struct wl1251 *wl) | |||
451 | return; | 451 | return; |
452 | 452 | ||
453 | /* First we read the result */ | 453 | /* First we read the result */ |
454 | wl1251_spi_mem_read(wl, wl->data_path->tx_complete_addr, | 454 | wl1251_mem_read(wl, wl->data_path->tx_complete_addr, |
455 | result, sizeof(result)); | 455 | result, sizeof(result)); |
456 | 456 | ||
457 | result_index = wl->next_tx_complete; | 457 | result_index = wl->next_tx_complete; |
@@ -482,41 +482,41 @@ void wl1251_tx_complete(struct wl1251 *wl) | |||
482 | */ | 482 | */ |
483 | if (result_index > wl->next_tx_complete) { | 483 | if (result_index > wl->next_tx_complete) { |
484 | /* Only 1 write is needed */ | 484 | /* Only 1 write is needed */ |
485 | wl1251_spi_mem_write(wl, | 485 | wl1251_mem_write(wl, |
486 | wl->data_path->tx_complete_addr + | 486 | wl->data_path->tx_complete_addr + |
487 | (wl->next_tx_complete * | 487 | (wl->next_tx_complete * |
488 | sizeof(struct tx_result)), | 488 | sizeof(struct tx_result)), |
489 | &result[wl->next_tx_complete], | 489 | &result[wl->next_tx_complete], |
490 | num_complete * | 490 | num_complete * |
491 | sizeof(struct tx_result)); | 491 | sizeof(struct tx_result)); |
492 | 492 | ||
493 | 493 | ||
494 | } else if (result_index < wl->next_tx_complete) { | 494 | } else if (result_index < wl->next_tx_complete) { |
495 | /* 2 writes are needed */ | 495 | /* 2 writes are needed */ |
496 | wl1251_spi_mem_write(wl, | 496 | wl1251_mem_write(wl, |
497 | wl->data_path->tx_complete_addr + | 497 | wl->data_path->tx_complete_addr + |
498 | (wl->next_tx_complete * | 498 | (wl->next_tx_complete * |
499 | sizeof(struct tx_result)), | 499 | sizeof(struct tx_result)), |
500 | &result[wl->next_tx_complete], | 500 | &result[wl->next_tx_complete], |
501 | (FW_TX_CMPLT_BLOCK_SIZE - | 501 | (FW_TX_CMPLT_BLOCK_SIZE - |
502 | wl->next_tx_complete) * | 502 | wl->next_tx_complete) * |
503 | sizeof(struct tx_result)); | 503 | sizeof(struct tx_result)); |
504 | 504 | ||
505 | wl1251_spi_mem_write(wl, | 505 | wl1251_mem_write(wl, |
506 | wl->data_path->tx_complete_addr, | 506 | wl->data_path->tx_complete_addr, |
507 | result, | 507 | result, |
508 | (num_complete - | 508 | (num_complete - |
509 | FW_TX_CMPLT_BLOCK_SIZE + | 509 | FW_TX_CMPLT_BLOCK_SIZE + |
510 | wl->next_tx_complete) * | 510 | wl->next_tx_complete) * |
511 | sizeof(struct tx_result)); | 511 | sizeof(struct tx_result)); |
512 | 512 | ||
513 | } else { | 513 | } else { |
514 | /* We have to write the whole array */ | 514 | /* We have to write the whole array */ |
515 | wl1251_spi_mem_write(wl, | 515 | wl1251_mem_write(wl, |
516 | wl->data_path->tx_complete_addr, | 516 | wl->data_path->tx_complete_addr, |
517 | result, | 517 | result, |
518 | FW_TX_CMPLT_BLOCK_SIZE * | 518 | FW_TX_CMPLT_BLOCK_SIZE * |
519 | sizeof(struct tx_result)); | 519 | sizeof(struct tx_result)); |
520 | } | 520 | } |
521 | 521 | ||
522 | } | 522 | } |
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h new file mode 100644 index 000000000000..55818f94017b --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271.h | |||
@@ -0,0 +1,407 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_H__ | ||
26 | #define __WL1271_H__ | ||
27 | |||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/completion.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/list.h> | ||
32 | #include <linux/bitops.h> | ||
33 | #include <net/mac80211.h> | ||
34 | |||
35 | #define DRIVER_NAME "wl1271" | ||
36 | #define DRIVER_PREFIX DRIVER_NAME ": " | ||
37 | |||
38 | enum { | ||
39 | DEBUG_NONE = 0, | ||
40 | DEBUG_IRQ = BIT(0), | ||
41 | DEBUG_SPI = BIT(1), | ||
42 | DEBUG_BOOT = BIT(2), | ||
43 | DEBUG_MAILBOX = BIT(3), | ||
44 | DEBUG_NETLINK = BIT(4), | ||
45 | DEBUG_EVENT = BIT(5), | ||
46 | DEBUG_TX = BIT(6), | ||
47 | DEBUG_RX = BIT(7), | ||
48 | DEBUG_SCAN = BIT(8), | ||
49 | DEBUG_CRYPT = BIT(9), | ||
50 | DEBUG_PSM = BIT(10), | ||
51 | DEBUG_MAC80211 = BIT(11), | ||
52 | DEBUG_CMD = BIT(12), | ||
53 | DEBUG_ACX = BIT(13), | ||
54 | DEBUG_ALL = ~0, | ||
55 | }; | ||
56 | |||
57 | #define DEBUG_LEVEL (DEBUG_NONE) | ||
58 | |||
59 | #define DEBUG_DUMP_LIMIT 1024 | ||
60 | |||
61 | #define wl1271_error(fmt, arg...) \ | ||
62 | printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) | ||
63 | |||
64 | #define wl1271_warning(fmt, arg...) \ | ||
65 | printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) | ||
66 | |||
67 | #define wl1271_notice(fmt, arg...) \ | ||
68 | printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) | ||
69 | |||
70 | #define wl1271_info(fmt, arg...) \ | ||
71 | printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) | ||
72 | |||
73 | #define wl1271_debug(level, fmt, arg...) \ | ||
74 | do { \ | ||
75 | if (level & DEBUG_LEVEL) \ | ||
76 | printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ | ||
77 | } while (0) | ||
78 | |||
79 | #define wl1271_dump(level, prefix, buf, len) \ | ||
80 | do { \ | ||
81 | if (level & DEBUG_LEVEL) \ | ||
82 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | ||
83 | DUMP_PREFIX_OFFSET, 16, 1, \ | ||
84 | buf, \ | ||
85 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | ||
86 | 0); \ | ||
87 | } while (0) | ||
88 | |||
89 | #define wl1271_dump_ascii(level, prefix, buf, len) \ | ||
90 | do { \ | ||
91 | if (level & DEBUG_LEVEL) \ | ||
92 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | ||
93 | DUMP_PREFIX_OFFSET, 16, 1, \ | ||
94 | buf, \ | ||
95 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | ||
96 | true); \ | ||
97 | } while (0) | ||
98 | |||
99 | #define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ | ||
100 | CFG_BSSID_FILTER_EN) | ||
101 | |||
102 | #define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \ | ||
103 | CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \ | ||
104 | CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ | ||
105 | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) | ||
106 | |||
107 | #define WL1271_FW_NAME "wl1271-fw.bin" | ||
108 | #define WL1271_NVS_NAME "wl1271-nvs.bin" | ||
109 | |||
110 | #define WL1271_BUSY_WORD_LEN 8 | ||
111 | |||
112 | #define WL1271_ELP_HW_STATE_ASLEEP 0 | ||
113 | #define WL1271_ELP_HW_STATE_IRQ 1 | ||
114 | |||
115 | enum wl1271_state { | ||
116 | WL1271_STATE_OFF, | ||
117 | WL1271_STATE_ON, | ||
118 | WL1271_STATE_PLT, | ||
119 | }; | ||
120 | |||
121 | enum wl1271_partition_type { | ||
122 | PART_DOWN, | ||
123 | PART_WORK, | ||
124 | PART_DRPW, | ||
125 | |||
126 | PART_TABLE_LEN | ||
127 | }; | ||
128 | |||
129 | struct wl1271_partition { | ||
130 | u32 size; | ||
131 | u32 start; | ||
132 | }; | ||
133 | |||
134 | struct wl1271_partition_set { | ||
135 | struct wl1271_partition mem; | ||
136 | struct wl1271_partition reg; | ||
137 | }; | ||
138 | |||
139 | struct wl1271; | ||
140 | |||
141 | /* FIXME: I'm not sure about this structure name */ | ||
142 | struct wl1271_chip { | ||
143 | u32 id; | ||
144 | char fw_ver[21]; | ||
145 | }; | ||
146 | |||
147 | struct wl1271_stats { | ||
148 | struct acx_statistics *fw_stats; | ||
149 | unsigned long fw_stats_update; | ||
150 | |||
151 | unsigned int retry_count; | ||
152 | unsigned int excessive_retries; | ||
153 | }; | ||
154 | |||
155 | struct wl1271_debugfs { | ||
156 | struct dentry *rootdir; | ||
157 | struct dentry *fw_statistics; | ||
158 | |||
159 | struct dentry *tx_internal_desc_overflow; | ||
160 | |||
161 | struct dentry *rx_out_of_mem; | ||
162 | struct dentry *rx_hdr_overflow; | ||
163 | struct dentry *rx_hw_stuck; | ||
164 | struct dentry *rx_dropped; | ||
165 | struct dentry *rx_fcs_err; | ||
166 | struct dentry *rx_xfr_hint_trig; | ||
167 | struct dentry *rx_path_reset; | ||
168 | struct dentry *rx_reset_counter; | ||
169 | |||
170 | struct dentry *dma_rx_requested; | ||
171 | struct dentry *dma_rx_errors; | ||
172 | struct dentry *dma_tx_requested; | ||
173 | struct dentry *dma_tx_errors; | ||
174 | |||
175 | struct dentry *isr_cmd_cmplt; | ||
176 | struct dentry *isr_fiqs; | ||
177 | struct dentry *isr_rx_headers; | ||
178 | struct dentry *isr_rx_mem_overflow; | ||
179 | struct dentry *isr_rx_rdys; | ||
180 | struct dentry *isr_irqs; | ||
181 | struct dentry *isr_tx_procs; | ||
182 | struct dentry *isr_decrypt_done; | ||
183 | struct dentry *isr_dma0_done; | ||
184 | struct dentry *isr_dma1_done; | ||
185 | struct dentry *isr_tx_exch_complete; | ||
186 | struct dentry *isr_commands; | ||
187 | struct dentry *isr_rx_procs; | ||
188 | struct dentry *isr_hw_pm_mode_changes; | ||
189 | struct dentry *isr_host_acknowledges; | ||
190 | struct dentry *isr_pci_pm; | ||
191 | struct dentry *isr_wakeups; | ||
192 | struct dentry *isr_low_rssi; | ||
193 | |||
194 | struct dentry *wep_addr_key_count; | ||
195 | struct dentry *wep_default_key_count; | ||
196 | /* skipping wep.reserved */ | ||
197 | struct dentry *wep_key_not_found; | ||
198 | struct dentry *wep_decrypt_fail; | ||
199 | struct dentry *wep_packets; | ||
200 | struct dentry *wep_interrupt; | ||
201 | |||
202 | struct dentry *pwr_ps_enter; | ||
203 | struct dentry *pwr_elp_enter; | ||
204 | struct dentry *pwr_missing_bcns; | ||
205 | struct dentry *pwr_wake_on_host; | ||
206 | struct dentry *pwr_wake_on_timer_exp; | ||
207 | struct dentry *pwr_tx_with_ps; | ||
208 | struct dentry *pwr_tx_without_ps; | ||
209 | struct dentry *pwr_rcvd_beacons; | ||
210 | struct dentry *pwr_power_save_off; | ||
211 | struct dentry *pwr_enable_ps; | ||
212 | struct dentry *pwr_disable_ps; | ||
213 | struct dentry *pwr_fix_tsf_ps; | ||
214 | /* skipping cont_miss_bcns_spread for now */ | ||
215 | struct dentry *pwr_rcvd_awake_beacons; | ||
216 | |||
217 | struct dentry *mic_rx_pkts; | ||
218 | struct dentry *mic_calc_failure; | ||
219 | |||
220 | struct dentry *aes_encrypt_fail; | ||
221 | struct dentry *aes_decrypt_fail; | ||
222 | struct dentry *aes_encrypt_packets; | ||
223 | struct dentry *aes_decrypt_packets; | ||
224 | struct dentry *aes_encrypt_interrupt; | ||
225 | struct dentry *aes_decrypt_interrupt; | ||
226 | |||
227 | struct dentry *event_heart_beat; | ||
228 | struct dentry *event_calibration; | ||
229 | struct dentry *event_rx_mismatch; | ||
230 | struct dentry *event_rx_mem_empty; | ||
231 | struct dentry *event_rx_pool; | ||
232 | struct dentry *event_oom_late; | ||
233 | struct dentry *event_phy_transmit_error; | ||
234 | struct dentry *event_tx_stuck; | ||
235 | |||
236 | struct dentry *ps_pspoll_timeouts; | ||
237 | struct dentry *ps_upsd_timeouts; | ||
238 | struct dentry *ps_upsd_max_sptime; | ||
239 | struct dentry *ps_upsd_max_apturn; | ||
240 | struct dentry *ps_pspoll_max_apturn; | ||
241 | struct dentry *ps_pspoll_utilization; | ||
242 | struct dentry *ps_upsd_utilization; | ||
243 | |||
244 | struct dentry *rxpipe_rx_prep_beacon_drop; | ||
245 | struct dentry *rxpipe_descr_host_int_trig_rx_data; | ||
246 | struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; | ||
247 | struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; | ||
248 | struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; | ||
249 | |||
250 | struct dentry *tx_queue_len; | ||
251 | |||
252 | struct dentry *retry_count; | ||
253 | struct dentry *excessive_retries; | ||
254 | }; | ||
255 | |||
256 | #define NUM_TX_QUEUES 4 | ||
257 | #define NUM_RX_PKT_DESC 8 | ||
258 | |||
259 | /* FW status registers */ | ||
260 | struct wl1271_fw_status { | ||
261 | u32 intr; | ||
262 | u8 fw_rx_counter; | ||
263 | u8 drv_rx_counter; | ||
264 | u8 reserved; | ||
265 | u8 tx_results_counter; | ||
266 | u32 rx_pkt_descs[NUM_RX_PKT_DESC]; | ||
267 | u32 tx_released_blks[NUM_TX_QUEUES]; | ||
268 | u32 fw_localtime; | ||
269 | u32 padding[2]; | ||
270 | } __attribute__ ((packed)); | ||
271 | |||
272 | struct wl1271_rx_mem_pool_addr { | ||
273 | u32 addr; | ||
274 | u32 addr_extra; | ||
275 | }; | ||
276 | |||
277 | struct wl1271 { | ||
278 | struct ieee80211_hw *hw; | ||
279 | bool mac80211_registered; | ||
280 | |||
281 | struct spi_device *spi; | ||
282 | |||
283 | void (*set_power)(bool enable); | ||
284 | int irq; | ||
285 | |||
286 | spinlock_t wl_lock; | ||
287 | |||
288 | enum wl1271_state state; | ||
289 | struct mutex mutex; | ||
290 | |||
291 | int physical_mem_addr; | ||
292 | int physical_reg_addr; | ||
293 | int virtual_mem_addr; | ||
294 | int virtual_reg_addr; | ||
295 | |||
296 | struct wl1271_chip chip; | ||
297 | |||
298 | int cmd_box_addr; | ||
299 | int event_box_addr; | ||
300 | |||
301 | u8 *fw; | ||
302 | size_t fw_len; | ||
303 | u8 *nvs; | ||
304 | size_t nvs_len; | ||
305 | |||
306 | u8 bssid[ETH_ALEN]; | ||
307 | u8 mac_addr[ETH_ALEN]; | ||
308 | u8 bss_type; | ||
309 | u8 ssid[IW_ESSID_MAX_SIZE + 1]; | ||
310 | u8 ssid_len; | ||
311 | u8 listen_int; | ||
312 | int channel; | ||
313 | |||
314 | struct wl1271_acx_mem_map *target_mem_map; | ||
315 | |||
316 | /* Accounting for allocated / available TX blocks on HW */ | ||
317 | u32 tx_blocks_freed[NUM_TX_QUEUES]; | ||
318 | u32 tx_blocks_available; | ||
319 | u8 tx_results_count; | ||
320 | |||
321 | /* Transmitted TX packets counter for chipset interface */ | ||
322 | int tx_packets_count; | ||
323 | |||
324 | /* Time-offset between host and chipset clocks */ | ||
325 | int time_offset; | ||
326 | |||
327 | /* Session counter for the chipset */ | ||
328 | int session_counter; | ||
329 | |||
330 | /* Frames scheduled for transmission, not handled yet */ | ||
331 | struct sk_buff_head tx_queue; | ||
332 | bool tx_queue_stopped; | ||
333 | |||
334 | struct work_struct tx_work; | ||
335 | struct work_struct filter_work; | ||
336 | |||
337 | /* Pending TX frames */ | ||
338 | struct sk_buff *tx_frames[16]; | ||
339 | |||
340 | /* FW Rx counter */ | ||
341 | u32 rx_counter; | ||
342 | |||
343 | /* Rx memory pool address */ | ||
344 | struct wl1271_rx_mem_pool_addr rx_mem_pool_addr; | ||
345 | |||
346 | /* The target interrupt mask */ | ||
347 | struct work_struct irq_work; | ||
348 | |||
349 | /* The mbox event mask */ | ||
350 | u32 event_mask; | ||
351 | |||
352 | /* Mailbox pointers */ | ||
353 | u32 mbox_ptr[2]; | ||
354 | |||
355 | /* Are we currently scanning */ | ||
356 | bool scanning; | ||
357 | |||
358 | /* Our association ID */ | ||
359 | u16 aid; | ||
360 | |||
361 | /* Default key (for WEP) */ | ||
362 | u32 default_key; | ||
363 | |||
364 | unsigned int rx_config; | ||
365 | unsigned int rx_filter; | ||
366 | |||
367 | /* is firmware in elp mode */ | ||
368 | bool elp; | ||
369 | |||
370 | struct completion *elp_compl; | ||
371 | |||
372 | /* we can be in psm, but not in elp, we have to differentiate */ | ||
373 | bool psm; | ||
374 | |||
375 | /* PSM mode requested */ | ||
376 | bool psm_requested; | ||
377 | |||
378 | /* in dBm */ | ||
379 | int power_level; | ||
380 | |||
381 | struct wl1271_stats stats; | ||
382 | struct wl1271_debugfs debugfs; | ||
383 | |||
384 | u32 buffer_32; | ||
385 | u32 buffer_cmd; | ||
386 | u8 buffer_busyword[WL1271_BUSY_WORD_LEN]; | ||
387 | struct wl1271_rx_descriptor *rx_descriptor; | ||
388 | |||
389 | struct wl1271_fw_status *fw_status; | ||
390 | struct wl1271_tx_hw_res_if *tx_res_if; | ||
391 | }; | ||
392 | |||
393 | int wl1271_plt_start(struct wl1271 *wl); | ||
394 | int wl1271_plt_stop(struct wl1271 *wl); | ||
395 | |||
396 | #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ | ||
397 | |||
398 | #define SESSION_COUNTER_MAX 7 /* maximum value for the session counter */ | ||
399 | |||
400 | #define WL1271_DEFAULT_POWER_LEVEL 0 | ||
401 | |||
402 | #define WL1271_TX_QUEUE_MAX_LENGTH 20 | ||
403 | |||
404 | /* WL1271 needs a 200ms sleep after power on */ | ||
405 | #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ | ||
406 | |||
407 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c new file mode 100644 index 000000000000..f622a4092615 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c | |||
@@ -0,0 +1,961 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "wl1271_acx.h" | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/crc7.h> | ||
29 | #include <linux/spi/spi.h> | ||
30 | |||
31 | #include "wl1271.h" | ||
32 | #include "wl12xx_80211.h" | ||
33 | #include "wl1271_reg.h" | ||
34 | #include "wl1271_spi.h" | ||
35 | #include "wl1271_ps.h" | ||
36 | |||
37 | int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event, | ||
38 | u8 listen_interval) | ||
39 | { | ||
40 | struct acx_wake_up_condition *wake_up; | ||
41 | int ret; | ||
42 | |||
43 | wl1271_debug(DEBUG_ACX, "acx wake up conditions"); | ||
44 | |||
45 | wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); | ||
46 | if (!wake_up) { | ||
47 | ret = -ENOMEM; | ||
48 | goto out; | ||
49 | } | ||
50 | |||
51 | wake_up->wake_up_event = wake_up_event; | ||
52 | wake_up->listen_interval = listen_interval; | ||
53 | |||
54 | ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, | ||
55 | wake_up, sizeof(*wake_up)); | ||
56 | if (ret < 0) { | ||
57 | wl1271_warning("could not set wake up conditions: %d", ret); | ||
58 | goto out; | ||
59 | } | ||
60 | |||
61 | out: | ||
62 | kfree(wake_up); | ||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) | ||
67 | { | ||
68 | struct acx_sleep_auth *auth; | ||
69 | int ret; | ||
70 | |||
71 | wl1271_debug(DEBUG_ACX, "acx sleep auth"); | ||
72 | |||
73 | auth = kzalloc(sizeof(*auth), GFP_KERNEL); | ||
74 | if (!auth) { | ||
75 | ret = -ENOMEM; | ||
76 | goto out; | ||
77 | } | ||
78 | |||
79 | auth->sleep_auth = sleep_auth; | ||
80 | |||
81 | ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); | ||
82 | if (ret < 0) | ||
83 | return ret; | ||
84 | |||
85 | out: | ||
86 | kfree(auth); | ||
87 | return ret; | ||
88 | } | ||
89 | |||
90 | int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len) | ||
91 | { | ||
92 | struct acx_revision *rev; | ||
93 | int ret; | ||
94 | |||
95 | wl1271_debug(DEBUG_ACX, "acx fw rev"); | ||
96 | |||
97 | rev = kzalloc(sizeof(*rev), GFP_KERNEL); | ||
98 | if (!rev) { | ||
99 | ret = -ENOMEM; | ||
100 | goto out; | ||
101 | } | ||
102 | |||
103 | ret = wl1271_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); | ||
104 | if (ret < 0) { | ||
105 | wl1271_warning("ACX_FW_REV interrogate failed"); | ||
106 | goto out; | ||
107 | } | ||
108 | |||
109 | /* be careful with the buffer sizes */ | ||
110 | strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); | ||
111 | |||
112 | /* | ||
113 | * if the firmware version string is exactly | ||
114 | * sizeof(rev->fw_version) long or fw_len is less than | ||
115 | * sizeof(rev->fw_version) it won't be null terminated | ||
116 | */ | ||
117 | buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; | ||
118 | |||
119 | out: | ||
120 | kfree(rev); | ||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | int wl1271_acx_tx_power(struct wl1271 *wl, int power) | ||
125 | { | ||
126 | struct acx_current_tx_power *acx; | ||
127 | int ret; | ||
128 | |||
129 | wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); | ||
130 | |||
131 | if (power < 0 || power > 25) | ||
132 | return -EINVAL; | ||
133 | |||
134 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
135 | if (!acx) { | ||
136 | ret = -ENOMEM; | ||
137 | goto out; | ||
138 | } | ||
139 | |||
140 | acx->current_tx_power = power * 10; | ||
141 | |||
142 | ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); | ||
143 | if (ret < 0) { | ||
144 | wl1271_warning("configure of tx power failed: %d", ret); | ||
145 | goto out; | ||
146 | } | ||
147 | |||
148 | out: | ||
149 | kfree(acx); | ||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | int wl1271_acx_feature_cfg(struct wl1271 *wl) | ||
154 | { | ||
155 | struct acx_feature_config *feature; | ||
156 | int ret; | ||
157 | |||
158 | wl1271_debug(DEBUG_ACX, "acx feature cfg"); | ||
159 | |||
160 | feature = kzalloc(sizeof(*feature), GFP_KERNEL); | ||
161 | if (!feature) { | ||
162 | ret = -ENOMEM; | ||
163 | goto out; | ||
164 | } | ||
165 | |||
166 | /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ | ||
167 | feature->data_flow_options = 0; | ||
168 | feature->options = 0; | ||
169 | |||
170 | ret = wl1271_cmd_configure(wl, ACX_FEATURE_CFG, | ||
171 | feature, sizeof(*feature)); | ||
172 | if (ret < 0) { | ||
173 | wl1271_error("Couldnt set HW encryption"); | ||
174 | goto out; | ||
175 | } | ||
176 | |||
177 | out: | ||
178 | kfree(feature); | ||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, | ||
183 | size_t len) | ||
184 | { | ||
185 | int ret; | ||
186 | |||
187 | wl1271_debug(DEBUG_ACX, "acx mem map"); | ||
188 | |||
189 | ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); | ||
190 | if (ret < 0) | ||
191 | return ret; | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time) | ||
197 | { | ||
198 | struct acx_rx_msdu_lifetime *acx; | ||
199 | int ret; | ||
200 | |||
201 | wl1271_debug(DEBUG_ACX, "acx rx msdu life time"); | ||
202 | |||
203 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
204 | if (!acx) { | ||
205 | ret = -ENOMEM; | ||
206 | goto out; | ||
207 | } | ||
208 | |||
209 | acx->lifetime = life_time; | ||
210 | ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, | ||
211 | acx, sizeof(*acx)); | ||
212 | if (ret < 0) { | ||
213 | wl1271_warning("failed to set rx msdu life time: %d", ret); | ||
214 | goto out; | ||
215 | } | ||
216 | |||
217 | out: | ||
218 | kfree(acx); | ||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter) | ||
223 | { | ||
224 | struct acx_rx_config *rx_config; | ||
225 | int ret; | ||
226 | |||
227 | wl1271_debug(DEBUG_ACX, "acx rx config"); | ||
228 | |||
229 | rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); | ||
230 | if (!rx_config) { | ||
231 | ret = -ENOMEM; | ||
232 | goto out; | ||
233 | } | ||
234 | |||
235 | rx_config->config_options = config; | ||
236 | rx_config->filter_options = filter; | ||
237 | |||
238 | ret = wl1271_cmd_configure(wl, ACX_RX_CFG, | ||
239 | rx_config, sizeof(*rx_config)); | ||
240 | if (ret < 0) { | ||
241 | wl1271_warning("failed to set rx config: %d", ret); | ||
242 | goto out; | ||
243 | } | ||
244 | |||
245 | out: | ||
246 | kfree(rx_config); | ||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | int wl1271_acx_pd_threshold(struct wl1271 *wl) | ||
251 | { | ||
252 | struct acx_packet_detection *pd; | ||
253 | int ret; | ||
254 | |||
255 | wl1271_debug(DEBUG_ACX, "acx data pd threshold"); | ||
256 | |||
257 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); | ||
258 | if (!pd) { | ||
259 | ret = -ENOMEM; | ||
260 | goto out; | ||
261 | } | ||
262 | |||
263 | /* FIXME: threshold value not set */ | ||
264 | |||
265 | ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); | ||
266 | if (ret < 0) { | ||
267 | wl1271_warning("failed to set pd threshold: %d", ret); | ||
268 | goto out; | ||
269 | } | ||
270 | |||
271 | out: | ||
272 | kfree(pd); | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time) | ||
277 | { | ||
278 | struct acx_slot *slot; | ||
279 | int ret; | ||
280 | |||
281 | wl1271_debug(DEBUG_ACX, "acx slot"); | ||
282 | |||
283 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | ||
284 | if (!slot) { | ||
285 | ret = -ENOMEM; | ||
286 | goto out; | ||
287 | } | ||
288 | |||
289 | slot->wone_index = STATION_WONE_INDEX; | ||
290 | slot->slot_time = slot_time; | ||
291 | |||
292 | ret = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); | ||
293 | if (ret < 0) { | ||
294 | wl1271_warning("failed to set slot time: %d", ret); | ||
295 | goto out; | ||
296 | } | ||
297 | |||
298 | out: | ||
299 | kfree(slot); | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | int wl1271_acx_group_address_tbl(struct wl1271 *wl) | ||
304 | { | ||
305 | struct acx_dot11_grp_addr_tbl *acx; | ||
306 | int ret; | ||
307 | |||
308 | wl1271_debug(DEBUG_ACX, "acx group address tbl"); | ||
309 | |||
310 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
311 | if (!acx) { | ||
312 | ret = -ENOMEM; | ||
313 | goto out; | ||
314 | } | ||
315 | |||
316 | /* MAC filtering */ | ||
317 | acx->enabled = 0; | ||
318 | acx->num_groups = 0; | ||
319 | memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); | ||
320 | |||
321 | ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, | ||
322 | acx, sizeof(*acx)); | ||
323 | if (ret < 0) { | ||
324 | wl1271_warning("failed to set group addr table: %d", ret); | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | out: | ||
329 | kfree(acx); | ||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | int wl1271_acx_service_period_timeout(struct wl1271 *wl) | ||
334 | { | ||
335 | struct acx_rx_timeout *rx_timeout; | ||
336 | int ret; | ||
337 | |||
338 | rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); | ||
339 | if (!rx_timeout) { | ||
340 | ret = -ENOMEM; | ||
341 | goto out; | ||
342 | } | ||
343 | |||
344 | wl1271_debug(DEBUG_ACX, "acx service period timeout"); | ||
345 | |||
346 | rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; | ||
347 | rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; | ||
348 | |||
349 | ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, | ||
350 | rx_timeout, sizeof(*rx_timeout)); | ||
351 | if (ret < 0) { | ||
352 | wl1271_warning("failed to set service period timeout: %d", | ||
353 | ret); | ||
354 | goto out; | ||
355 | } | ||
356 | |||
357 | out: | ||
358 | kfree(rx_timeout); | ||
359 | return ret; | ||
360 | } | ||
361 | |||
362 | int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold) | ||
363 | { | ||
364 | struct acx_rts_threshold *rts; | ||
365 | int ret; | ||
366 | |||
367 | wl1271_debug(DEBUG_ACX, "acx rts threshold"); | ||
368 | |||
369 | rts = kzalloc(sizeof(*rts), GFP_KERNEL); | ||
370 | if (!rts) { | ||
371 | ret = -ENOMEM; | ||
372 | goto out; | ||
373 | } | ||
374 | |||
375 | rts->threshold = rts_threshold; | ||
376 | |||
377 | ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); | ||
378 | if (ret < 0) { | ||
379 | wl1271_warning("failed to set rts threshold: %d", ret); | ||
380 | goto out; | ||
381 | } | ||
382 | |||
383 | out: | ||
384 | kfree(rts); | ||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | int wl1271_acx_beacon_filter_opt(struct wl1271 *wl) | ||
389 | { | ||
390 | struct acx_beacon_filter_option *beacon_filter; | ||
391 | int ret; | ||
392 | |||
393 | wl1271_debug(DEBUG_ACX, "acx beacon filter opt"); | ||
394 | |||
395 | beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); | ||
396 | if (!beacon_filter) { | ||
397 | ret = -ENOMEM; | ||
398 | goto out; | ||
399 | } | ||
400 | |||
401 | beacon_filter->enable = 0; | ||
402 | beacon_filter->max_num_beacons = 0; | ||
403 | |||
404 | ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT, | ||
405 | beacon_filter, sizeof(*beacon_filter)); | ||
406 | if (ret < 0) { | ||
407 | wl1271_warning("failed to set beacon filter opt: %d", ret); | ||
408 | goto out; | ||
409 | } | ||
410 | |||
411 | out: | ||
412 | kfree(beacon_filter); | ||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | int wl1271_acx_beacon_filter_table(struct wl1271 *wl) | ||
417 | { | ||
418 | struct acx_beacon_filter_ie_table *ie_table; | ||
419 | int ret; | ||
420 | |||
421 | wl1271_debug(DEBUG_ACX, "acx beacon filter table"); | ||
422 | |||
423 | ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); | ||
424 | if (!ie_table) { | ||
425 | ret = -ENOMEM; | ||
426 | goto out; | ||
427 | } | ||
428 | |||
429 | ie_table->num_ie = 0; | ||
430 | memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); | ||
431 | |||
432 | ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, | ||
433 | ie_table, sizeof(*ie_table)); | ||
434 | if (ret < 0) { | ||
435 | wl1271_warning("failed to set beacon filter table: %d", ret); | ||
436 | goto out; | ||
437 | } | ||
438 | |||
439 | out: | ||
440 | kfree(ie_table); | ||
441 | return ret; | ||
442 | } | ||
443 | |||
444 | int wl1271_acx_sg_enable(struct wl1271 *wl) | ||
445 | { | ||
446 | struct acx_bt_wlan_coex *pta; | ||
447 | int ret; | ||
448 | |||
449 | wl1271_debug(DEBUG_ACX, "acx sg enable"); | ||
450 | |||
451 | pta = kzalloc(sizeof(*pta), GFP_KERNEL); | ||
452 | if (!pta) { | ||
453 | ret = -ENOMEM; | ||
454 | goto out; | ||
455 | } | ||
456 | |||
457 | pta->enable = SG_ENABLE; | ||
458 | |||
459 | ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); | ||
460 | if (ret < 0) { | ||
461 | wl1271_warning("failed to set softgemini enable: %d", ret); | ||
462 | goto out; | ||
463 | } | ||
464 | |||
465 | out: | ||
466 | kfree(pta); | ||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | int wl1271_acx_sg_cfg(struct wl1271 *wl) | ||
471 | { | ||
472 | struct acx_bt_wlan_coex_param *param; | ||
473 | int ret; | ||
474 | |||
475 | wl1271_debug(DEBUG_ACX, "acx sg cfg"); | ||
476 | |||
477 | param = kzalloc(sizeof(*param), GFP_KERNEL); | ||
478 | if (!param) { | ||
479 | ret = -ENOMEM; | ||
480 | goto out; | ||
481 | } | ||
482 | |||
483 | /* BT-WLAN coext parameters */ | ||
484 | param->min_rate = RATE_INDEX_24MBPS; | ||
485 | param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; | ||
486 | param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; | ||
487 | param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; | ||
488 | param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; | ||
489 | param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; | ||
490 | param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; | ||
491 | param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; | ||
492 | param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; | ||
493 | param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; | ||
494 | param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; | ||
495 | param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; | ||
496 | param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; | ||
497 | param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; | ||
498 | param->antenna_type = PTA_ANTENNA_TYPE_DEF; | ||
499 | param->signal_type = PTA_SIGNALING_TYPE_DEF; | ||
500 | param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; | ||
501 | param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; | ||
502 | param->max_cts = PTA_MAX_NUM_CTS_DEF; | ||
503 | param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; | ||
504 | param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; | ||
505 | param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; | ||
506 | param->wlan_elp_hp = PTA_ELP_HP_DEF; | ||
507 | param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; | ||
508 | param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; | ||
509 | param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; | ||
510 | param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; | ||
511 | param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; | ||
512 | |||
513 | ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); | ||
514 | if (ret < 0) { | ||
515 | wl1271_warning("failed to set sg config: %d", ret); | ||
516 | goto out; | ||
517 | } | ||
518 | |||
519 | out: | ||
520 | kfree(param); | ||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | int wl1271_acx_cca_threshold(struct wl1271 *wl) | ||
525 | { | ||
526 | struct acx_energy_detection *detection; | ||
527 | int ret; | ||
528 | |||
529 | wl1271_debug(DEBUG_ACX, "acx cca threshold"); | ||
530 | |||
531 | detection = kzalloc(sizeof(*detection), GFP_KERNEL); | ||
532 | if (!detection) { | ||
533 | ret = -ENOMEM; | ||
534 | goto out; | ||
535 | } | ||
536 | |||
537 | detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; | ||
538 | detection->tx_energy_detection = 0; | ||
539 | |||
540 | ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, | ||
541 | detection, sizeof(*detection)); | ||
542 | if (ret < 0) { | ||
543 | wl1271_warning("failed to set cca threshold: %d", ret); | ||
544 | return ret; | ||
545 | } | ||
546 | |||
547 | out: | ||
548 | kfree(detection); | ||
549 | return ret; | ||
550 | } | ||
551 | |||
552 | int wl1271_acx_bcn_dtim_options(struct wl1271 *wl) | ||
553 | { | ||
554 | struct acx_beacon_broadcast *bb; | ||
555 | int ret; | ||
556 | |||
557 | wl1271_debug(DEBUG_ACX, "acx bcn dtim options"); | ||
558 | |||
559 | bb = kzalloc(sizeof(*bb), GFP_KERNEL); | ||
560 | if (!bb) { | ||
561 | ret = -ENOMEM; | ||
562 | goto out; | ||
563 | } | ||
564 | |||
565 | bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; | ||
566 | bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; | ||
567 | bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; | ||
568 | bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; | ||
569 | |||
570 | ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); | ||
571 | if (ret < 0) { | ||
572 | wl1271_warning("failed to set rx config: %d", ret); | ||
573 | goto out; | ||
574 | } | ||
575 | |||
576 | out: | ||
577 | kfree(bb); | ||
578 | return ret; | ||
579 | } | ||
580 | |||
581 | int wl1271_acx_aid(struct wl1271 *wl, u16 aid) | ||
582 | { | ||
583 | struct acx_aid *acx_aid; | ||
584 | int ret; | ||
585 | |||
586 | wl1271_debug(DEBUG_ACX, "acx aid"); | ||
587 | |||
588 | acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); | ||
589 | if (!acx_aid) { | ||
590 | ret = -ENOMEM; | ||
591 | goto out; | ||
592 | } | ||
593 | |||
594 | acx_aid->aid = aid; | ||
595 | |||
596 | ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); | ||
597 | if (ret < 0) { | ||
598 | wl1271_warning("failed to set aid: %d", ret); | ||
599 | goto out; | ||
600 | } | ||
601 | |||
602 | out: | ||
603 | kfree(acx_aid); | ||
604 | return ret; | ||
605 | } | ||
606 | |||
607 | int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask) | ||
608 | { | ||
609 | struct acx_event_mask *mask; | ||
610 | int ret; | ||
611 | |||
612 | wl1271_debug(DEBUG_ACX, "acx event mbox mask"); | ||
613 | |||
614 | mask = kzalloc(sizeof(*mask), GFP_KERNEL); | ||
615 | if (!mask) { | ||
616 | ret = -ENOMEM; | ||
617 | goto out; | ||
618 | } | ||
619 | |||
620 | /* high event mask is unused */ | ||
621 | mask->high_event_mask = 0xffffffff; | ||
622 | |||
623 | mask->event_mask = event_mask; | ||
624 | |||
625 | ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK, | ||
626 | mask, sizeof(*mask)); | ||
627 | if (ret < 0) { | ||
628 | wl1271_warning("failed to set acx_event_mbox_mask: %d", ret); | ||
629 | goto out; | ||
630 | } | ||
631 | |||
632 | out: | ||
633 | kfree(mask); | ||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble) | ||
638 | { | ||
639 | struct acx_preamble *acx; | ||
640 | int ret; | ||
641 | |||
642 | wl1271_debug(DEBUG_ACX, "acx_set_preamble"); | ||
643 | |||
644 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
645 | if (!acx) { | ||
646 | ret = -ENOMEM; | ||
647 | goto out; | ||
648 | } | ||
649 | |||
650 | acx->preamble = preamble; | ||
651 | |||
652 | ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); | ||
653 | if (ret < 0) { | ||
654 | wl1271_warning("Setting of preamble failed: %d", ret); | ||
655 | goto out; | ||
656 | } | ||
657 | |||
658 | out: | ||
659 | kfree(acx); | ||
660 | return ret; | ||
661 | } | ||
662 | |||
663 | int wl1271_acx_cts_protect(struct wl1271 *wl, | ||
664 | enum acx_ctsprotect_type ctsprotect) | ||
665 | { | ||
666 | struct acx_ctsprotect *acx; | ||
667 | int ret; | ||
668 | |||
669 | wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect"); | ||
670 | |||
671 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
672 | if (!acx) { | ||
673 | ret = -ENOMEM; | ||
674 | goto out; | ||
675 | } | ||
676 | |||
677 | acx->ctsprotect = ctsprotect; | ||
678 | |||
679 | ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); | ||
680 | if (ret < 0) { | ||
681 | wl1271_warning("Setting of ctsprotect failed: %d", ret); | ||
682 | goto out; | ||
683 | } | ||
684 | |||
685 | out: | ||
686 | kfree(acx); | ||
687 | return ret; | ||
688 | } | ||
689 | |||
690 | int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) | ||
691 | { | ||
692 | int ret; | ||
693 | |||
694 | wl1271_debug(DEBUG_ACX, "acx statistics"); | ||
695 | |||
696 | ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats, | ||
697 | sizeof(*stats)); | ||
698 | if (ret < 0) { | ||
699 | wl1271_warning("acx statistics failed: %d", ret); | ||
700 | return -ENOMEM; | ||
701 | } | ||
702 | |||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | int wl1271_acx_rate_policies(struct wl1271 *wl) | ||
707 | { | ||
708 | struct acx_rate_policy *acx; | ||
709 | int ret = 0; | ||
710 | |||
711 | wl1271_debug(DEBUG_ACX, "acx rate policies"); | ||
712 | |||
713 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
714 | |||
715 | if (!acx) { | ||
716 | ret = -ENOMEM; | ||
717 | goto out; | ||
718 | } | ||
719 | |||
720 | /* configure one default (one-size-fits-all) rate class */ | ||
721 | acx->rate_class_cnt = 1; | ||
722 | acx->rate_class[0].enabled_rates = ACX_RATE_MASK_ALL; | ||
723 | acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
724 | acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
725 | acx->rate_class[0].aflags = 0; | ||
726 | |||
727 | ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); | ||
728 | if (ret < 0) { | ||
729 | wl1271_warning("Setting of rate policies failed: %d", ret); | ||
730 | goto out; | ||
731 | } | ||
732 | |||
733 | out: | ||
734 | kfree(acx); | ||
735 | return ret; | ||
736 | } | ||
737 | |||
738 | int wl1271_acx_ac_cfg(struct wl1271 *wl) | ||
739 | { | ||
740 | struct acx_ac_cfg *acx; | ||
741 | int i, ret = 0; | ||
742 | |||
743 | wl1271_debug(DEBUG_ACX, "acx access category config"); | ||
744 | |||
745 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
746 | |||
747 | if (!acx) { | ||
748 | ret = -ENOMEM; | ||
749 | goto out; | ||
750 | } | ||
751 | |||
752 | /* | ||
753 | * FIXME: Configure each AC with appropriate values (most suitable | ||
754 | * values will probably be different for each AC. | ||
755 | */ | ||
756 | for (i = 0; i < WL1271_ACX_AC_COUNT; i++) { | ||
757 | acx->ac = i; | ||
758 | |||
759 | /* | ||
760 | * FIXME: The following default values originate from | ||
761 | * the TI reference driver. What do they mean? | ||
762 | */ | ||
763 | acx->cw_min = 15; | ||
764 | acx->cw_max = 63; | ||
765 | acx->aifsn = 3; | ||
766 | acx->reserved = 0; | ||
767 | acx->tx_op_limit = 0; | ||
768 | |||
769 | ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); | ||
770 | if (ret < 0) { | ||
771 | wl1271_warning("Setting of access category " | ||
772 | "config: %d", ret); | ||
773 | goto out; | ||
774 | } | ||
775 | } | ||
776 | |||
777 | out: | ||
778 | kfree(acx); | ||
779 | return ret; | ||
780 | } | ||
781 | |||
782 | int wl1271_acx_tid_cfg(struct wl1271 *wl) | ||
783 | { | ||
784 | struct acx_tid_config *acx; | ||
785 | int i, ret = 0; | ||
786 | |||
787 | wl1271_debug(DEBUG_ACX, "acx tid config"); | ||
788 | |||
789 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
790 | |||
791 | if (!acx) { | ||
792 | ret = -ENOMEM; | ||
793 | goto out; | ||
794 | } | ||
795 | |||
796 | /* FIXME: configure each TID with a different AC reference */ | ||
797 | for (i = 0; i < WL1271_ACX_TID_COUNT; i++) { | ||
798 | acx->queue_id = i; | ||
799 | acx->tsid = WL1271_ACX_AC_BE; | ||
800 | acx->ps_scheme = WL1271_ACX_PS_SCHEME_LEGACY; | ||
801 | acx->ack_policy = WL1271_ACX_ACK_POLICY_LEGACY; | ||
802 | |||
803 | ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); | ||
804 | if (ret < 0) { | ||
805 | wl1271_warning("Setting of tid config failed: %d", ret); | ||
806 | goto out; | ||
807 | } | ||
808 | } | ||
809 | |||
810 | out: | ||
811 | kfree(acx); | ||
812 | return ret; | ||
813 | } | ||
814 | |||
815 | int wl1271_acx_frag_threshold(struct wl1271 *wl) | ||
816 | { | ||
817 | struct acx_frag_threshold *acx; | ||
818 | int ret = 0; | ||
819 | |||
820 | wl1271_debug(DEBUG_ACX, "acx frag threshold"); | ||
821 | |||
822 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
823 | |||
824 | if (!acx) { | ||
825 | ret = -ENOMEM; | ||
826 | goto out; | ||
827 | } | ||
828 | |||
829 | acx->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | ||
830 | ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); | ||
831 | if (ret < 0) { | ||
832 | wl1271_warning("Setting of frag threshold failed: %d", ret); | ||
833 | goto out; | ||
834 | } | ||
835 | |||
836 | out: | ||
837 | kfree(acx); | ||
838 | return ret; | ||
839 | } | ||
840 | |||
841 | int wl1271_acx_tx_config_options(struct wl1271 *wl) | ||
842 | { | ||
843 | struct acx_tx_config_options *acx; | ||
844 | int ret = 0; | ||
845 | |||
846 | wl1271_debug(DEBUG_ACX, "acx tx config options"); | ||
847 | |||
848 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
849 | |||
850 | if (!acx) { | ||
851 | ret = -ENOMEM; | ||
852 | goto out; | ||
853 | } | ||
854 | |||
855 | acx->tx_compl_timeout = WL1271_ACX_TX_COMPL_TIMEOUT; | ||
856 | acx->tx_compl_threshold = WL1271_ACX_TX_COMPL_THRESHOLD; | ||
857 | ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx)); | ||
858 | if (ret < 0) { | ||
859 | wl1271_warning("Setting of tx options failed: %d", ret); | ||
860 | goto out; | ||
861 | } | ||
862 | |||
863 | out: | ||
864 | kfree(acx); | ||
865 | return ret; | ||
866 | } | ||
867 | |||
868 | int wl1271_acx_mem_cfg(struct wl1271 *wl) | ||
869 | { | ||
870 | struct wl1271_acx_config_memory *mem_conf; | ||
871 | int ret; | ||
872 | |||
873 | wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); | ||
874 | |||
875 | mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); | ||
876 | if (!mem_conf) { | ||
877 | ret = -ENOMEM; | ||
878 | goto out; | ||
879 | } | ||
880 | |||
881 | /* memory config */ | ||
882 | mem_conf->num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); | ||
883 | mem_conf->rx_mem_block_num = ACX_RX_MEM_BLOCKS; | ||
884 | mem_conf->tx_min_mem_block_num = ACX_TX_MIN_MEM_BLOCKS; | ||
885 | mem_conf->num_ssid_profiles = ACX_NUM_SSID_PROFILES; | ||
886 | mem_conf->total_tx_descriptors = ACX_TX_DESCRIPTORS; | ||
887 | |||
888 | ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, | ||
889 | sizeof(*mem_conf)); | ||
890 | if (ret < 0) { | ||
891 | wl1271_warning("wl1271 mem config failed: %d", ret); | ||
892 | goto out; | ||
893 | } | ||
894 | |||
895 | out: | ||
896 | kfree(mem_conf); | ||
897 | return ret; | ||
898 | } | ||
899 | |||
900 | int wl1271_acx_init_mem_config(struct wl1271 *wl) | ||
901 | { | ||
902 | int ret; | ||
903 | |||
904 | ret = wl1271_acx_mem_cfg(wl); | ||
905 | if (ret < 0) | ||
906 | return ret; | ||
907 | |||
908 | wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map), | ||
909 | GFP_KERNEL); | ||
910 | if (!wl->target_mem_map) { | ||
911 | wl1271_error("couldn't allocate target memory map"); | ||
912 | return -ENOMEM; | ||
913 | } | ||
914 | |||
915 | /* we now ask for the firmware built memory map */ | ||
916 | ret = wl1271_acx_mem_map(wl, (void *)wl->target_mem_map, | ||
917 | sizeof(struct wl1271_acx_mem_map)); | ||
918 | if (ret < 0) { | ||
919 | wl1271_error("couldn't retrieve firmware memory map"); | ||
920 | kfree(wl->target_mem_map); | ||
921 | wl->target_mem_map = NULL; | ||
922 | return ret; | ||
923 | } | ||
924 | |||
925 | /* initialize TX block book keeping */ | ||
926 | wl->tx_blocks_available = wl->target_mem_map->num_tx_mem_blocks; | ||
927 | wl1271_debug(DEBUG_TX, "available tx blocks: %d", | ||
928 | wl->tx_blocks_available); | ||
929 | |||
930 | return 0; | ||
931 | } | ||
932 | |||
933 | int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) | ||
934 | { | ||
935 | struct wl1271_acx_rx_config_opt *rx_conf; | ||
936 | int ret; | ||
937 | |||
938 | wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config"); | ||
939 | |||
940 | rx_conf = kzalloc(sizeof(*rx_conf), GFP_KERNEL); | ||
941 | if (!rx_conf) { | ||
942 | ret = -ENOMEM; | ||
943 | goto out; | ||
944 | } | ||
945 | |||
946 | rx_conf->threshold = WL1271_RX_INTR_THRESHOLD_DEF; | ||
947 | rx_conf->timeout = WL1271_RX_INTR_TIMEOUT_DEF; | ||
948 | rx_conf->mblk_threshold = USHORT_MAX; /* Disabled */ | ||
949 | rx_conf->queue_type = RX_QUEUE_TYPE_RX_LOW_PRIORITY; | ||
950 | |||
951 | ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf, | ||
952 | sizeof(*rx_conf)); | ||
953 | if (ret < 0) { | ||
954 | wl1271_warning("wl1271 rx config opt failed: %d", ret); | ||
955 | goto out; | ||
956 | } | ||
957 | |||
958 | out: | ||
959 | kfree(rx_conf); | ||
960 | return ret; | ||
961 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h new file mode 100644 index 000000000000..9068daaf0ddf --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h | |||
@@ -0,0 +1,1221 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_ACX_H__ | ||
26 | #define __WL1271_ACX_H__ | ||
27 | |||
28 | #include "wl1271.h" | ||
29 | #include "wl1271_cmd.h" | ||
30 | |||
31 | /************************************************************************* | ||
32 | |||
33 | Host Interrupt Register (WiLink -> Host) | ||
34 | |||
35 | **************************************************************************/ | ||
36 | /* HW Initiated interrupt Watchdog timer expiration */ | ||
37 | #define WL1271_ACX_INTR_WATCHDOG BIT(0) | ||
38 | /* Init sequence is done (masked interrupt, detection through polling only ) */ | ||
39 | #define WL1271_ACX_INTR_INIT_COMPLETE BIT(1) | ||
40 | /* Event was entered to Event MBOX #A*/ | ||
41 | #define WL1271_ACX_INTR_EVENT_A BIT(2) | ||
42 | /* Event was entered to Event MBOX #B*/ | ||
43 | #define WL1271_ACX_INTR_EVENT_B BIT(3) | ||
44 | /* Command processing completion*/ | ||
45 | #define WL1271_ACX_INTR_CMD_COMPLETE BIT(4) | ||
46 | /* Signaling the host on HW wakeup */ | ||
47 | #define WL1271_ACX_INTR_HW_AVAILABLE BIT(5) | ||
48 | /* The MISC bit is used for aggregation of RX, TxComplete and TX rate update */ | ||
49 | #define WL1271_ACX_INTR_DATA BIT(6) | ||
50 | /* Trace meassge on MBOX #A */ | ||
51 | #define WL1271_ACX_INTR_TRACE_A BIT(7) | ||
52 | /* Trace meassge on MBOX #B */ | ||
53 | #define WL1271_ACX_INTR_TRACE_B BIT(8) | ||
54 | |||
55 | #define WL1271_ACX_INTR_ALL 0xFFFFFFFF | ||
56 | #define WL1271_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \ | ||
57 | WL1271_ACX_INTR_INIT_COMPLETE | \ | ||
58 | WL1271_ACX_INTR_EVENT_A | \ | ||
59 | WL1271_ACX_INTR_EVENT_B | \ | ||
60 | WL1271_ACX_INTR_CMD_COMPLETE | \ | ||
61 | WL1271_ACX_INTR_HW_AVAILABLE | \ | ||
62 | WL1271_ACX_INTR_DATA) | ||
63 | |||
64 | #define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \ | ||
65 | WL1271_ACX_INTR_EVENT_B | \ | ||
66 | WL1271_ACX_INTR_DATA) | ||
67 | |||
68 | /* Target's information element */ | ||
69 | struct acx_header { | ||
70 | struct wl1271_cmd_header cmd; | ||
71 | |||
72 | /* acx (or information element) header */ | ||
73 | u16 id; | ||
74 | |||
75 | /* payload length (not including headers */ | ||
76 | u16 len; | ||
77 | }; | ||
78 | |||
79 | struct acx_error_counter { | ||
80 | struct acx_header header; | ||
81 | |||
82 | /* The number of PLCP errors since the last time this */ | ||
83 | /* information element was interrogated. This field is */ | ||
84 | /* automatically cleared when it is interrogated.*/ | ||
85 | u32 PLCP_error; | ||
86 | |||
87 | /* The number of FCS errors since the last time this */ | ||
88 | /* information element was interrogated. This field is */ | ||
89 | /* automatically cleared when it is interrogated.*/ | ||
90 | u32 FCS_error; | ||
91 | |||
92 | /* The number of MPDUs without PLCP header errors received*/ | ||
93 | /* since the last time this information element was interrogated. */ | ||
94 | /* This field is automatically cleared when it is interrogated.*/ | ||
95 | u32 valid_frame; | ||
96 | |||
97 | /* the number of missed sequence numbers in the squentially */ | ||
98 | /* values of frames seq numbers */ | ||
99 | u32 seq_num_miss; | ||
100 | } __attribute__ ((packed)); | ||
101 | |||
102 | struct acx_revision { | ||
103 | struct acx_header header; | ||
104 | |||
105 | /* | ||
106 | * The WiLink firmware version, an ASCII string x.x.x.x, | ||
107 | * that uniquely identifies the current firmware. | ||
108 | * The left most digit is incremented each time a | ||
109 | * significant change is made to the firmware, such as | ||
110 | * code redesign or new platform support. | ||
111 | * The second digit is incremented when major enhancements | ||
112 | * are added or major fixes are made. | ||
113 | * The third digit is incremented for each GA release. | ||
114 | * The fourth digit is incremented for each build. | ||
115 | * The first two digits identify a firmware release version, | ||
116 | * in other words, a unique set of features. | ||
117 | * The first three digits identify a GA release. | ||
118 | */ | ||
119 | char fw_version[20]; | ||
120 | |||
121 | /* | ||
122 | * This 4 byte field specifies the WiLink hardware version. | ||
123 | * bits 0 - 15: Reserved. | ||
124 | * bits 16 - 23: Version ID - The WiLink version ID | ||
125 | * (1 = first spin, 2 = second spin, and so on). | ||
126 | * bits 24 - 31: Chip ID - The WiLink chip ID. | ||
127 | */ | ||
128 | u32 hw_version; | ||
129 | } __attribute__ ((packed)); | ||
130 | |||
131 | enum wl1271_psm_mode { | ||
132 | /* Active mode */ | ||
133 | WL1271_PSM_CAM = 0, | ||
134 | |||
135 | /* Power save mode */ | ||
136 | WL1271_PSM_PS = 1, | ||
137 | |||
138 | /* Extreme low power */ | ||
139 | WL1271_PSM_ELP = 2, | ||
140 | }; | ||
141 | |||
142 | struct acx_sleep_auth { | ||
143 | struct acx_header header; | ||
144 | |||
145 | /* The sleep level authorization of the device. */ | ||
146 | /* 0 - Always active*/ | ||
147 | /* 1 - Power down mode: light / fast sleep*/ | ||
148 | /* 2 - ELP mode: Deep / Max sleep*/ | ||
149 | u8 sleep_auth; | ||
150 | u8 padding[3]; | ||
151 | } __attribute__ ((packed)); | ||
152 | |||
153 | enum { | ||
154 | HOSTIF_PCI_MASTER_HOST_INDIRECT, | ||
155 | HOSTIF_PCI_MASTER_HOST_DIRECT, | ||
156 | HOSTIF_SLAVE, | ||
157 | HOSTIF_PKT_RING, | ||
158 | HOSTIF_DONTCARE = 0xFF | ||
159 | }; | ||
160 | |||
161 | #define DEFAULT_UCAST_PRIORITY 0 | ||
162 | #define DEFAULT_RX_Q_PRIORITY 0 | ||
163 | #define DEFAULT_NUM_STATIONS 1 | ||
164 | #define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ | ||
165 | #define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ | ||
166 | #define TRACE_BUFFER_MAX_SIZE 256 | ||
167 | |||
168 | #define DP_RX_PACKET_RING_CHUNK_SIZE 1600 | ||
169 | #define DP_TX_PACKET_RING_CHUNK_SIZE 1600 | ||
170 | #define DP_RX_PACKET_RING_CHUNK_NUM 2 | ||
171 | #define DP_TX_PACKET_RING_CHUNK_NUM 2 | ||
172 | #define DP_TX_COMPLETE_TIME_OUT 20 | ||
173 | #define FW_TX_CMPLT_BLOCK_SIZE 16 | ||
174 | |||
175 | #define TX_MSDU_LIFETIME_MIN 0 | ||
176 | #define TX_MSDU_LIFETIME_MAX 3000 | ||
177 | #define TX_MSDU_LIFETIME_DEF 512 | ||
178 | #define RX_MSDU_LIFETIME_MIN 0 | ||
179 | #define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF | ||
180 | #define RX_MSDU_LIFETIME_DEF 512000 | ||
181 | |||
182 | struct acx_rx_msdu_lifetime { | ||
183 | struct acx_header header; | ||
184 | |||
185 | /* | ||
186 | * The maximum amount of time, in TU, before the | ||
187 | * firmware discards the MSDU. | ||
188 | */ | ||
189 | u32 lifetime; | ||
190 | } __attribute__ ((packed)); | ||
191 | |||
192 | /* | ||
193 | * RX Config Options Table | ||
194 | * Bit Definition | ||
195 | * === ========== | ||
196 | * 31:14 Reserved | ||
197 | * 13 Copy RX Status - when set, write three receive status words | ||
198 | * to top of rx'd MPDUs. | ||
199 | * When cleared, do not write three status words (added rev 1.5) | ||
200 | * 12 Reserved | ||
201 | * 11 RX Complete upon FCS error - when set, give rx complete | ||
202 | * interrupt for FCS errors, after the rx filtering, e.g. unicast | ||
203 | * frames not to us with FCS error will not generate an interrupt. | ||
204 | * 10 SSID Filter Enable - When set, the WiLink discards all beacon, | ||
205 | * probe request, and probe response frames with an SSID that does | ||
206 | * not match the SSID specified by the host in the START/JOIN | ||
207 | * command. | ||
208 | * When clear, the WiLink receives frames with any SSID. | ||
209 | * 9 Broadcast Filter Enable - When set, the WiLink discards all | ||
210 | * broadcast frames. When clear, the WiLink receives all received | ||
211 | * broadcast frames. | ||
212 | * 8:6 Reserved | ||
213 | * 5 BSSID Filter Enable - When set, the WiLink discards any frames | ||
214 | * with a BSSID that does not match the BSSID specified by the | ||
215 | * host. | ||
216 | * When clear, the WiLink receives frames from any BSSID. | ||
217 | * 4 MAC Addr Filter - When set, the WiLink discards any frames | ||
218 | * with a destination address that does not match the MAC address | ||
219 | * of the adaptor. | ||
220 | * When clear, the WiLink receives frames destined to any MAC | ||
221 | * address. | ||
222 | * 3 Promiscuous - When set, the WiLink receives all valid frames | ||
223 | * (i.e., all frames that pass the FCS check). | ||
224 | * When clear, only frames that pass the other filters specified | ||
225 | * are received. | ||
226 | * 2 FCS - When set, the WiLink includes the FCS with the received | ||
227 | * frame. | ||
228 | * When cleared, the FCS is discarded. | ||
229 | * 1 PLCP header - When set, write all data from baseband to frame | ||
230 | * buffer including PHY header. | ||
231 | * 0 Reserved - Always equal to 0. | ||
232 | * | ||
233 | * RX Filter Options Table | ||
234 | * Bit Definition | ||
235 | * === ========== | ||
236 | * 31:12 Reserved - Always equal to 0. | ||
237 | * 11 Association - When set, the WiLink receives all association | ||
238 | * related frames (association request/response, reassocation | ||
239 | * request/response, and disassociation). When clear, these frames | ||
240 | * are discarded. | ||
241 | * 10 Auth/De auth - When set, the WiLink receives all authentication | ||
242 | * and de-authentication frames. When clear, these frames are | ||
243 | * discarded. | ||
244 | * 9 Beacon - When set, the WiLink receives all beacon frames. | ||
245 | * When clear, these frames are discarded. | ||
246 | * 8 Contention Free - When set, the WiLink receives all contention | ||
247 | * free frames. | ||
248 | * When clear, these frames are discarded. | ||
249 | * 7 Control - When set, the WiLink receives all control frames. | ||
250 | * When clear, these frames are discarded. | ||
251 | * 6 Data - When set, the WiLink receives all data frames. | ||
252 | * When clear, these frames are discarded. | ||
253 | * 5 FCS Error - When set, the WiLink receives frames that have FCS | ||
254 | * errors. | ||
255 | * When clear, these frames are discarded. | ||
256 | * 4 Management - When set, the WiLink receives all management | ||
257 | * frames. | ||
258 | * When clear, these frames are discarded. | ||
259 | * 3 Probe Request - When set, the WiLink receives all probe request | ||
260 | * frames. | ||
261 | * When clear, these frames are discarded. | ||
262 | * 2 Probe Response - When set, the WiLink receives all probe | ||
263 | * response frames. | ||
264 | * When clear, these frames are discarded. | ||
265 | * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK | ||
266 | * frames. | ||
267 | * When clear, these frames are discarded. | ||
268 | * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames | ||
269 | * that have reserved frame types and sub types as defined by the | ||
270 | * 802.11 specification. | ||
271 | * When clear, these frames are discarded. | ||
272 | */ | ||
273 | struct acx_rx_config { | ||
274 | struct acx_header header; | ||
275 | |||
276 | u32 config_options; | ||
277 | u32 filter_options; | ||
278 | } __attribute__ ((packed)); | ||
279 | |||
280 | struct acx_packet_detection { | ||
281 | struct acx_header header; | ||
282 | |||
283 | u32 threshold; | ||
284 | } __attribute__ ((packed)); | ||
285 | |||
286 | |||
287 | enum acx_slot_type { | ||
288 | SLOT_TIME_LONG = 0, | ||
289 | SLOT_TIME_SHORT = 1, | ||
290 | DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, | ||
291 | MAX_SLOT_TIMES = 0xFF | ||
292 | }; | ||
293 | |||
294 | #define STATION_WONE_INDEX 0 | ||
295 | |||
296 | struct acx_slot { | ||
297 | struct acx_header header; | ||
298 | |||
299 | u8 wone_index; /* Reserved */ | ||
300 | u8 slot_time; | ||
301 | u8 reserved[6]; | ||
302 | } __attribute__ ((packed)); | ||
303 | |||
304 | |||
305 | #define ADDRESS_GROUP_MAX (8) | ||
306 | #define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) | ||
307 | |||
308 | struct acx_dot11_grp_addr_tbl { | ||
309 | struct acx_header header; | ||
310 | |||
311 | u8 enabled; | ||
312 | u8 num_groups; | ||
313 | u8 pad[2]; | ||
314 | u8 mac_table[ADDRESS_GROUP_MAX_LEN]; | ||
315 | } __attribute__ ((packed)); | ||
316 | |||
317 | |||
318 | #define RX_TIMEOUT_PS_POLL_MIN 0 | ||
319 | #define RX_TIMEOUT_PS_POLL_MAX (200000) | ||
320 | #define RX_TIMEOUT_PS_POLL_DEF (15) | ||
321 | #define RX_TIMEOUT_UPSD_MIN 0 | ||
322 | #define RX_TIMEOUT_UPSD_MAX (200000) | ||
323 | #define RX_TIMEOUT_UPSD_DEF (15) | ||
324 | |||
325 | struct acx_rx_timeout { | ||
326 | struct acx_header header; | ||
327 | |||
328 | /* | ||
329 | * The longest time the STA will wait to receive | ||
330 | * traffic from the AP after a PS-poll has been | ||
331 | * transmitted. | ||
332 | */ | ||
333 | u16 ps_poll_timeout; | ||
334 | |||
335 | /* | ||
336 | * The longest time the STA will wait to receive | ||
337 | * traffic from the AP after a frame has been sent | ||
338 | * from an UPSD enabled queue. | ||
339 | */ | ||
340 | u16 upsd_timeout; | ||
341 | } __attribute__ ((packed)); | ||
342 | |||
343 | #define RTS_THRESHOLD_MIN 0 | ||
344 | #define RTS_THRESHOLD_MAX 4096 | ||
345 | #define RTS_THRESHOLD_DEF 2347 | ||
346 | |||
347 | struct acx_rts_threshold { | ||
348 | struct acx_header header; | ||
349 | |||
350 | u16 threshold; | ||
351 | u8 pad[2]; | ||
352 | } __attribute__ ((packed)); | ||
353 | |||
354 | struct acx_beacon_filter_option { | ||
355 | struct acx_header header; | ||
356 | |||
357 | u8 enable; | ||
358 | |||
359 | /* | ||
360 | * The number of beacons without the unicast TIM | ||
361 | * bit set that the firmware buffers before | ||
362 | * signaling the host about ready frames. | ||
363 | * When set to 0 and the filter is enabled, beacons | ||
364 | * without the unicast TIM bit set are dropped. | ||
365 | */ | ||
366 | u8 max_num_beacons; | ||
367 | u8 pad[2]; | ||
368 | } __attribute__ ((packed)); | ||
369 | |||
370 | /* | ||
371 | * ACXBeaconFilterEntry (not 221) | ||
372 | * Byte Offset Size (Bytes) Definition | ||
373 | * =========== ============ ========== | ||
374 | * 0 1 IE identifier | ||
375 | * 1 1 Treatment bit mask | ||
376 | * | ||
377 | * ACXBeaconFilterEntry (221) | ||
378 | * Byte Offset Size (Bytes) Definition | ||
379 | * =========== ============ ========== | ||
380 | * 0 1 IE identifier | ||
381 | * 1 1 Treatment bit mask | ||
382 | * 2 3 OUI | ||
383 | * 5 1 Type | ||
384 | * 6 2 Version | ||
385 | * | ||
386 | * | ||
387 | * Treatment bit mask - The information element handling: | ||
388 | * bit 0 - The information element is compared and transferred | ||
389 | * in case of change. | ||
390 | * bit 1 - The information element is transferred to the host | ||
391 | * with each appearance or disappearance. | ||
392 | * Note that both bits can be set at the same time. | ||
393 | */ | ||
394 | #define BEACON_FILTER_TABLE_MAX_IE_NUM (32) | ||
395 | #define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) | ||
396 | #define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) | ||
397 | #define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) | ||
398 | #define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ | ||
399 | BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ | ||
400 | (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ | ||
401 | BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) | ||
402 | |||
403 | struct acx_beacon_filter_ie_table { | ||
404 | struct acx_header header; | ||
405 | |||
406 | u8 num_ie; | ||
407 | u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; | ||
408 | u8 pad[3]; | ||
409 | } __attribute__ ((packed)); | ||
410 | |||
411 | enum { | ||
412 | SG_ENABLE = 0, | ||
413 | SG_DISABLE, | ||
414 | SG_SENSE_NO_ACTIVITY, | ||
415 | SG_SENSE_ACTIVE | ||
416 | }; | ||
417 | |||
418 | struct acx_bt_wlan_coex { | ||
419 | struct acx_header header; | ||
420 | |||
421 | /* | ||
422 | * 0 -> PTA enabled | ||
423 | * 1 -> PTA disabled | ||
424 | * 2 -> sense no active mode, i.e. | ||
425 | * an interrupt is sent upon | ||
426 | * BT activity. | ||
427 | * 3 -> PTA is switched on in response | ||
428 | * to the interrupt sending. | ||
429 | */ | ||
430 | u8 enable; | ||
431 | u8 pad[3]; | ||
432 | } __attribute__ ((packed)); | ||
433 | |||
434 | #define PTA_ANTENNA_TYPE_DEF (0) | ||
435 | #define PTA_BT_HP_MAXTIME_DEF (2000) | ||
436 | #define PTA_WLAN_HP_MAX_TIME_DEF (5000) | ||
437 | #define PTA_SENSE_DISABLE_TIMER_DEF (1350) | ||
438 | #define PTA_PROTECTIVE_RX_TIME_DEF (1500) | ||
439 | #define PTA_PROTECTIVE_TX_TIME_DEF (1500) | ||
440 | #define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) | ||
441 | #define PTA_SIGNALING_TYPE_DEF (1) | ||
442 | #define PTA_AFH_LEVERAGE_ON_DEF (0) | ||
443 | #define PTA_NUMBER_QUIET_CYCLE_DEF (0) | ||
444 | #define PTA_MAX_NUM_CTS_DEF (3) | ||
445 | #define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) | ||
446 | #define PTA_NUMBER_OF_BT_PACKETS_DEF (2) | ||
447 | #define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) | ||
448 | #define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) | ||
449 | #define PTA_CYCLE_TIME_FAST_DEF (8700) | ||
450 | #define PTA_RX_FOR_AVALANCHE_DEF (5) | ||
451 | #define PTA_ELP_HP_DEF (0) | ||
452 | #define PTA_ANTI_STARVE_PERIOD_DEF (500) | ||
453 | #define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) | ||
454 | #define PTA_ALLOW_PA_SD_DEF (1) | ||
455 | #define PTA_TIME_BEFORE_BEACON_DEF (6300) | ||
456 | #define PTA_HPDM_MAX_TIME_DEF (1600) | ||
457 | #define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) | ||
458 | #define PTA_AUTO_MODE_NO_CTS_DEF (0) | ||
459 | #define PTA_BT_HP_RESPECTED_DEF (3) | ||
460 | #define PTA_WLAN_RX_MIN_RATE_DEF (24) | ||
461 | #define PTA_ACK_MODE_DEF (1) | ||
462 | |||
463 | struct acx_bt_wlan_coex_param { | ||
464 | struct acx_header header; | ||
465 | |||
466 | /* | ||
467 | * The minimum rate of a received WLAN packet in the STA, | ||
468 | * during protective mode, of which a new BT-HP request | ||
469 | * during this Rx will always be respected and gain the antenna. | ||
470 | */ | ||
471 | u32 min_rate; | ||
472 | |||
473 | /* Max time the BT HP will be respected. */ | ||
474 | u16 bt_hp_max_time; | ||
475 | |||
476 | /* Max time the WLAN HP will be respected. */ | ||
477 | u16 wlan_hp_max_time; | ||
478 | |||
479 | /* | ||
480 | * The time between the last BT activity | ||
481 | * and the moment when the sense mode returns | ||
482 | * to SENSE_INACTIVE. | ||
483 | */ | ||
484 | u16 sense_disable_timer; | ||
485 | |||
486 | /* Time before the next BT HP instance */ | ||
487 | u16 rx_time_bt_hp; | ||
488 | u16 tx_time_bt_hp; | ||
489 | |||
490 | /* range: 10-20000 default: 1500 */ | ||
491 | u16 rx_time_bt_hp_fast; | ||
492 | u16 tx_time_bt_hp_fast; | ||
493 | |||
494 | /* range: 2000-65535 default: 8700 */ | ||
495 | u16 wlan_cycle_fast; | ||
496 | |||
497 | /* range: 0 - 15000 (Msec) default: 1000 */ | ||
498 | u16 bt_anti_starvation_period; | ||
499 | |||
500 | /* range 400-10000(Usec) default: 3000 */ | ||
501 | u16 next_bt_lp_packet; | ||
502 | |||
503 | /* Deafult: worst case for BT DH5 traffic */ | ||
504 | u16 wake_up_beacon; | ||
505 | |||
506 | /* range: 0-50000(Usec) default: 1050 */ | ||
507 | u16 hp_dm_max_guard_time; | ||
508 | |||
509 | /* | ||
510 | * This is to prevent both BT & WLAN antenna | ||
511 | * starvation. | ||
512 | * Range: 100-50000(Usec) default:2550 | ||
513 | */ | ||
514 | u16 next_wlan_packet; | ||
515 | |||
516 | /* 0 -> shared antenna */ | ||
517 | u8 antenna_type; | ||
518 | |||
519 | /* | ||
520 | * 0 -> TI legacy | ||
521 | * 1 -> Palau | ||
522 | */ | ||
523 | u8 signal_type; | ||
524 | |||
525 | /* | ||
526 | * BT AFH status | ||
527 | * 0 -> no AFH | ||
528 | * 1 -> from dedicated GPIO | ||
529 | * 2 -> AFH on (from host) | ||
530 | */ | ||
531 | u8 afh_leverage_on; | ||
532 | |||
533 | /* | ||
534 | * The number of cycles during which no | ||
535 | * TX will be sent after 1 cycle of RX | ||
536 | * transaction in protective mode | ||
537 | */ | ||
538 | u8 quiet_cycle_num; | ||
539 | |||
540 | /* | ||
541 | * The maximum number of CTSs that will | ||
542 | * be sent for receiving RX packet in | ||
543 | * protective mode | ||
544 | */ | ||
545 | u8 max_cts; | ||
546 | |||
547 | /* | ||
548 | * The number of WLAN packets | ||
549 | * transferred in common mode before | ||
550 | * switching to BT. | ||
551 | */ | ||
552 | u8 wlan_packets_num; | ||
553 | |||
554 | /* | ||
555 | * The number of BT packets | ||
556 | * transferred in common mode before | ||
557 | * switching to WLAN. | ||
558 | */ | ||
559 | u8 bt_packets_num; | ||
560 | |||
561 | /* range: 1-255 default: 5 */ | ||
562 | u8 missed_rx_avalanche; | ||
563 | |||
564 | /* range: 0-1 default: 1 */ | ||
565 | u8 wlan_elp_hp; | ||
566 | |||
567 | /* range: 0 - 15 default: 4 */ | ||
568 | u8 bt_anti_starvation_cycles; | ||
569 | |||
570 | u8 ack_mode_dual_ant; | ||
571 | |||
572 | /* | ||
573 | * Allow PA_SD assertion/de-assertion | ||
574 | * during enabled BT activity. | ||
575 | */ | ||
576 | u8 pa_sd_enable; | ||
577 | |||
578 | /* | ||
579 | * Enable/Disable PTA in auto mode: | ||
580 | * Support Both Active & P.S modes | ||
581 | */ | ||
582 | u8 pta_auto_mode_enable; | ||
583 | |||
584 | /* range: 0 - 20 default: 1 */ | ||
585 | u8 bt_hp_respected_num; | ||
586 | } __attribute__ ((packed)); | ||
587 | |||
588 | #define CCA_THRSH_ENABLE_ENERGY_D 0x140A | ||
589 | #define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF | ||
590 | |||
591 | struct acx_energy_detection { | ||
592 | struct acx_header header; | ||
593 | |||
594 | /* The RX Clear Channel Assessment threshold in the PHY */ | ||
595 | u16 rx_cca_threshold; | ||
596 | u8 tx_energy_detection; | ||
597 | u8 pad; | ||
598 | } __attribute__ ((packed)); | ||
599 | |||
600 | #define BCN_RX_TIMEOUT_DEF_VALUE 10000 | ||
601 | #define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 | ||
602 | #define RX_BROADCAST_IN_PS_DEF_VALUE 1 | ||
603 | #define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 | ||
604 | |||
605 | struct acx_beacon_broadcast { | ||
606 | struct acx_header header; | ||
607 | |||
608 | u16 beacon_rx_timeout; | ||
609 | u16 broadcast_timeout; | ||
610 | |||
611 | /* Enables receiving of broadcast packets in PS mode */ | ||
612 | u8 rx_broadcast_in_ps; | ||
613 | |||
614 | /* Consecutive PS Poll failures before updating the host */ | ||
615 | u8 ps_poll_threshold; | ||
616 | u8 pad[2]; | ||
617 | } __attribute__ ((packed)); | ||
618 | |||
619 | struct acx_event_mask { | ||
620 | struct acx_header header; | ||
621 | |||
622 | u32 event_mask; | ||
623 | u32 high_event_mask; /* Unused */ | ||
624 | } __attribute__ ((packed)); | ||
625 | |||
626 | #define CFG_RX_FCS BIT(2) | ||
627 | #define CFG_RX_ALL_GOOD BIT(3) | ||
628 | #define CFG_UNI_FILTER_EN BIT(4) | ||
629 | #define CFG_BSSID_FILTER_EN BIT(5) | ||
630 | #define CFG_MC_FILTER_EN BIT(6) | ||
631 | #define CFG_MC_ADDR0_EN BIT(7) | ||
632 | #define CFG_MC_ADDR1_EN BIT(8) | ||
633 | #define CFG_BC_REJECT_EN BIT(9) | ||
634 | #define CFG_SSID_FILTER_EN BIT(10) | ||
635 | #define CFG_RX_INT_FCS_ERROR BIT(11) | ||
636 | #define CFG_RX_INT_ENCRYPTED BIT(12) | ||
637 | #define CFG_RX_WR_RX_STATUS BIT(13) | ||
638 | #define CFG_RX_FILTER_NULTI BIT(14) | ||
639 | #define CFG_RX_RESERVE BIT(15) | ||
640 | #define CFG_RX_TIMESTAMP_TSF BIT(16) | ||
641 | |||
642 | #define CFG_RX_RSV_EN BIT(0) | ||
643 | #define CFG_RX_RCTS_ACK BIT(1) | ||
644 | #define CFG_RX_PRSP_EN BIT(2) | ||
645 | #define CFG_RX_PREQ_EN BIT(3) | ||
646 | #define CFG_RX_MGMT_EN BIT(4) | ||
647 | #define CFG_RX_FCS_ERROR BIT(5) | ||
648 | #define CFG_RX_DATA_EN BIT(6) | ||
649 | #define CFG_RX_CTL_EN BIT(7) | ||
650 | #define CFG_RX_CF_EN BIT(8) | ||
651 | #define CFG_RX_BCN_EN BIT(9) | ||
652 | #define CFG_RX_AUTH_EN BIT(10) | ||
653 | #define CFG_RX_ASSOC_EN BIT(11) | ||
654 | |||
655 | #define SCAN_PASSIVE BIT(0) | ||
656 | #define SCAN_5GHZ_BAND BIT(1) | ||
657 | #define SCAN_TRIGGERED BIT(2) | ||
658 | #define SCAN_PRIORITY_HIGH BIT(3) | ||
659 | |||
660 | struct acx_feature_config { | ||
661 | struct acx_header header; | ||
662 | |||
663 | u32 options; | ||
664 | u32 data_flow_options; | ||
665 | } __attribute__ ((packed)); | ||
666 | |||
667 | struct acx_current_tx_power { | ||
668 | struct acx_header header; | ||
669 | |||
670 | u8 current_tx_power; | ||
671 | u8 padding[3]; | ||
672 | } __attribute__ ((packed)); | ||
673 | |||
674 | enum acx_wake_up_event { | ||
675 | WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ | ||
676 | WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ | ||
677 | WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ | ||
678 | WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ | ||
679 | WAKE_UP_EVENT_BITS_MASK = 0x0F | ||
680 | }; | ||
681 | |||
682 | struct acx_wake_up_condition { | ||
683 | struct acx_header header; | ||
684 | |||
685 | u8 wake_up_event; /* Only one bit can be set */ | ||
686 | u8 listen_interval; | ||
687 | u8 pad[2]; | ||
688 | } __attribute__ ((packed)); | ||
689 | |||
690 | struct acx_aid { | ||
691 | struct acx_header header; | ||
692 | |||
693 | /* | ||
694 | * To be set when associated with an AP. | ||
695 | */ | ||
696 | u16 aid; | ||
697 | u8 pad[2]; | ||
698 | } __attribute__ ((packed)); | ||
699 | |||
700 | enum acx_preamble_type { | ||
701 | ACX_PREAMBLE_LONG = 0, | ||
702 | ACX_PREAMBLE_SHORT = 1 | ||
703 | }; | ||
704 | |||
705 | struct acx_preamble { | ||
706 | struct acx_header header; | ||
707 | |||
708 | /* | ||
709 | * When set, the WiLink transmits the frames with a short preamble and | ||
710 | * when cleared, the WiLink transmits the frames with a long preamble. | ||
711 | */ | ||
712 | u8 preamble; | ||
713 | u8 padding[3]; | ||
714 | } __attribute__ ((packed)); | ||
715 | |||
716 | enum acx_ctsprotect_type { | ||
717 | CTSPROTECT_DISABLE = 0, | ||
718 | CTSPROTECT_ENABLE = 1 | ||
719 | }; | ||
720 | |||
721 | struct acx_ctsprotect { | ||
722 | struct acx_header header; | ||
723 | u8 ctsprotect; | ||
724 | u8 padding[3]; | ||
725 | } __attribute__ ((packed)); | ||
726 | |||
727 | struct acx_tx_statistics { | ||
728 | u32 internal_desc_overflow; | ||
729 | } __attribute__ ((packed)); | ||
730 | |||
731 | struct acx_rx_statistics { | ||
732 | u32 out_of_mem; | ||
733 | u32 hdr_overflow; | ||
734 | u32 hw_stuck; | ||
735 | u32 dropped; | ||
736 | u32 fcs_err; | ||
737 | u32 xfr_hint_trig; | ||
738 | u32 path_reset; | ||
739 | u32 reset_counter; | ||
740 | } __attribute__ ((packed)); | ||
741 | |||
742 | struct acx_dma_statistics { | ||
743 | u32 rx_requested; | ||
744 | u32 rx_errors; | ||
745 | u32 tx_requested; | ||
746 | u32 tx_errors; | ||
747 | } __attribute__ ((packed)); | ||
748 | |||
749 | struct acx_isr_statistics { | ||
750 | /* host command complete */ | ||
751 | u32 cmd_cmplt; | ||
752 | |||
753 | /* fiqisr() */ | ||
754 | u32 fiqs; | ||
755 | |||
756 | /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ | ||
757 | u32 rx_headers; | ||
758 | |||
759 | /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ | ||
760 | u32 rx_completes; | ||
761 | |||
762 | /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ | ||
763 | u32 rx_mem_overflow; | ||
764 | |||
765 | /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ | ||
766 | u32 rx_rdys; | ||
767 | |||
768 | /* irqisr() */ | ||
769 | u32 irqs; | ||
770 | |||
771 | /* (INT_STS_ND & INT_TRIG_TX_PROC) */ | ||
772 | u32 tx_procs; | ||
773 | |||
774 | /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ | ||
775 | u32 decrypt_done; | ||
776 | |||
777 | /* (INT_STS_ND & INT_TRIG_DMA0) */ | ||
778 | u32 dma0_done; | ||
779 | |||
780 | /* (INT_STS_ND & INT_TRIG_DMA1) */ | ||
781 | u32 dma1_done; | ||
782 | |||
783 | /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ | ||
784 | u32 tx_exch_complete; | ||
785 | |||
786 | /* (INT_STS_ND & INT_TRIG_COMMAND) */ | ||
787 | u32 commands; | ||
788 | |||
789 | /* (INT_STS_ND & INT_TRIG_RX_PROC) */ | ||
790 | u32 rx_procs; | ||
791 | |||
792 | /* (INT_STS_ND & INT_TRIG_PM_802) */ | ||
793 | u32 hw_pm_mode_changes; | ||
794 | |||
795 | /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ | ||
796 | u32 host_acknowledges; | ||
797 | |||
798 | /* (INT_STS_ND & INT_TRIG_PM_PCI) */ | ||
799 | u32 pci_pm; | ||
800 | |||
801 | /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ | ||
802 | u32 wakeups; | ||
803 | |||
804 | /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ | ||
805 | u32 low_rssi; | ||
806 | } __attribute__ ((packed)); | ||
807 | |||
808 | struct acx_wep_statistics { | ||
809 | /* WEP address keys configured */ | ||
810 | u32 addr_key_count; | ||
811 | |||
812 | /* default keys configured */ | ||
813 | u32 default_key_count; | ||
814 | |||
815 | u32 reserved; | ||
816 | |||
817 | /* number of times that WEP key not found on lookup */ | ||
818 | u32 key_not_found; | ||
819 | |||
820 | /* number of times that WEP key decryption failed */ | ||
821 | u32 decrypt_fail; | ||
822 | |||
823 | /* WEP packets decrypted */ | ||
824 | u32 packets; | ||
825 | |||
826 | /* WEP decrypt interrupts */ | ||
827 | u32 interrupt; | ||
828 | } __attribute__ ((packed)); | ||
829 | |||
830 | #define ACX_MISSED_BEACONS_SPREAD 10 | ||
831 | |||
832 | struct acx_pwr_statistics { | ||
833 | /* the amount of enters into power save mode (both PD & ELP) */ | ||
834 | u32 ps_enter; | ||
835 | |||
836 | /* the amount of enters into ELP mode */ | ||
837 | u32 elp_enter; | ||
838 | |||
839 | /* the amount of missing beacon interrupts to the host */ | ||
840 | u32 missing_bcns; | ||
841 | |||
842 | /* the amount of wake on host-access times */ | ||
843 | u32 wake_on_host; | ||
844 | |||
845 | /* the amount of wake on timer-expire */ | ||
846 | u32 wake_on_timer_exp; | ||
847 | |||
848 | /* the number of packets that were transmitted with PS bit set */ | ||
849 | u32 tx_with_ps; | ||
850 | |||
851 | /* the number of packets that were transmitted with PS bit clear */ | ||
852 | u32 tx_without_ps; | ||
853 | |||
854 | /* the number of received beacons */ | ||
855 | u32 rcvd_beacons; | ||
856 | |||
857 | /* the number of entering into PowerOn (power save off) */ | ||
858 | u32 power_save_off; | ||
859 | |||
860 | /* the number of entries into power save mode */ | ||
861 | u16 enable_ps; | ||
862 | |||
863 | /* | ||
864 | * the number of exits from power save, not including failed PS | ||
865 | * transitions | ||
866 | */ | ||
867 | u16 disable_ps; | ||
868 | |||
869 | /* | ||
870 | * the number of times the TSF counter was adjusted because | ||
871 | * of drift | ||
872 | */ | ||
873 | u32 fix_tsf_ps; | ||
874 | |||
875 | /* Gives statistics about the spread continuous missed beacons. | ||
876 | * The 16 LSB are dedicated for the PS mode. | ||
877 | * The 16 MSB are dedicated for the PS mode. | ||
878 | * cont_miss_bcns_spread[0] - single missed beacon. | ||
879 | * cont_miss_bcns_spread[1] - two continuous missed beacons. | ||
880 | * cont_miss_bcns_spread[2] - three continuous missed beacons. | ||
881 | * ... | ||
882 | * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. | ||
883 | */ | ||
884 | u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; | ||
885 | |||
886 | /* the number of beacons in awake mode */ | ||
887 | u32 rcvd_awake_beacons; | ||
888 | } __attribute__ ((packed)); | ||
889 | |||
890 | struct acx_mic_statistics { | ||
891 | u32 rx_pkts; | ||
892 | u32 calc_failure; | ||
893 | } __attribute__ ((packed)); | ||
894 | |||
895 | struct acx_aes_statistics { | ||
896 | u32 encrypt_fail; | ||
897 | u32 decrypt_fail; | ||
898 | u32 encrypt_packets; | ||
899 | u32 decrypt_packets; | ||
900 | u32 encrypt_interrupt; | ||
901 | u32 decrypt_interrupt; | ||
902 | } __attribute__ ((packed)); | ||
903 | |||
904 | struct acx_event_statistics { | ||
905 | u32 heart_beat; | ||
906 | u32 calibration; | ||
907 | u32 rx_mismatch; | ||
908 | u32 rx_mem_empty; | ||
909 | u32 rx_pool; | ||
910 | u32 oom_late; | ||
911 | u32 phy_transmit_error; | ||
912 | u32 tx_stuck; | ||
913 | } __attribute__ ((packed)); | ||
914 | |||
915 | struct acx_ps_statistics { | ||
916 | u32 pspoll_timeouts; | ||
917 | u32 upsd_timeouts; | ||
918 | u32 upsd_max_sptime; | ||
919 | u32 upsd_max_apturn; | ||
920 | u32 pspoll_max_apturn; | ||
921 | u32 pspoll_utilization; | ||
922 | u32 upsd_utilization; | ||
923 | } __attribute__ ((packed)); | ||
924 | |||
925 | struct acx_rxpipe_statistics { | ||
926 | u32 rx_prep_beacon_drop; | ||
927 | u32 descr_host_int_trig_rx_data; | ||
928 | u32 beacon_buffer_thres_host_int_trig_rx_data; | ||
929 | u32 missed_beacon_host_int_trig_rx_data; | ||
930 | u32 tx_xfr_host_int_trig_rx_data; | ||
931 | } __attribute__ ((packed)); | ||
932 | |||
933 | struct acx_statistics { | ||
934 | struct acx_header header; | ||
935 | |||
936 | struct acx_tx_statistics tx; | ||
937 | struct acx_rx_statistics rx; | ||
938 | struct acx_dma_statistics dma; | ||
939 | struct acx_isr_statistics isr; | ||
940 | struct acx_wep_statistics wep; | ||
941 | struct acx_pwr_statistics pwr; | ||
942 | struct acx_aes_statistics aes; | ||
943 | struct acx_mic_statistics mic; | ||
944 | struct acx_event_statistics event; | ||
945 | struct acx_ps_statistics ps; | ||
946 | struct acx_rxpipe_statistics rxpipe; | ||
947 | } __attribute__ ((packed)); | ||
948 | |||
949 | #define ACX_MAX_RATE_CLASSES 8 | ||
950 | #define ACX_RATE_MASK_UNSPECIFIED 0 | ||
951 | #define ACX_RATE_MASK_ALL 0x1eff | ||
952 | #define ACX_RATE_RETRY_LIMIT 10 | ||
953 | |||
954 | struct acx_rate_class { | ||
955 | u32 enabled_rates; | ||
956 | u8 short_retry_limit; | ||
957 | u8 long_retry_limit; | ||
958 | u8 aflags; | ||
959 | u8 reserved; | ||
960 | }; | ||
961 | |||
962 | struct acx_rate_policy { | ||
963 | struct acx_header header; | ||
964 | |||
965 | u32 rate_class_cnt; | ||
966 | struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; | ||
967 | } __attribute__ ((packed)); | ||
968 | |||
969 | #define WL1271_ACX_AC_COUNT 4 | ||
970 | |||
971 | struct acx_ac_cfg { | ||
972 | struct acx_header header; | ||
973 | u8 ac; | ||
974 | u8 cw_min; | ||
975 | u16 cw_max; | ||
976 | u8 aifsn; | ||
977 | u8 reserved; | ||
978 | u16 tx_op_limit; | ||
979 | } __attribute__ ((packed)); | ||
980 | |||
981 | enum wl1271_acx_ac { | ||
982 | WL1271_ACX_AC_BE = 0, | ||
983 | WL1271_ACX_AC_BK = 1, | ||
984 | WL1271_ACX_AC_VI = 2, | ||
985 | WL1271_ACX_AC_VO = 3, | ||
986 | WL1271_ACX_AC_CTS2SELF = 4, | ||
987 | WL1271_ACX_AC_ANY_TID = 0x1F, | ||
988 | WL1271_ACX_AC_INVALID = 0xFF, | ||
989 | }; | ||
990 | |||
991 | enum wl1271_acx_ps_scheme { | ||
992 | WL1271_ACX_PS_SCHEME_LEGACY = 0, | ||
993 | WL1271_ACX_PS_SCHEME_UPSD_TRIGGER = 1, | ||
994 | WL1271_ACX_PS_SCHEME_LEGACY_PSPOLL = 2, | ||
995 | WL1271_ACX_PS_SCHEME_SAPSD = 3, | ||
996 | }; | ||
997 | |||
998 | enum wl1271_acx_ack_policy { | ||
999 | WL1271_ACX_ACK_POLICY_LEGACY = 0, | ||
1000 | WL1271_ACX_ACK_POLICY_NO_ACK = 1, | ||
1001 | WL1271_ACX_ACK_POLICY_BLOCK = 2, | ||
1002 | }; | ||
1003 | |||
1004 | #define WL1271_ACX_TID_COUNT 7 | ||
1005 | |||
1006 | struct acx_tid_config { | ||
1007 | struct acx_header header; | ||
1008 | u8 queue_id; | ||
1009 | u8 channel_type; | ||
1010 | u8 tsid; | ||
1011 | u8 ps_scheme; | ||
1012 | u8 ack_policy; | ||
1013 | u8 padding[3]; | ||
1014 | u32 apsd_conf[2]; | ||
1015 | } __attribute__ ((packed)); | ||
1016 | |||
1017 | struct acx_frag_threshold { | ||
1018 | struct acx_header header; | ||
1019 | u16 frag_threshold; | ||
1020 | u8 padding[2]; | ||
1021 | } __attribute__ ((packed)); | ||
1022 | |||
1023 | #define WL1271_ACX_TX_COMPL_TIMEOUT 5 | ||
1024 | #define WL1271_ACX_TX_COMPL_THRESHOLD 5 | ||
1025 | |||
1026 | struct acx_tx_config_options { | ||
1027 | struct acx_header header; | ||
1028 | u16 tx_compl_timeout; /* msec */ | ||
1029 | u16 tx_compl_threshold; /* number of packets */ | ||
1030 | } __attribute__ ((packed)); | ||
1031 | |||
1032 | #define ACX_RX_MEM_BLOCKS 64 | ||
1033 | #define ACX_TX_MIN_MEM_BLOCKS 64 | ||
1034 | #define ACX_TX_DESCRIPTORS 32 | ||
1035 | #define ACX_NUM_SSID_PROFILES 1 | ||
1036 | |||
1037 | struct wl1271_acx_config_memory { | ||
1038 | struct acx_header header; | ||
1039 | |||
1040 | u8 rx_mem_block_num; | ||
1041 | u8 tx_min_mem_block_num; | ||
1042 | u8 num_stations; | ||
1043 | u8 num_ssid_profiles; | ||
1044 | u32 total_tx_descriptors; | ||
1045 | } __attribute__ ((packed)); | ||
1046 | |||
1047 | struct wl1271_acx_mem_map { | ||
1048 | struct acx_header header; | ||
1049 | |||
1050 | void *code_start; | ||
1051 | void *code_end; | ||
1052 | |||
1053 | void *wep_defkey_start; | ||
1054 | void *wep_defkey_end; | ||
1055 | |||
1056 | void *sta_table_start; | ||
1057 | void *sta_table_end; | ||
1058 | |||
1059 | void *packet_template_start; | ||
1060 | void *packet_template_end; | ||
1061 | |||
1062 | /* Address of the TX result interface (control block) */ | ||
1063 | u32 tx_result; | ||
1064 | u32 tx_result_queue_start; | ||
1065 | |||
1066 | void *queue_memory_start; | ||
1067 | void *queue_memory_end; | ||
1068 | |||
1069 | u32 packet_memory_pool_start; | ||
1070 | u32 packet_memory_pool_end; | ||
1071 | |||
1072 | void *debug_buffer1_start; | ||
1073 | void *debug_buffer1_end; | ||
1074 | |||
1075 | void *debug_buffer2_start; | ||
1076 | void *debug_buffer2_end; | ||
1077 | |||
1078 | /* Number of blocks FW allocated for TX packets */ | ||
1079 | u32 num_tx_mem_blocks; | ||
1080 | |||
1081 | /* Number of blocks FW allocated for RX packets */ | ||
1082 | u32 num_rx_mem_blocks; | ||
1083 | |||
1084 | /* the following 4 fields are valid in SLAVE mode only */ | ||
1085 | u8 *tx_cbuf; | ||
1086 | u8 *rx_cbuf; | ||
1087 | void *rx_ctrl; | ||
1088 | void *tx_ctrl; | ||
1089 | } __attribute__ ((packed)); | ||
1090 | |||
1091 | enum wl1271_acx_rx_queue_type { | ||
1092 | RX_QUEUE_TYPE_RX_LOW_PRIORITY, /* All except the high priority */ | ||
1093 | RX_QUEUE_TYPE_RX_HIGH_PRIORITY, /* Management and voice packets */ | ||
1094 | RX_QUEUE_TYPE_NUM, | ||
1095 | RX_QUEUE_TYPE_MAX = USHORT_MAX | ||
1096 | }; | ||
1097 | |||
1098 | #define WL1271_RX_INTR_THRESHOLD_DEF 0 /* no pacing, send interrupt on | ||
1099 | * every event */ | ||
1100 | #define WL1271_RX_INTR_THRESHOLD_MIN 0 | ||
1101 | #define WL1271_RX_INTR_THRESHOLD_MAX 15 | ||
1102 | |||
1103 | #define WL1271_RX_INTR_TIMEOUT_DEF 5 | ||
1104 | #define WL1271_RX_INTR_TIMEOUT_MIN 1 | ||
1105 | #define WL1271_RX_INTR_TIMEOUT_MAX 100 | ||
1106 | |||
1107 | struct wl1271_acx_rx_config_opt { | ||
1108 | struct acx_header header; | ||
1109 | |||
1110 | u16 mblk_threshold; | ||
1111 | u16 threshold; | ||
1112 | u16 timeout; | ||
1113 | u8 queue_type; | ||
1114 | u8 reserved; | ||
1115 | } __attribute__ ((packed)); | ||
1116 | |||
1117 | enum { | ||
1118 | ACX_WAKE_UP_CONDITIONS = 0x0002, | ||
1119 | ACX_MEM_CFG = 0x0003, | ||
1120 | ACX_SLOT = 0x0004, | ||
1121 | ACX_AC_CFG = 0x0007, | ||
1122 | ACX_MEM_MAP = 0x0008, | ||
1123 | ACX_AID = 0x000A, | ||
1124 | /* ACX_FW_REV is missing in the ref driver, but seems to work */ | ||
1125 | ACX_FW_REV = 0x000D, | ||
1126 | ACX_MEDIUM_USAGE = 0x000F, | ||
1127 | ACX_RX_CFG = 0x0010, | ||
1128 | ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ | ||
1129 | ACX_STATISTICS = 0x0013, /* Debug API */ | ||
1130 | ACX_PWR_CONSUMPTION_STATISTICS = 0x0014, | ||
1131 | ACX_FEATURE_CFG = 0x0015, | ||
1132 | ACX_TID_CFG = 0x001A, | ||
1133 | ACX_PS_RX_STREAMING = 0x001B, | ||
1134 | ACX_BEACON_FILTER_OPT = 0x001F, | ||
1135 | ACX_NOISE_HIST = 0x0021, | ||
1136 | ACX_HDK_VERSION = 0x0022, /* ??? */ | ||
1137 | ACX_PD_THRESHOLD = 0x0023, | ||
1138 | ACX_TX_CONFIG_OPT = 0x0024, | ||
1139 | ACX_CCA_THRESHOLD = 0x0025, | ||
1140 | ACX_EVENT_MBOX_MASK = 0x0026, | ||
1141 | ACX_CONN_MONIT_PARAMS = 0x002D, | ||
1142 | ACX_CONS_TX_FAILURE = 0x002F, | ||
1143 | ACX_BCN_DTIM_OPTIONS = 0x0031, | ||
1144 | ACX_SG_ENABLE = 0x0032, | ||
1145 | ACX_SG_CFG = 0x0033, | ||
1146 | ACX_BEACON_FILTER_TABLE = 0x0038, | ||
1147 | ACX_ARP_IP_FILTER = 0x0039, | ||
1148 | ACX_ROAMING_STATISTICS_TBL = 0x003B, | ||
1149 | ACX_RATE_POLICY = 0x003D, | ||
1150 | ACX_CTS_PROTECTION = 0x003E, | ||
1151 | ACX_SLEEP_AUTH = 0x003F, | ||
1152 | ACX_PREAMBLE_TYPE = 0x0040, | ||
1153 | ACX_ERROR_CNT = 0x0041, | ||
1154 | ACX_IBSS_FILTER = 0x0044, | ||
1155 | ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, | ||
1156 | ACX_TSF_INFO = 0x0046, | ||
1157 | ACX_CONFIG_PS_WMM = 0x0049, | ||
1158 | ACX_ENABLE_RX_DATA_FILTER = 0x004A, | ||
1159 | ACX_SET_RX_DATA_FILTER = 0x004B, | ||
1160 | ACX_GET_DATA_FILTER_STATISTICS = 0x004C, | ||
1161 | ACX_RX_CONFIG_OPT = 0x004E, | ||
1162 | ACX_FRAG_CFG = 0x004F, | ||
1163 | ACX_BET_ENABLE = 0x0050, | ||
1164 | ACX_RSSI_SNR_TRIGGER = 0x0051, | ||
1165 | ACX_RSSI_SNR_WEIGHTS = 0x0051, | ||
1166 | ACX_KEEP_ALIVE_MODE = 0x0052, | ||
1167 | ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, | ||
1168 | ACX_BA_SESSION_RESPONDER_POLICY = 0x0055, | ||
1169 | ACX_BA_SESSION_INITIATOR_POLICY = 0x0056, | ||
1170 | ACX_PEER_HT_CAP = 0x0057, | ||
1171 | ACX_HT_BSS_OPERATION = 0x0058, | ||
1172 | ACX_COEX_ACTIVITY = 0x0059, | ||
1173 | DOT11_RX_MSDU_LIFE_TIME = 0x1004, | ||
1174 | DOT11_CUR_TX_PWR = 0x100D, | ||
1175 | DOT11_RX_DOT11_MODE = 0x1012, | ||
1176 | DOT11_RTS_THRESHOLD = 0x1013, | ||
1177 | DOT11_GROUP_ADDRESS_TBL = 0x1014, | ||
1178 | |||
1179 | MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, | ||
1180 | |||
1181 | MAX_IE = 0xFFFF | ||
1182 | }; | ||
1183 | |||
1184 | |||
1185 | int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event, | ||
1186 | u8 listen_interval); | ||
1187 | int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); | ||
1188 | int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len); | ||
1189 | int wl1271_acx_tx_power(struct wl1271 *wl, int power); | ||
1190 | int wl1271_acx_feature_cfg(struct wl1271 *wl); | ||
1191 | int wl1271_acx_mem_map(struct wl1271 *wl, | ||
1192 | struct acx_header *mem_map, size_t len); | ||
1193 | int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time); | ||
1194 | int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter); | ||
1195 | int wl1271_acx_pd_threshold(struct wl1271 *wl); | ||
1196 | int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time); | ||
1197 | int wl1271_acx_group_address_tbl(struct wl1271 *wl); | ||
1198 | int wl1271_acx_service_period_timeout(struct wl1271 *wl); | ||
1199 | int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); | ||
1200 | int wl1271_acx_beacon_filter_opt(struct wl1271 *wl); | ||
1201 | int wl1271_acx_beacon_filter_table(struct wl1271 *wl); | ||
1202 | int wl1271_acx_sg_enable(struct wl1271 *wl); | ||
1203 | int wl1271_acx_sg_cfg(struct wl1271 *wl); | ||
1204 | int wl1271_acx_cca_threshold(struct wl1271 *wl); | ||
1205 | int wl1271_acx_bcn_dtim_options(struct wl1271 *wl); | ||
1206 | int wl1271_acx_aid(struct wl1271 *wl, u16 aid); | ||
1207 | int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask); | ||
1208 | int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); | ||
1209 | int wl1271_acx_cts_protect(struct wl1271 *wl, | ||
1210 | enum acx_ctsprotect_type ctsprotect); | ||
1211 | int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); | ||
1212 | int wl1271_acx_rate_policies(struct wl1271 *wl); | ||
1213 | int wl1271_acx_ac_cfg(struct wl1271 *wl); | ||
1214 | int wl1271_acx_tid_cfg(struct wl1271 *wl); | ||
1215 | int wl1271_acx_frag_threshold(struct wl1271 *wl); | ||
1216 | int wl1271_acx_tx_config_options(struct wl1271 *wl); | ||
1217 | int wl1271_acx_mem_cfg(struct wl1271 *wl); | ||
1218 | int wl1271_acx_init_mem_config(struct wl1271 *wl); | ||
1219 | int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); | ||
1220 | |||
1221 | #endif /* __WL1271_ACX_H__ */ | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c new file mode 100644 index 000000000000..8228ef474a7e --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c | |||
@@ -0,0 +1,541 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/gpio.h> | ||
25 | |||
26 | #include "wl1271_acx.h" | ||
27 | #include "wl1271_reg.h" | ||
28 | #include "wl1271_boot.h" | ||
29 | #include "wl1271_spi.h" | ||
30 | #include "wl1271_event.h" | ||
31 | |||
32 | static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { | ||
33 | [PART_DOWN] = { | ||
34 | .mem = { | ||
35 | .start = 0x00000000, | ||
36 | .size = 0x000177c0 | ||
37 | }, | ||
38 | .reg = { | ||
39 | .start = REGISTERS_BASE, | ||
40 | .size = 0x00008800 | ||
41 | }, | ||
42 | }, | ||
43 | |||
44 | [PART_WORK] = { | ||
45 | .mem = { | ||
46 | .start = 0x00040000, | ||
47 | .size = 0x00014fc0 | ||
48 | }, | ||
49 | .reg = { | ||
50 | .start = REGISTERS_BASE, | ||
51 | .size = 0x0000b000 | ||
52 | }, | ||
53 | }, | ||
54 | |||
55 | [PART_DRPW] = { | ||
56 | .mem = { | ||
57 | .start = 0x00040000, | ||
58 | .size = 0x00014fc0 | ||
59 | }, | ||
60 | .reg = { | ||
61 | .start = DRPW_BASE, | ||
62 | .size = 0x00006000 | ||
63 | } | ||
64 | } | ||
65 | }; | ||
66 | |||
67 | static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) | ||
68 | { | ||
69 | u32 cpu_ctrl; | ||
70 | |||
71 | /* 10.5.0 run the firmware (I) */ | ||
72 | cpu_ctrl = wl1271_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
73 | |||
74 | /* 10.5.1 run the firmware (II) */ | ||
75 | cpu_ctrl |= flag; | ||
76 | wl1271_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); | ||
77 | } | ||
78 | |||
79 | static void wl1271_boot_fw_version(struct wl1271 *wl) | ||
80 | { | ||
81 | struct wl1271_static_data static_data; | ||
82 | |||
83 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, | ||
84 | &static_data, sizeof(static_data)); | ||
85 | |||
86 | strncpy(wl->chip.fw_ver, static_data.fw_version, | ||
87 | sizeof(wl->chip.fw_ver)); | ||
88 | |||
89 | /* make sure the string is NULL-terminated */ | ||
90 | wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0'; | ||
91 | } | ||
92 | |||
93 | static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, | ||
94 | size_t fw_data_len, u32 dest) | ||
95 | { | ||
96 | int addr, chunk_num, partition_limit; | ||
97 | u8 *p; | ||
98 | |||
99 | /* whal_FwCtrl_LoadFwImageSm() */ | ||
100 | |||
101 | wl1271_debug(DEBUG_BOOT, "starting firmware upload"); | ||
102 | |||
103 | wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d", | ||
104 | fw_data_len, CHUNK_SIZE); | ||
105 | |||
106 | |||
107 | if ((fw_data_len % 4) != 0) { | ||
108 | wl1271_error("firmware length not multiple of four"); | ||
109 | return -EIO; | ||
110 | } | ||
111 | |||
112 | wl1271_set_partition(wl, dest, | ||
113 | part_table[PART_DOWN].mem.size, | ||
114 | part_table[PART_DOWN].reg.start, | ||
115 | part_table[PART_DOWN].reg.size); | ||
116 | |||
117 | /* 10.1 set partition limit and chunk num */ | ||
118 | chunk_num = 0; | ||
119 | partition_limit = part_table[PART_DOWN].mem.size; | ||
120 | |||
121 | while (chunk_num < fw_data_len / CHUNK_SIZE) { | ||
122 | /* 10.2 update partition, if needed */ | ||
123 | addr = dest + (chunk_num + 2) * CHUNK_SIZE; | ||
124 | if (addr > partition_limit) { | ||
125 | addr = dest + chunk_num * CHUNK_SIZE; | ||
126 | partition_limit = chunk_num * CHUNK_SIZE + | ||
127 | part_table[PART_DOWN].mem.size; | ||
128 | |||
129 | /* FIXME: Over 80 chars! */ | ||
130 | wl1271_set_partition(wl, | ||
131 | addr, | ||
132 | part_table[PART_DOWN].mem.size, | ||
133 | part_table[PART_DOWN].reg.start, | ||
134 | part_table[PART_DOWN].reg.size); | ||
135 | } | ||
136 | |||
137 | /* 10.3 upload the chunk */ | ||
138 | addr = dest + chunk_num * CHUNK_SIZE; | ||
139 | p = buf + chunk_num * CHUNK_SIZE; | ||
140 | wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", | ||
141 | p, addr); | ||
142 | wl1271_spi_mem_write(wl, addr, p, CHUNK_SIZE); | ||
143 | |||
144 | chunk_num++; | ||
145 | } | ||
146 | |||
147 | /* 10.4 upload the last chunk */ | ||
148 | addr = dest + chunk_num * CHUNK_SIZE; | ||
149 | p = buf + chunk_num * CHUNK_SIZE; | ||
150 | wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", | ||
151 | fw_data_len % CHUNK_SIZE, p, addr); | ||
152 | wl1271_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int wl1271_boot_upload_firmware(struct wl1271 *wl) | ||
158 | { | ||
159 | u32 chunks, addr, len; | ||
160 | u8 *fw; | ||
161 | |||
162 | fw = wl->fw; | ||
163 | chunks = be32_to_cpup((u32 *) fw); | ||
164 | fw += sizeof(u32); | ||
165 | |||
166 | wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks); | ||
167 | |||
168 | while (chunks--) { | ||
169 | addr = be32_to_cpup((u32 *) fw); | ||
170 | fw += sizeof(u32); | ||
171 | len = be32_to_cpup((u32 *) fw); | ||
172 | fw += sizeof(u32); | ||
173 | |||
174 | if (len > 300000) { | ||
175 | wl1271_info("firmware chunk too long: %u", len); | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u", | ||
179 | chunks, addr, len); | ||
180 | wl1271_boot_upload_firmware_chunk(wl, fw, len, addr); | ||
181 | fw += len; | ||
182 | } | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int wl1271_boot_upload_nvs(struct wl1271 *wl) | ||
188 | { | ||
189 | size_t nvs_len, burst_len; | ||
190 | int i; | ||
191 | u32 dest_addr, val; | ||
192 | u8 *nvs_ptr, *nvs, *nvs_aligned; | ||
193 | |||
194 | nvs = wl->nvs; | ||
195 | if (nvs == NULL) | ||
196 | return -ENODEV; | ||
197 | |||
198 | nvs_ptr = nvs; | ||
199 | |||
200 | nvs_len = wl->nvs_len; | ||
201 | |||
202 | /* Update the device MAC address into the nvs */ | ||
203 | nvs[11] = wl->mac_addr[0]; | ||
204 | nvs[10] = wl->mac_addr[1]; | ||
205 | nvs[6] = wl->mac_addr[2]; | ||
206 | nvs[5] = wl->mac_addr[3]; | ||
207 | nvs[4] = wl->mac_addr[4]; | ||
208 | nvs[3] = wl->mac_addr[5]; | ||
209 | |||
210 | /* | ||
211 | * Layout before the actual NVS tables: | ||
212 | * 1 byte : burst length. | ||
213 | * 2 bytes: destination address. | ||
214 | * n bytes: data to burst copy. | ||
215 | * | ||
216 | * This is ended by a 0 length, then the NVS tables. | ||
217 | */ | ||
218 | |||
219 | /* FIXME: Do we need to check here whether the LSB is 1? */ | ||
220 | while (nvs_ptr[0]) { | ||
221 | burst_len = nvs_ptr[0]; | ||
222 | dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); | ||
223 | |||
224 | /* FIXME: Due to our new wl1271_translate_reg_addr function, | ||
225 | we need to add the REGISTER_BASE to the destination */ | ||
226 | dest_addr += REGISTERS_BASE; | ||
227 | |||
228 | /* We move our pointer to the data */ | ||
229 | nvs_ptr += 3; | ||
230 | |||
231 | for (i = 0; i < burst_len; i++) { | ||
232 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
233 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
234 | |||
235 | wl1271_debug(DEBUG_BOOT, | ||
236 | "nvs burst write 0x%x: 0x%x", | ||
237 | dest_addr, val); | ||
238 | wl1271_reg_write32(wl, dest_addr, val); | ||
239 | |||
240 | nvs_ptr += 4; | ||
241 | dest_addr += 4; | ||
242 | } | ||
243 | } | ||
244 | |||
245 | /* | ||
246 | * We've reached the first zero length, the first NVS table | ||
247 | * is 7 bytes further. | ||
248 | */ | ||
249 | nvs_ptr += 7; | ||
250 | nvs_len -= nvs_ptr - nvs; | ||
251 | nvs_len = ALIGN(nvs_len, 4); | ||
252 | |||
253 | /* FIXME: The driver sets the partition here, but this is not needed, | ||
254 | since it sets to the same one as currently in use */ | ||
255 | /* Now we must set the partition correctly */ | ||
256 | wl1271_set_partition(wl, | ||
257 | part_table[PART_WORK].mem.start, | ||
258 | part_table[PART_WORK].mem.size, | ||
259 | part_table[PART_WORK].reg.start, | ||
260 | part_table[PART_WORK].reg.size); | ||
261 | |||
262 | /* Copy the NVS tables to a new block to ensure alignment */ | ||
263 | nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); | ||
264 | |||
265 | /* And finally we upload the NVS tables */ | ||
266 | /* FIXME: In wl1271, we upload everything at once. | ||
267 | No endianness handling needed here?! The ref driver doesn't do | ||
268 | anything about it at this point */ | ||
269 | wl1271_spi_mem_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len); | ||
270 | |||
271 | kfree(nvs_aligned); | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static void wl1271_boot_enable_interrupts(struct wl1271 *wl) | ||
276 | { | ||
277 | enable_irq(wl->irq); | ||
278 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
279 | WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); | ||
280 | wl1271_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); | ||
281 | } | ||
282 | |||
283 | static int wl1271_boot_soft_reset(struct wl1271 *wl) | ||
284 | { | ||
285 | unsigned long timeout; | ||
286 | u32 boot_data; | ||
287 | |||
288 | /* perform soft reset */ | ||
289 | wl1271_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); | ||
290 | |||
291 | /* SOFT_RESET is self clearing */ | ||
292 | timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); | ||
293 | while (1) { | ||
294 | boot_data = wl1271_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); | ||
295 | wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); | ||
296 | if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) | ||
297 | break; | ||
298 | |||
299 | if (time_after(jiffies, timeout)) { | ||
300 | /* 1.2 check pWhalBus->uSelfClearTime if the | ||
301 | * timeout was reached */ | ||
302 | wl1271_error("soft reset timeout"); | ||
303 | return -1; | ||
304 | } | ||
305 | |||
306 | udelay(SOFT_RESET_STALL_TIME); | ||
307 | } | ||
308 | |||
309 | /* disable Rx/Tx */ | ||
310 | wl1271_reg_write32(wl, ENABLE, 0x0); | ||
311 | |||
312 | /* disable auto calibration on start*/ | ||
313 | wl1271_reg_write32(wl, SPARE_A2, 0xffff); | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int wl1271_boot_run_firmware(struct wl1271 *wl) | ||
319 | { | ||
320 | int loop, ret; | ||
321 | u32 chip_id, interrupt; | ||
322 | |||
323 | wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); | ||
324 | |||
325 | chip_id = wl1271_reg_read32(wl, CHIP_ID_B); | ||
326 | |||
327 | wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); | ||
328 | |||
329 | if (chip_id != wl->chip.id) { | ||
330 | wl1271_error("chip id doesn't match after firmware boot"); | ||
331 | return -EIO; | ||
332 | } | ||
333 | |||
334 | /* wait for init to complete */ | ||
335 | loop = 0; | ||
336 | while (loop++ < INIT_LOOP) { | ||
337 | udelay(INIT_LOOP_DELAY); | ||
338 | interrupt = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
339 | |||
340 | if (interrupt == 0xffffffff) { | ||
341 | wl1271_error("error reading hardware complete " | ||
342 | "init indication"); | ||
343 | return -EIO; | ||
344 | } | ||
345 | /* check that ACX_INTR_INIT_COMPLETE is enabled */ | ||
346 | else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) { | ||
347 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | ||
348 | WL1271_ACX_INTR_INIT_COMPLETE); | ||
349 | break; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | if (loop >= INIT_LOOP) { | ||
354 | wl1271_error("timeout waiting for the hardware to " | ||
355 | "complete initialization"); | ||
356 | return -EIO; | ||
357 | } | ||
358 | |||
359 | /* get hardware config command mail box */ | ||
360 | wl->cmd_box_addr = wl1271_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); | ||
361 | |||
362 | /* get hardware config event mail box */ | ||
363 | wl->event_box_addr = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR); | ||
364 | |||
365 | /* set the working partition to its "running" mode offset */ | ||
366 | wl1271_set_partition(wl, | ||
367 | part_table[PART_WORK].mem.start, | ||
368 | part_table[PART_WORK].mem.size, | ||
369 | part_table[PART_WORK].reg.start, | ||
370 | part_table[PART_WORK].reg.size); | ||
371 | |||
372 | wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", | ||
373 | wl->cmd_box_addr, wl->event_box_addr); | ||
374 | |||
375 | wl1271_boot_fw_version(wl); | ||
376 | |||
377 | /* | ||
378 | * in case of full asynchronous mode the firmware event must be | ||
379 | * ready to receive event from the command mailbox | ||
380 | */ | ||
381 | |||
382 | /* enable gpio interrupts */ | ||
383 | wl1271_boot_enable_interrupts(wl); | ||
384 | |||
385 | /* unmask all mbox events */ | ||
386 | wl->event_mask = 0xffffffff; | ||
387 | |||
388 | ret = wl1271_event_unmask(wl); | ||
389 | if (ret < 0) { | ||
390 | wl1271_error("EVENT mask setting failed"); | ||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | wl1271_event_mbox_config(wl); | ||
395 | |||
396 | /* firmware startup completed */ | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static int wl1271_boot_write_irq_polarity(struct wl1271 *wl) | ||
401 | { | ||
402 | u32 polarity, status, i; | ||
403 | |||
404 | wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY); | ||
405 | wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ); | ||
406 | |||
407 | /* Wait until the command is complete (ie. bit 18 is set) */ | ||
408 | for (i = 0; i < OCP_CMD_LOOP; i++) { | ||
409 | polarity = wl1271_reg_read32(wl, OCP_DATA_READ); | ||
410 | if (polarity & OCP_READY_MASK) | ||
411 | break; | ||
412 | } | ||
413 | if (i == OCP_CMD_LOOP) { | ||
414 | wl1271_error("OCP command timeout!"); | ||
415 | return -EIO; | ||
416 | } | ||
417 | |||
418 | status = polarity & OCP_STATUS_MASK; | ||
419 | if (status != OCP_STATUS_OK) { | ||
420 | wl1271_error("OCP command failed (%d)", status); | ||
421 | return -EIO; | ||
422 | } | ||
423 | |||
424 | /* We use HIGH polarity, so unset the LOW bit */ | ||
425 | polarity &= ~POLARITY_LOW; | ||
426 | |||
427 | wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY); | ||
428 | wl1271_reg_write32(wl, OCP_DATA_WRITE, polarity); | ||
429 | wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE); | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | int wl1271_boot(struct wl1271 *wl) | ||
435 | { | ||
436 | int ret = 0; | ||
437 | u32 tmp, clk, pause; | ||
438 | |||
439 | if (REF_CLOCK == 0 || REF_CLOCK == 2) | ||
440 | /* ref clk: 19.2/38.4 */ | ||
441 | clk = 0x3; | ||
442 | else if (REF_CLOCK == 1 || REF_CLOCK == 3) | ||
443 | /* ref clk: 26/52 */ | ||
444 | clk = 0x5; | ||
445 | |||
446 | wl1271_reg_write32(wl, PLL_PARAMETERS, clk); | ||
447 | |||
448 | pause = wl1271_reg_read32(wl, PLL_PARAMETERS); | ||
449 | |||
450 | wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); | ||
451 | |||
452 | pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be | ||
453 | * WU_COUNTER_PAUSE_VAL instead of | ||
454 | * 0x3ff (magic number ). How does | ||
455 | * this work?! */ | ||
456 | pause |= WU_COUNTER_PAUSE_VAL; | ||
457 | wl1271_reg_write32(wl, WU_COUNTER_PAUSE, pause); | ||
458 | |||
459 | /* Continue the ELP wake up sequence */ | ||
460 | wl1271_reg_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); | ||
461 | udelay(500); | ||
462 | |||
463 | wl1271_set_partition(wl, | ||
464 | part_table[PART_DRPW].mem.start, | ||
465 | part_table[PART_DRPW].mem.size, | ||
466 | part_table[PART_DRPW].reg.start, | ||
467 | part_table[PART_DRPW].reg.size); | ||
468 | |||
469 | /* Read-modify-write DRPW_SCRATCH_START register (see next state) | ||
470 | to be used by DRPw FW. The RTRIM value will be added by the FW | ||
471 | before taking DRPw out of reset */ | ||
472 | |||
473 | wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START); | ||
474 | clk = wl1271_reg_read32(wl, DRPW_SCRATCH_START); | ||
475 | |||
476 | wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); | ||
477 | |||
478 | /* 2 */ | ||
479 | clk |= (REF_CLOCK << 1) << 4; | ||
480 | wl1271_reg_write32(wl, DRPW_SCRATCH_START, clk); | ||
481 | |||
482 | wl1271_set_partition(wl, | ||
483 | part_table[PART_WORK].mem.start, | ||
484 | part_table[PART_WORK].mem.size, | ||
485 | part_table[PART_WORK].reg.start, | ||
486 | part_table[PART_WORK].reg.size); | ||
487 | |||
488 | /* Disable interrupts */ | ||
489 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); | ||
490 | |||
491 | ret = wl1271_boot_soft_reset(wl); | ||
492 | if (ret < 0) | ||
493 | goto out; | ||
494 | |||
495 | /* 2. start processing NVS file */ | ||
496 | ret = wl1271_boot_upload_nvs(wl); | ||
497 | if (ret < 0) | ||
498 | goto out; | ||
499 | |||
500 | /* write firmware's last address (ie. it's length) to | ||
501 | * ACX_EEPROMLESS_IND_REG */ | ||
502 | wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); | ||
503 | |||
504 | wl1271_reg_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG); | ||
505 | |||
506 | tmp = wl1271_reg_read32(wl, CHIP_ID_B); | ||
507 | |||
508 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); | ||
509 | |||
510 | /* 6. read the EEPROM parameters */ | ||
511 | tmp = wl1271_reg_read32(wl, SCR_PAD2); | ||
512 | |||
513 | ret = wl1271_boot_write_irq_polarity(wl); | ||
514 | if (ret < 0) | ||
515 | goto out; | ||
516 | |||
517 | /* FIXME: Need to check whether this is really what we want */ | ||
518 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
519 | WL1271_ACX_ALL_EVENTS_VECTOR); | ||
520 | |||
521 | /* WL1271: The reference driver skips steps 7 to 10 (jumps directly | ||
522 | * to upload_fw) */ | ||
523 | |||
524 | ret = wl1271_boot_upload_firmware(wl); | ||
525 | if (ret < 0) | ||
526 | goto out; | ||
527 | |||
528 | /* 10.5 start firmware */ | ||
529 | ret = wl1271_boot_run_firmware(wl); | ||
530 | if (ret < 0) | ||
531 | goto out; | ||
532 | |||
533 | /* set the wl1271 default filters */ | ||
534 | wl->rx_config = WL1271_DEFAULT_RX_CONFIG; | ||
535 | wl->rx_filter = WL1271_DEFAULT_RX_FILTER; | ||
536 | |||
537 | wl1271_event_mbox_config(wl); | ||
538 | |||
539 | out: | ||
540 | return ret; | ||
541 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.h b/drivers/net/wireless/wl12xx/wl1271_boot.h new file mode 100644 index 000000000000..b0d8fb46a439 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_boot.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __BOOT_H__ | ||
25 | #define __BOOT_H__ | ||
26 | |||
27 | #include "wl1271.h" | ||
28 | |||
29 | int wl1271_boot(struct wl1271 *wl); | ||
30 | |||
31 | #define WL1271_NO_SUBBANDS 8 | ||
32 | #define WL1271_NO_POWER_LEVELS 4 | ||
33 | #define WL1271_FW_VERSION_MAX_LEN 20 | ||
34 | |||
35 | struct wl1271_static_data { | ||
36 | u8 mac_address[ETH_ALEN]; | ||
37 | u8 padding[2]; | ||
38 | u8 fw_version[WL1271_FW_VERSION_MAX_LEN]; | ||
39 | u32 hw_version; | ||
40 | u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS]; | ||
41 | }; | ||
42 | |||
43 | /* number of times we try to read the INIT interrupt */ | ||
44 | #define INIT_LOOP 20000 | ||
45 | |||
46 | /* delay between retries */ | ||
47 | #define INIT_LOOP_DELAY 50 | ||
48 | |||
49 | #define REF_CLOCK 2 | ||
50 | #define WU_COUNTER_PAUSE_VAL 0x3FF | ||
51 | #define WELP_ARM_COMMAND_VAL 0x4 | ||
52 | |||
53 | #define OCP_CMD_LOOP 32 | ||
54 | |||
55 | #define OCP_CMD_WRITE 0x1 | ||
56 | #define OCP_CMD_READ 0x2 | ||
57 | |||
58 | #define OCP_READY_MASK BIT(18) | ||
59 | #define OCP_STATUS_MASK (BIT(16) | BIT(17)) | ||
60 | |||
61 | #define OCP_STATUS_NO_RESP 0x00000 | ||
62 | #define OCP_STATUS_OK 0x10000 | ||
63 | #define OCP_STATUS_REQ_FAILED 0x20000 | ||
64 | #define OCP_STATUS_RESP_ERROR 0x30000 | ||
65 | |||
66 | #define OCP_REG_POLARITY 0x30032 | ||
67 | |||
68 | #define CMD_MBOX_ADDRESS 0x407B4 | ||
69 | |||
70 | #define POLARITY_LOW BIT(1) | ||
71 | |||
72 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c new file mode 100644 index 000000000000..2a4351ff54dc --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c | |||
@@ -0,0 +1,813 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/crc7.h> | ||
27 | #include <linux/spi/spi.h> | ||
28 | #include <linux/etherdevice.h> | ||
29 | |||
30 | #include "wl1271.h" | ||
31 | #include "wl1271_reg.h" | ||
32 | #include "wl1271_spi.h" | ||
33 | #include "wl1271_acx.h" | ||
34 | #include "wl12xx_80211.h" | ||
35 | #include "wl1271_cmd.h" | ||
36 | |||
37 | /* | ||
38 | * send command to firmware | ||
39 | * | ||
40 | * @wl: wl struct | ||
41 | * @id: command id | ||
42 | * @buf: buffer containing the command, must work with dma | ||
43 | * @len: length of the buffer | ||
44 | */ | ||
45 | int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) | ||
46 | { | ||
47 | struct wl1271_cmd_header *cmd; | ||
48 | unsigned long timeout; | ||
49 | u32 intr; | ||
50 | int ret = 0; | ||
51 | |||
52 | cmd = buf; | ||
53 | cmd->id = id; | ||
54 | cmd->status = 0; | ||
55 | |||
56 | WARN_ON(len % 4 != 0); | ||
57 | |||
58 | wl1271_spi_mem_write(wl, wl->cmd_box_addr, buf, len); | ||
59 | |||
60 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); | ||
61 | |||
62 | timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); | ||
63 | |||
64 | intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
65 | while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { | ||
66 | if (time_after(jiffies, timeout)) { | ||
67 | wl1271_error("command complete timeout"); | ||
68 | ret = -ETIMEDOUT; | ||
69 | goto out; | ||
70 | } | ||
71 | |||
72 | msleep(1); | ||
73 | |||
74 | intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
75 | } | ||
76 | |||
77 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | ||
78 | WL1271_ACX_INTR_CMD_COMPLETE); | ||
79 | |||
80 | out: | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | int wl1271_cmd_cal_channel_tune(struct wl1271 *wl) | ||
85 | { | ||
86 | struct wl1271_cmd_cal_channel_tune *cmd; | ||
87 | int ret = 0; | ||
88 | |||
89 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
90 | if (!cmd) | ||
91 | return -ENOMEM; | ||
92 | |||
93 | cmd->test.id = TEST_CMD_CHANNEL_TUNE; | ||
94 | |||
95 | cmd->band = WL1271_CHANNEL_TUNE_BAND_2_4; | ||
96 | /* set up any channel, 7 is in the middle of the range */ | ||
97 | cmd->channel = 7; | ||
98 | |||
99 | ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); | ||
100 | if (ret < 0) | ||
101 | wl1271_warning("TEST_CMD_CHANNEL_TUNE failed"); | ||
102 | |||
103 | kfree(cmd); | ||
104 | return ret; | ||
105 | } | ||
106 | |||
107 | int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl) | ||
108 | { | ||
109 | struct wl1271_cmd_cal_update_ref_point *cmd; | ||
110 | int ret = 0; | ||
111 | |||
112 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
113 | if (!cmd) | ||
114 | return -ENOMEM; | ||
115 | |||
116 | cmd->test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT; | ||
117 | |||
118 | /* FIXME: still waiting for the correct values */ | ||
119 | cmd->ref_power = 0; | ||
120 | cmd->ref_detector = 0; | ||
121 | |||
122 | cmd->sub_band = WL1271_PD_REFERENCE_POINT_BAND_B_G; | ||
123 | |||
124 | ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); | ||
125 | if (ret < 0) | ||
126 | wl1271_warning("TEST_CMD_UPDATE_PD_REFERENCE_POINT failed"); | ||
127 | |||
128 | kfree(cmd); | ||
129 | return ret; | ||
130 | } | ||
131 | |||
132 | int wl1271_cmd_cal_p2g(struct wl1271 *wl) | ||
133 | { | ||
134 | struct wl1271_cmd_cal_p2g *cmd; | ||
135 | int ret = 0; | ||
136 | |||
137 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
138 | if (!cmd) | ||
139 | return -ENOMEM; | ||
140 | |||
141 | cmd->test.id = TEST_CMD_P2G_CAL; | ||
142 | |||
143 | cmd->sub_band_mask = WL1271_CAL_P2G_BAND_B_G; | ||
144 | |||
145 | ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); | ||
146 | if (ret < 0) | ||
147 | wl1271_warning("TEST_CMD_P2G_CAL failed"); | ||
148 | |||
149 | kfree(cmd); | ||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | int wl1271_cmd_cal(struct wl1271 *wl) | ||
154 | { | ||
155 | /* | ||
156 | * FIXME: we must make sure that we're not sleeping when calibration | ||
157 | * is done | ||
158 | */ | ||
159 | int ret; | ||
160 | |||
161 | wl1271_notice("performing tx calibration"); | ||
162 | |||
163 | ret = wl1271_cmd_cal_channel_tune(wl); | ||
164 | if (ret < 0) | ||
165 | return ret; | ||
166 | |||
167 | ret = wl1271_cmd_cal_update_ref_point(wl); | ||
168 | if (ret < 0) | ||
169 | return ret; | ||
170 | |||
171 | ret = wl1271_cmd_cal_p2g(wl); | ||
172 | if (ret < 0) | ||
173 | return ret; | ||
174 | |||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, | ||
179 | u16 beacon_interval, u8 wait) | ||
180 | { | ||
181 | static bool do_cal = true; | ||
182 | unsigned long timeout; | ||
183 | struct wl1271_cmd_join *join; | ||
184 | int ret, i; | ||
185 | u8 *bssid; | ||
186 | |||
187 | /* FIXME: remove when we get calibration from the factory */ | ||
188 | if (do_cal) { | ||
189 | ret = wl1271_cmd_cal(wl); | ||
190 | if (ret < 0) | ||
191 | wl1271_warning("couldn't calibrate"); | ||
192 | else | ||
193 | do_cal = false; | ||
194 | } | ||
195 | |||
196 | |||
197 | join = kzalloc(sizeof(*join), GFP_KERNEL); | ||
198 | if (!join) { | ||
199 | ret = -ENOMEM; | ||
200 | goto out; | ||
201 | } | ||
202 | |||
203 | wl1271_debug(DEBUG_CMD, "cmd join"); | ||
204 | |||
205 | /* Reverse order BSSID */ | ||
206 | bssid = (u8 *) &join->bssid_lsb; | ||
207 | for (i = 0; i < ETH_ALEN; i++) | ||
208 | bssid[i] = wl->bssid[ETH_ALEN - i - 1]; | ||
209 | |||
210 | join->rx_config_options = wl->rx_config; | ||
211 | join->rx_filter_options = wl->rx_filter; | ||
212 | |||
213 | join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | | ||
214 | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; | ||
215 | |||
216 | join->beacon_interval = beacon_interval; | ||
217 | join->dtim_interval = dtim_interval; | ||
218 | join->bss_type = bss_type; | ||
219 | join->channel = wl->channel; | ||
220 | join->ssid_len = wl->ssid_len; | ||
221 | memcpy(join->ssid, wl->ssid, wl->ssid_len); | ||
222 | join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH; | ||
223 | |||
224 | /* increment the session counter */ | ||
225 | wl->session_counter++; | ||
226 | if (wl->session_counter >= SESSION_COUNTER_MAX) | ||
227 | wl->session_counter = 0; | ||
228 | |||
229 | join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; | ||
230 | |||
231 | |||
232 | ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); | ||
233 | if (ret < 0) { | ||
234 | wl1271_error("failed to initiate cmd join"); | ||
235 | goto out_free; | ||
236 | } | ||
237 | |||
238 | timeout = msecs_to_jiffies(JOIN_TIMEOUT); | ||
239 | |||
240 | /* | ||
241 | * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to | ||
242 | * simplify locking we just sleep instead, for now | ||
243 | */ | ||
244 | if (wait) | ||
245 | msleep(10); | ||
246 | |||
247 | out_free: | ||
248 | kfree(join); | ||
249 | |||
250 | out: | ||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * send test command to firmware | ||
256 | * | ||
257 | * @wl: wl struct | ||
258 | * @buf: buffer containing the command, with all headers, must work with dma | ||
259 | * @len: length of the buffer | ||
260 | * @answer: is answer needed | ||
261 | */ | ||
262 | int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) | ||
263 | { | ||
264 | int ret; | ||
265 | |||
266 | wl1271_debug(DEBUG_CMD, "cmd test"); | ||
267 | |||
268 | ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len); | ||
269 | |||
270 | if (ret < 0) { | ||
271 | wl1271_warning("TEST command failed"); | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | if (answer) { | ||
276 | struct wl1271_command *cmd_answer; | ||
277 | |||
278 | /* | ||
279 | * The test command got in, we can read the answer. | ||
280 | * The answer would be a wl1271_command, where the | ||
281 | * parameter array contains the actual answer. | ||
282 | */ | ||
283 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); | ||
284 | |||
285 | cmd_answer = buf; | ||
286 | |||
287 | if (cmd_answer->header.status != CMD_STATUS_SUCCESS) | ||
288 | wl1271_error("TEST command answer error: %d", | ||
289 | cmd_answer->header.status); | ||
290 | } | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * read acx from firmware | ||
297 | * | ||
298 | * @wl: wl struct | ||
299 | * @id: acx id | ||
300 | * @buf: buffer for the response, including all headers, must work with dma | ||
301 | * @len: lenght of buf | ||
302 | */ | ||
303 | int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) | ||
304 | { | ||
305 | struct acx_header *acx = buf; | ||
306 | int ret; | ||
307 | |||
308 | wl1271_debug(DEBUG_CMD, "cmd interrogate"); | ||
309 | |||
310 | acx->id = id; | ||
311 | |||
312 | /* payload length, does not include any headers */ | ||
313 | acx->len = len - sizeof(*acx); | ||
314 | |||
315 | ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); | ||
316 | if (ret < 0) { | ||
317 | wl1271_error("INTERROGATE command failed"); | ||
318 | goto out; | ||
319 | } | ||
320 | |||
321 | /* the interrogate command got in, we can read the answer */ | ||
322 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, len); | ||
323 | |||
324 | acx = buf; | ||
325 | if (acx->cmd.status != CMD_STATUS_SUCCESS) | ||
326 | wl1271_error("INTERROGATE command error: %d", | ||
327 | acx->cmd.status); | ||
328 | |||
329 | out: | ||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | /** | ||
334 | * write acx value to firmware | ||
335 | * | ||
336 | * @wl: wl struct | ||
337 | * @id: acx id | ||
338 | * @buf: buffer containing acx, including all headers, must work with dma | ||
339 | * @len: length of buf | ||
340 | */ | ||
341 | int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) | ||
342 | { | ||
343 | struct acx_header *acx = buf; | ||
344 | int ret; | ||
345 | |||
346 | wl1271_debug(DEBUG_CMD, "cmd configure"); | ||
347 | |||
348 | acx->id = id; | ||
349 | |||
350 | /* payload length, does not include any headers */ | ||
351 | acx->len = len - sizeof(*acx); | ||
352 | |||
353 | ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len); | ||
354 | if (ret < 0) { | ||
355 | wl1271_warning("CONFIGURE command NOK"); | ||
356 | return ret; | ||
357 | } | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) | ||
363 | { | ||
364 | struct cmd_enabledisable_path *cmd; | ||
365 | int ret; | ||
366 | u16 cmd_rx, cmd_tx; | ||
367 | |||
368 | wl1271_debug(DEBUG_CMD, "cmd data path"); | ||
369 | |||
370 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
371 | if (!cmd) { | ||
372 | ret = -ENOMEM; | ||
373 | goto out; | ||
374 | } | ||
375 | |||
376 | cmd->channel = channel; | ||
377 | |||
378 | if (enable) { | ||
379 | cmd_rx = CMD_ENABLE_RX; | ||
380 | cmd_tx = CMD_ENABLE_TX; | ||
381 | } else { | ||
382 | cmd_rx = CMD_DISABLE_RX; | ||
383 | cmd_tx = CMD_DISABLE_TX; | ||
384 | } | ||
385 | |||
386 | ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); | ||
387 | if (ret < 0) { | ||
388 | wl1271_error("rx %s cmd for channel %d failed", | ||
389 | enable ? "start" : "stop", channel); | ||
390 | goto out; | ||
391 | } | ||
392 | |||
393 | wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", | ||
394 | enable ? "start" : "stop", channel); | ||
395 | |||
396 | ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); | ||
397 | if (ret < 0) { | ||
398 | wl1271_error("tx %s cmd for channel %d failed", | ||
399 | enable ? "start" : "stop", channel); | ||
400 | return ret; | ||
401 | } | ||
402 | |||
403 | wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", | ||
404 | enable ? "start" : "stop", channel); | ||
405 | |||
406 | out: | ||
407 | kfree(cmd); | ||
408 | return ret; | ||
409 | } | ||
410 | |||
411 | int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) | ||
412 | { | ||
413 | struct wl1271_cmd_ps_params *ps_params = NULL; | ||
414 | int ret = 0; | ||
415 | |||
416 | /* FIXME: this should be in ps.c */ | ||
417 | ret = wl1271_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, | ||
418 | wl->listen_int); | ||
419 | if (ret < 0) { | ||
420 | wl1271_error("couldn't set wake up conditions"); | ||
421 | goto out; | ||
422 | } | ||
423 | |||
424 | wl1271_debug(DEBUG_CMD, "cmd set ps mode"); | ||
425 | |||
426 | ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); | ||
427 | if (!ps_params) { | ||
428 | ret = -ENOMEM; | ||
429 | goto out; | ||
430 | } | ||
431 | |||
432 | ps_params->ps_mode = ps_mode; | ||
433 | ps_params->send_null_data = 1; | ||
434 | ps_params->retries = 5; | ||
435 | ps_params->hang_over_period = 128; | ||
436 | ps_params->null_data_rate = 1; /* 1 Mbps */ | ||
437 | |||
438 | ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, | ||
439 | sizeof(*ps_params)); | ||
440 | if (ret < 0) { | ||
441 | wl1271_error("cmd set_ps_mode failed"); | ||
442 | goto out; | ||
443 | } | ||
444 | |||
445 | out: | ||
446 | kfree(ps_params); | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, | ||
451 | size_t len) | ||
452 | { | ||
453 | struct cmd_read_write_memory *cmd; | ||
454 | int ret = 0; | ||
455 | |||
456 | wl1271_debug(DEBUG_CMD, "cmd read memory"); | ||
457 | |||
458 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
459 | if (!cmd) { | ||
460 | ret = -ENOMEM; | ||
461 | goto out; | ||
462 | } | ||
463 | |||
464 | WARN_ON(len > MAX_READ_SIZE); | ||
465 | len = min_t(size_t, len, MAX_READ_SIZE); | ||
466 | |||
467 | cmd->addr = addr; | ||
468 | cmd->size = len; | ||
469 | |||
470 | ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); | ||
471 | if (ret < 0) { | ||
472 | wl1271_error("read memory command failed: %d", ret); | ||
473 | goto out; | ||
474 | } | ||
475 | |||
476 | /* the read command got in, we can now read the answer */ | ||
477 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); | ||
478 | |||
479 | if (cmd->header.status != CMD_STATUS_SUCCESS) | ||
480 | wl1271_error("error in read command result: %d", | ||
481 | cmd->header.status); | ||
482 | |||
483 | memcpy(answer, cmd->value, len); | ||
484 | |||
485 | out: | ||
486 | kfree(cmd); | ||
487 | return ret; | ||
488 | } | ||
489 | |||
490 | int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | ||
491 | u8 active_scan, u8 high_prio, u8 num_channels, | ||
492 | u8 probe_requests) | ||
493 | { | ||
494 | |||
495 | struct wl1271_cmd_trigger_scan_to *trigger = NULL; | ||
496 | struct wl1271_cmd_scan *params = NULL; | ||
497 | int i, ret; | ||
498 | u16 scan_options = 0; | ||
499 | |||
500 | if (wl->scanning) | ||
501 | return -EINVAL; | ||
502 | |||
503 | params = kzalloc(sizeof(*params), GFP_KERNEL); | ||
504 | if (!params) | ||
505 | return -ENOMEM; | ||
506 | |||
507 | params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); | ||
508 | params->params.rx_filter_options = | ||
509 | cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); | ||
510 | |||
511 | if (!active_scan) | ||
512 | scan_options |= WL1271_SCAN_OPT_PASSIVE; | ||
513 | if (high_prio) | ||
514 | scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH; | ||
515 | params->params.scan_options = scan_options; | ||
516 | |||
517 | params->params.num_channels = num_channels; | ||
518 | params->params.num_probe_requests = probe_requests; | ||
519 | params->params.tx_rate = cpu_to_le32(RATE_MASK_2MBPS); | ||
520 | params->params.tid_trigger = 0; | ||
521 | params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; | ||
522 | |||
523 | for (i = 0; i < num_channels; i++) { | ||
524 | params->channels[i].min_duration = | ||
525 | cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); | ||
526 | params->channels[i].max_duration = | ||
527 | cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); | ||
528 | memset(¶ms->channels[i].bssid_lsb, 0xff, 4); | ||
529 | memset(¶ms->channels[i].bssid_msb, 0xff, 2); | ||
530 | params->channels[i].early_termination = 0; | ||
531 | params->channels[i].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR; | ||
532 | params->channels[i].channel = i + 1; | ||
533 | } | ||
534 | |||
535 | if (len && ssid) { | ||
536 | params->params.ssid_len = len; | ||
537 | memcpy(params->params.ssid, ssid, len); | ||
538 | } | ||
539 | |||
540 | ret = wl1271_cmd_build_probe_req(wl, ssid, len); | ||
541 | if (ret < 0) { | ||
542 | wl1271_error("PROBE request template failed"); | ||
543 | goto out; | ||
544 | } | ||
545 | |||
546 | trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); | ||
547 | if (!trigger) { | ||
548 | ret = -ENOMEM; | ||
549 | goto out; | ||
550 | } | ||
551 | |||
552 | /* disable the timeout */ | ||
553 | trigger->timeout = 0; | ||
554 | |||
555 | ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, | ||
556 | sizeof(*trigger)); | ||
557 | if (ret < 0) { | ||
558 | wl1271_error("trigger scan to failed for hw scan"); | ||
559 | goto out; | ||
560 | } | ||
561 | |||
562 | wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); | ||
563 | |||
564 | wl->scanning = true; | ||
565 | |||
566 | ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); | ||
567 | if (ret < 0) { | ||
568 | wl1271_error("SCAN failed"); | ||
569 | goto out; | ||
570 | } | ||
571 | |||
572 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); | ||
573 | |||
574 | if (params->header.status != CMD_STATUS_SUCCESS) { | ||
575 | wl1271_error("Scan command error: %d", | ||
576 | params->header.status); | ||
577 | wl->scanning = false; | ||
578 | ret = -EIO; | ||
579 | goto out; | ||
580 | } | ||
581 | |||
582 | out: | ||
583 | kfree(params); | ||
584 | return ret; | ||
585 | } | ||
586 | |||
587 | int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, | ||
588 | void *buf, size_t buf_len) | ||
589 | { | ||
590 | struct wl1271_cmd_template_set *cmd; | ||
591 | int ret = 0; | ||
592 | |||
593 | wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id); | ||
594 | |||
595 | WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); | ||
596 | buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); | ||
597 | |||
598 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
599 | if (!cmd) { | ||
600 | ret = -ENOMEM; | ||
601 | goto out; | ||
602 | } | ||
603 | |||
604 | cmd->len = cpu_to_le16(buf_len); | ||
605 | cmd->template_type = template_id; | ||
606 | cmd->enabled_rates = ACX_RATE_MASK_UNSPECIFIED; | ||
607 | cmd->short_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
608 | cmd->long_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
609 | |||
610 | if (buf) | ||
611 | memcpy(cmd->template_data, buf, buf_len); | ||
612 | |||
613 | ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd)); | ||
614 | if (ret < 0) { | ||
615 | wl1271_warning("cmd set_template failed: %d", ret); | ||
616 | goto out_free; | ||
617 | } | ||
618 | |||
619 | out_free: | ||
620 | kfree(cmd); | ||
621 | |||
622 | out: | ||
623 | return ret; | ||
624 | } | ||
625 | |||
626 | static int wl1271_build_basic_rates(char *rates) | ||
627 | { | ||
628 | u8 index = 0; | ||
629 | |||
630 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; | ||
631 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; | ||
632 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; | ||
633 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; | ||
634 | |||
635 | return index; | ||
636 | } | ||
637 | |||
638 | static int wl1271_build_extended_rates(char *rates) | ||
639 | { | ||
640 | u8 index = 0; | ||
641 | |||
642 | rates[index++] = IEEE80211_OFDM_RATE_6MB; | ||
643 | rates[index++] = IEEE80211_OFDM_RATE_9MB; | ||
644 | rates[index++] = IEEE80211_OFDM_RATE_12MB; | ||
645 | rates[index++] = IEEE80211_OFDM_RATE_18MB; | ||
646 | rates[index++] = IEEE80211_OFDM_RATE_24MB; | ||
647 | rates[index++] = IEEE80211_OFDM_RATE_36MB; | ||
648 | rates[index++] = IEEE80211_OFDM_RATE_48MB; | ||
649 | rates[index++] = IEEE80211_OFDM_RATE_54MB; | ||
650 | |||
651 | return index; | ||
652 | } | ||
653 | |||
654 | int wl1271_cmd_build_null_data(struct wl1271 *wl) | ||
655 | { | ||
656 | struct wl12xx_null_data_template template; | ||
657 | |||
658 | if (!is_zero_ether_addr(wl->bssid)) { | ||
659 | memcpy(template.header.da, wl->bssid, ETH_ALEN); | ||
660 | memcpy(template.header.bssid, wl->bssid, ETH_ALEN); | ||
661 | } else { | ||
662 | memset(template.header.da, 0xff, ETH_ALEN); | ||
663 | memset(template.header.bssid, 0xff, ETH_ALEN); | ||
664 | } | ||
665 | |||
666 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | ||
667 | template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
668 | IEEE80211_STYPE_NULLFUNC); | ||
669 | |||
670 | return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template, | ||
671 | sizeof(template)); | ||
672 | |||
673 | } | ||
674 | |||
675 | int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) | ||
676 | { | ||
677 | struct wl12xx_ps_poll_template template; | ||
678 | |||
679 | memcpy(template.bssid, wl->bssid, ETH_ALEN); | ||
680 | memcpy(template.ta, wl->mac_addr, ETH_ALEN); | ||
681 | template.aid = aid; | ||
682 | template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); | ||
683 | |||
684 | return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template, | ||
685 | sizeof(template)); | ||
686 | |||
687 | } | ||
688 | |||
689 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len) | ||
690 | { | ||
691 | struct wl12xx_probe_req_template template; | ||
692 | struct wl12xx_ie_rates *rates; | ||
693 | char *ptr; | ||
694 | u16 size; | ||
695 | |||
696 | ptr = (char *)&template; | ||
697 | size = sizeof(struct ieee80211_header); | ||
698 | |||
699 | memset(template.header.da, 0xff, ETH_ALEN); | ||
700 | memset(template.header.bssid, 0xff, ETH_ALEN); | ||
701 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | ||
702 | template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | ||
703 | |||
704 | /* IEs */ | ||
705 | /* SSID */ | ||
706 | template.ssid.header.id = WLAN_EID_SSID; | ||
707 | template.ssid.header.len = ssid_len; | ||
708 | if (ssid_len && ssid) | ||
709 | memcpy(template.ssid.ssid, ssid, ssid_len); | ||
710 | size += sizeof(struct wl12xx_ie_header) + ssid_len; | ||
711 | ptr += size; | ||
712 | |||
713 | /* Basic Rates */ | ||
714 | rates = (struct wl12xx_ie_rates *)ptr; | ||
715 | rates->header.id = WLAN_EID_SUPP_RATES; | ||
716 | rates->header.len = wl1271_build_basic_rates(rates->rates); | ||
717 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
718 | ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
719 | |||
720 | /* Extended rates */ | ||
721 | rates = (struct wl12xx_ie_rates *)ptr; | ||
722 | rates->header.id = WLAN_EID_EXT_SUPP_RATES; | ||
723 | rates->header.len = wl1271_build_extended_rates(rates->rates); | ||
724 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
725 | |||
726 | wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); | ||
727 | |||
728 | return wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, | ||
729 | &template, size); | ||
730 | } | ||
731 | |||
732 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) | ||
733 | { | ||
734 | struct wl1271_cmd_set_keys *cmd; | ||
735 | int ret = 0; | ||
736 | |||
737 | wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); | ||
738 | |||
739 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
740 | if (!cmd) { | ||
741 | ret = -ENOMEM; | ||
742 | goto out; | ||
743 | } | ||
744 | |||
745 | cmd->id = id; | ||
746 | cmd->key_action = KEY_SET_ID; | ||
747 | cmd->key_type = KEY_WEP; | ||
748 | |||
749 | ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); | ||
750 | if (ret < 0) { | ||
751 | wl1271_warning("cmd set_default_wep_key failed: %d", ret); | ||
752 | goto out; | ||
753 | } | ||
754 | |||
755 | out: | ||
756 | kfree(cmd); | ||
757 | |||
758 | return ret; | ||
759 | } | ||
760 | |||
761 | int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | ||
762 | u8 key_size, const u8 *key, const u8 *addr) | ||
763 | { | ||
764 | struct wl1271_cmd_set_keys *cmd; | ||
765 | int ret = 0; | ||
766 | |||
767 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
768 | if (!cmd) { | ||
769 | ret = -ENOMEM; | ||
770 | goto out; | ||
771 | } | ||
772 | |||
773 | if (key_type != KEY_WEP) | ||
774 | memcpy(cmd->addr, addr, ETH_ALEN); | ||
775 | |||
776 | cmd->key_action = action; | ||
777 | cmd->key_size = key_size; | ||
778 | cmd->key_type = key_type; | ||
779 | |||
780 | /* we have only one SSID profile */ | ||
781 | cmd->ssid_profile = 0; | ||
782 | |||
783 | cmd->id = id; | ||
784 | |||
785 | /* FIXME: this is from wl1251, needs to be checked */ | ||
786 | if (key_type == KEY_TKIP) { | ||
787 | /* | ||
788 | * We get the key in the following form: | ||
789 | * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) | ||
790 | * but the target is expecting: | ||
791 | * TKIP - RX MIC - TX MIC | ||
792 | */ | ||
793 | memcpy(cmd->key, key, 16); | ||
794 | memcpy(cmd->key + 16, key + 24, 8); | ||
795 | memcpy(cmd->key + 24, key + 16, 8); | ||
796 | |||
797 | } else { | ||
798 | memcpy(cmd->key, key, key_size); | ||
799 | } | ||
800 | |||
801 | wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); | ||
802 | |||
803 | ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); | ||
804 | if (ret < 0) { | ||
805 | wl1271_warning("could not set keys"); | ||
806 | goto out; | ||
807 | } | ||
808 | |||
809 | out: | ||
810 | kfree(cmd); | ||
811 | |||
812 | return ret; | ||
813 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h new file mode 100644 index 000000000000..951a8447a516 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h | |||
@@ -0,0 +1,464 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_CMD_H__ | ||
26 | #define __WL1271_CMD_H__ | ||
27 | |||
28 | #include "wl1271.h" | ||
29 | |||
30 | struct acx_header; | ||
31 | |||
32 | int wl1271_cmd_send(struct wl1271 *wl, u16 type, void *buf, size_t buf_len); | ||
33 | int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, | ||
34 | u16 beacon_interval, u8 wait); | ||
35 | int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); | ||
36 | int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); | ||
37 | int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); | ||
38 | int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable); | ||
39 | int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode); | ||
40 | int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, | ||
41 | size_t len); | ||
42 | int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | ||
43 | u8 active_scan, u8 high_prio, u8 num_channels, | ||
44 | u8 probe_requests); | ||
45 | int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, | ||
46 | void *buf, size_t buf_len); | ||
47 | int wl1271_cmd_build_null_data(struct wl1271 *wl); | ||
48 | int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); | ||
49 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len); | ||
50 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); | ||
51 | int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | ||
52 | u8 key_size, const u8 *key, const u8 *addr); | ||
53 | |||
54 | enum wl1271_commands { | ||
55 | CMD_INTERROGATE = 1, /*use this to read information elements*/ | ||
56 | CMD_CONFIGURE = 2, /*use this to write information elements*/ | ||
57 | CMD_ENABLE_RX = 3, | ||
58 | CMD_ENABLE_TX = 4, | ||
59 | CMD_DISABLE_RX = 5, | ||
60 | CMD_DISABLE_TX = 6, | ||
61 | CMD_SCAN = 8, | ||
62 | CMD_STOP_SCAN = 9, | ||
63 | CMD_START_JOIN = 11, | ||
64 | CMD_SET_KEYS = 12, | ||
65 | CMD_READ_MEMORY = 13, | ||
66 | CMD_WRITE_MEMORY = 14, | ||
67 | CMD_SET_TEMPLATE = 19, | ||
68 | CMD_TEST = 23, | ||
69 | CMD_NOISE_HIST = 28, | ||
70 | CMD_LNA_CONTROL = 32, | ||
71 | CMD_SET_BCN_MODE = 33, | ||
72 | CMD_MEASUREMENT = 34, | ||
73 | CMD_STOP_MEASUREMENT = 35, | ||
74 | CMD_DISCONNECT = 36, | ||
75 | CMD_SET_PS_MODE = 37, | ||
76 | CMD_CHANNEL_SWITCH = 38, | ||
77 | CMD_STOP_CHANNEL_SWICTH = 39, | ||
78 | CMD_AP_DISCOVERY = 40, | ||
79 | CMD_STOP_AP_DISCOVERY = 41, | ||
80 | CMD_SPS_SCAN = 42, | ||
81 | CMD_STOP_SPS_SCAN = 43, | ||
82 | CMD_HEALTH_CHECK = 45, | ||
83 | CMD_DEBUG = 46, | ||
84 | CMD_TRIGGER_SCAN_TO = 47, | ||
85 | CMD_CONNECTION_SCAN_CFG = 48, | ||
86 | CMD_CONNECTION_SCAN_SSID_CFG = 49, | ||
87 | CMD_START_PERIODIC_SCAN = 50, | ||
88 | CMD_STOP_PERIODIC_SCAN = 51, | ||
89 | CMD_SET_STA_STATE = 52, | ||
90 | |||
91 | NUM_COMMANDS, | ||
92 | MAX_COMMAND_ID = 0xFFFF, | ||
93 | }; | ||
94 | |||
95 | #define MAX_CMD_PARAMS 572 | ||
96 | |||
97 | enum cmd_templ { | ||
98 | CMD_TEMPL_NULL_DATA = 0, | ||
99 | CMD_TEMPL_BEACON, | ||
100 | CMD_TEMPL_CFG_PROBE_REQ_2_4, | ||
101 | CMD_TEMPL_CFG_PROBE_REQ_5, | ||
102 | CMD_TEMPL_PROBE_RESPONSE, | ||
103 | CMD_TEMPL_QOS_NULL_DATA, | ||
104 | CMD_TEMPL_PS_POLL, | ||
105 | CMD_TEMPL_KLV, | ||
106 | CMD_TEMPL_DISCONNECT, | ||
107 | CMD_TEMPL_PROBE_REQ_2_4, /* for firmware internal use only */ | ||
108 | CMD_TEMPL_PROBE_REQ_5, /* for firmware internal use only */ | ||
109 | CMD_TEMPL_BAR, /* for firmware internal use only */ | ||
110 | CMD_TEMPL_CTS, /* | ||
111 | * For CTS-to-self (FastCTS) mechanism | ||
112 | * for BT/WLAN coexistence (SoftGemini). */ | ||
113 | CMD_TEMPL_MAX = 0xff | ||
114 | }; | ||
115 | |||
116 | /* unit ms */ | ||
117 | #define WL1271_COMMAND_TIMEOUT 2000 | ||
118 | #define WL1271_CMD_TEMPL_MAX_SIZE 252 | ||
119 | |||
120 | struct wl1271_cmd_header { | ||
121 | u16 id; | ||
122 | u16 status; | ||
123 | /* payload */ | ||
124 | u8 data[0]; | ||
125 | } __attribute__ ((packed)); | ||
126 | |||
127 | #define WL1271_CMD_MAX_PARAMS 572 | ||
128 | |||
129 | struct wl1271_command { | ||
130 | struct wl1271_cmd_header header; | ||
131 | u8 parameters[WL1271_CMD_MAX_PARAMS]; | ||
132 | } __attribute__ ((packed)); | ||
133 | |||
134 | enum { | ||
135 | CMD_MAILBOX_IDLE = 0, | ||
136 | CMD_STATUS_SUCCESS = 1, | ||
137 | CMD_STATUS_UNKNOWN_CMD = 2, | ||
138 | CMD_STATUS_UNKNOWN_IE = 3, | ||
139 | CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, | ||
140 | CMD_STATUS_RX_BUSY = 13, | ||
141 | CMD_STATUS_INVALID_PARAM = 14, | ||
142 | CMD_STATUS_TEMPLATE_TOO_LARGE = 15, | ||
143 | CMD_STATUS_OUT_OF_MEMORY = 16, | ||
144 | CMD_STATUS_STA_TABLE_FULL = 17, | ||
145 | CMD_STATUS_RADIO_ERROR = 18, | ||
146 | CMD_STATUS_WRONG_NESTING = 19, | ||
147 | CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ | ||
148 | CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ | ||
149 | MAX_COMMAND_STATUS = 0xff | ||
150 | }; | ||
151 | |||
152 | |||
153 | /* | ||
154 | * CMD_READ_MEMORY | ||
155 | * | ||
156 | * The host issues this command to read the WiLink device memory/registers. | ||
157 | * | ||
158 | * Note: The Base Band address has special handling (16 bits registers and | ||
159 | * addresses). For more information, see the hardware specification. | ||
160 | */ | ||
161 | /* | ||
162 | * CMD_WRITE_MEMORY | ||
163 | * | ||
164 | * The host issues this command to write the WiLink device memory/registers. | ||
165 | * | ||
166 | * The Base Band address has special handling (16 bits registers and | ||
167 | * addresses). For more information, see the hardware specification. | ||
168 | */ | ||
169 | #define MAX_READ_SIZE 256 | ||
170 | |||
171 | struct cmd_read_write_memory { | ||
172 | struct wl1271_cmd_header header; | ||
173 | |||
174 | /* The address of the memory to read from or write to.*/ | ||
175 | u32 addr; | ||
176 | |||
177 | /* The amount of data in bytes to read from or write to the WiLink | ||
178 | * device.*/ | ||
179 | u32 size; | ||
180 | |||
181 | /* The actual value read from or written to the Wilink. The source | ||
182 | of this field is the Host in WRITE command or the Wilink in READ | ||
183 | command. */ | ||
184 | u8 value[MAX_READ_SIZE]; | ||
185 | }; | ||
186 | |||
187 | #define CMDMBOX_HEADER_LEN 4 | ||
188 | #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 | ||
189 | |||
190 | enum { | ||
191 | BSS_TYPE_IBSS = 0, | ||
192 | BSS_TYPE_STA_BSS = 2, | ||
193 | BSS_TYPE_AP_BSS = 3, | ||
194 | MAX_BSS_TYPE = 0xFF | ||
195 | }; | ||
196 | |||
197 | #define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ | ||
198 | #define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1 | ||
199 | |||
200 | struct wl1271_cmd_join { | ||
201 | struct wl1271_cmd_header header; | ||
202 | |||
203 | u32 bssid_lsb; | ||
204 | u16 bssid_msb; | ||
205 | u16 beacon_interval; /* in TBTTs */ | ||
206 | u32 rx_config_options; | ||
207 | u32 rx_filter_options; | ||
208 | |||
209 | /* | ||
210 | * The target uses this field to determine the rate at | ||
211 | * which to transmit control frame responses (such as | ||
212 | * ACK or CTS frames). | ||
213 | */ | ||
214 | u32 basic_rate_set; | ||
215 | u8 dtim_interval; | ||
216 | /* | ||
217 | * bits 0-2: This bitwise field specifies the type | ||
218 | * of BSS to start or join (BSS_TYPE_*). | ||
219 | * bit 4: Band - The radio band in which to join | ||
220 | * or start. | ||
221 | * 0 - 2.4GHz band | ||
222 | * 1 - 5GHz band | ||
223 | * bits 3, 5-7: Reserved | ||
224 | */ | ||
225 | u8 bss_type; | ||
226 | u8 channel; | ||
227 | u8 ssid_len; | ||
228 | u8 ssid[IW_ESSID_MAX_SIZE]; | ||
229 | u8 ctrl; /* JOIN_CMD_CTRL_* */ | ||
230 | u8 reserved[3]; | ||
231 | } __attribute__ ((packed)); | ||
232 | |||
233 | struct cmd_enabledisable_path { | ||
234 | struct wl1271_cmd_header header; | ||
235 | |||
236 | u8 channel; | ||
237 | u8 padding[3]; | ||
238 | } __attribute__ ((packed)); | ||
239 | |||
240 | struct wl1271_cmd_template_set { | ||
241 | struct wl1271_cmd_header header; | ||
242 | |||
243 | u16 len; | ||
244 | u8 template_type; | ||
245 | u8 index; /* relevant only for KLV_TEMPLATE type */ | ||
246 | u32 enabled_rates; | ||
247 | u8 short_retry_limit; | ||
248 | u8 long_retry_limit; | ||
249 | u8 aflags; | ||
250 | u8 reserved; | ||
251 | u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE]; | ||
252 | } __attribute__ ((packed)); | ||
253 | |||
254 | #define TIM_ELE_ID 5 | ||
255 | #define PARTIAL_VBM_MAX 251 | ||
256 | |||
257 | struct wl1271_tim { | ||
258 | u8 identity; | ||
259 | u8 length; | ||
260 | u8 dtim_count; | ||
261 | u8 dtim_period; | ||
262 | u8 bitmap_ctrl; | ||
263 | u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ | ||
264 | } __attribute__ ((packed)); | ||
265 | |||
266 | enum wl1271_cmd_ps_mode { | ||
267 | STATION_ACTIVE_MODE, | ||
268 | STATION_POWER_SAVE_MODE | ||
269 | }; | ||
270 | |||
271 | struct wl1271_cmd_ps_params { | ||
272 | struct wl1271_cmd_header header; | ||
273 | |||
274 | u8 ps_mode; /* STATION_* */ | ||
275 | u8 send_null_data; /* Do we have to send NULL data packet ? */ | ||
276 | u8 retries; /* Number of retires for the initial NULL data packet */ | ||
277 | |||
278 | /* | ||
279 | * TUs during which the target stays awake after switching | ||
280 | * to power save mode. | ||
281 | */ | ||
282 | u8 hang_over_period; | ||
283 | u32 null_data_rate; | ||
284 | } __attribute__ ((packed)); | ||
285 | |||
286 | /* HW encryption keys */ | ||
287 | #define NUM_ACCESS_CATEGORIES_COPY 4 | ||
288 | #define MAX_KEY_SIZE 32 | ||
289 | |||
290 | /* When set, disable HW encryption */ | ||
291 | #define DF_ENCRYPTION_DISABLE 0x01 | ||
292 | /* When set, disable HW decryption */ | ||
293 | #define DF_SNIFF_MODE_ENABLE 0x80 | ||
294 | |||
295 | enum wl1271_cmd_key_action { | ||
296 | KEY_ADD_OR_REPLACE = 1, | ||
297 | KEY_REMOVE = 2, | ||
298 | KEY_SET_ID = 3, | ||
299 | MAX_KEY_ACTION = 0xffff, | ||
300 | }; | ||
301 | |||
302 | enum wl1271_cmd_key_type { | ||
303 | KEY_NONE = 0, | ||
304 | KEY_WEP = 1, | ||
305 | KEY_TKIP = 2, | ||
306 | KEY_AES = 3, | ||
307 | KEY_GEM = 4 | ||
308 | }; | ||
309 | |||
310 | /* FIXME: Add description for key-types */ | ||
311 | |||
312 | struct wl1271_cmd_set_keys { | ||
313 | struct wl1271_cmd_header header; | ||
314 | |||
315 | /* Ignored for default WEP key */ | ||
316 | u8 addr[ETH_ALEN]; | ||
317 | |||
318 | /* key_action_e */ | ||
319 | u16 key_action; | ||
320 | |||
321 | u16 reserved_1; | ||
322 | |||
323 | /* key size in bytes */ | ||
324 | u8 key_size; | ||
325 | |||
326 | /* key_type_e */ | ||
327 | u8 key_type; | ||
328 | u8 ssid_profile; | ||
329 | |||
330 | /* | ||
331 | * TKIP, AES: frame's key id field. | ||
332 | * For WEP default key: key id; | ||
333 | */ | ||
334 | u8 id; | ||
335 | u8 reserved_2[6]; | ||
336 | u8 key[MAX_KEY_SIZE]; | ||
337 | u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; | ||
338 | u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; | ||
339 | } __attribute__ ((packed)); | ||
340 | |||
341 | |||
342 | #define WL1271_SCAN_MAX_CHANNELS 24 | ||
343 | #define WL1271_SCAN_DEFAULT_TAG 1 | ||
344 | #define WL1271_SCAN_CURRENT_TX_PWR 0 | ||
345 | #define WL1271_SCAN_OPT_ACTIVE 0 | ||
346 | #define WL1271_SCAN_OPT_PASSIVE 1 | ||
347 | #define WL1271_SCAN_OPT_PRIORITY_HIGH 4 | ||
348 | #define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */ | ||
349 | #define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */ | ||
350 | |||
351 | struct basic_scan_params { | ||
352 | u32 rx_config_options; | ||
353 | u32 rx_filter_options; | ||
354 | /* Scan option flags (WL1271_SCAN_OPT_*) */ | ||
355 | u16 scan_options; | ||
356 | /* Number of scan channels in the list (maximum 30) */ | ||
357 | u8 num_channels; | ||
358 | /* This field indicates the number of probe requests to send | ||
359 | per channel for an active scan */ | ||
360 | u8 num_probe_requests; | ||
361 | /* Rate bit field for sending the probes */ | ||
362 | u32 tx_rate; | ||
363 | u8 tid_trigger; | ||
364 | u8 ssid_len; | ||
365 | /* in order to align */ | ||
366 | u8 padding1[2]; | ||
367 | u8 ssid[IW_ESSID_MAX_SIZE]; | ||
368 | /* Band to scan */ | ||
369 | u8 band; | ||
370 | u8 use_ssid_list; | ||
371 | u8 scan_tag; | ||
372 | u8 padding2; | ||
373 | } __attribute__ ((packed)); | ||
374 | |||
375 | struct basic_scan_channel_params { | ||
376 | /* Duration in TU to wait for frames on a channel for active scan */ | ||
377 | u32 min_duration; | ||
378 | u32 max_duration; | ||
379 | u32 bssid_lsb; | ||
380 | u16 bssid_msb; | ||
381 | u8 early_termination; | ||
382 | u8 tx_power_att; | ||
383 | u8 channel; | ||
384 | /* FW internal use only! */ | ||
385 | u8 dfs_candidate; | ||
386 | u8 activity_detected; | ||
387 | u8 pad; | ||
388 | } __attribute__ ((packed)); | ||
389 | |||
390 | struct wl1271_cmd_scan { | ||
391 | struct wl1271_cmd_header header; | ||
392 | |||
393 | struct basic_scan_params params; | ||
394 | struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; | ||
395 | } __attribute__ ((packed)); | ||
396 | |||
397 | struct wl1271_cmd_trigger_scan_to { | ||
398 | struct wl1271_cmd_header header; | ||
399 | |||
400 | u32 timeout; | ||
401 | }; | ||
402 | |||
403 | struct wl1271_cmd_test_header { | ||
404 | u8 id; | ||
405 | u8 padding[3]; | ||
406 | }; | ||
407 | |||
408 | enum wl1271_channel_tune_bands { | ||
409 | WL1271_CHANNEL_TUNE_BAND_2_4, | ||
410 | WL1271_CHANNEL_TUNE_BAND_5, | ||
411 | WL1271_CHANNEL_TUNE_BAND_4_9 | ||
412 | }; | ||
413 | |||
414 | #define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 | ||
415 | |||
416 | #define TEST_CMD_P2G_CAL 0x02 | ||
417 | #define TEST_CMD_CHANNEL_TUNE 0x0d | ||
418 | #define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d | ||
419 | |||
420 | struct wl1271_cmd_cal_channel_tune { | ||
421 | struct wl1271_cmd_header header; | ||
422 | |||
423 | struct wl1271_cmd_test_header test; | ||
424 | |||
425 | u8 band; | ||
426 | u8 channel; | ||
427 | |||
428 | u16 radio_status; | ||
429 | } __attribute__ ((packed)); | ||
430 | |||
431 | struct wl1271_cmd_cal_update_ref_point { | ||
432 | struct wl1271_cmd_header header; | ||
433 | |||
434 | struct wl1271_cmd_test_header test; | ||
435 | |||
436 | s32 ref_power; | ||
437 | s32 ref_detector; | ||
438 | u8 sub_band; | ||
439 | u8 padding[3]; | ||
440 | } __attribute__ ((packed)); | ||
441 | |||
442 | #define MAX_TLV_LENGTH 400 | ||
443 | #define MAX_NVS_VERSION_LENGTH 12 | ||
444 | |||
445 | #define WL1271_CAL_P2G_BAND_B_G BIT(0) | ||
446 | |||
447 | struct wl1271_cmd_cal_p2g { | ||
448 | struct wl1271_cmd_header header; | ||
449 | |||
450 | struct wl1271_cmd_test_header test; | ||
451 | |||
452 | u16 len; | ||
453 | u8 buf[MAX_TLV_LENGTH]; | ||
454 | u8 type; | ||
455 | u8 padding; | ||
456 | |||
457 | s16 radio_status; | ||
458 | u8 nvs_version[MAX_NVS_VERSION_LENGTH]; | ||
459 | |||
460 | u8 sub_band_mask; | ||
461 | u8 padding2; | ||
462 | } __attribute__ ((packed)); | ||
463 | |||
464 | #endif /* __WL1271_CMD_H__ */ | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c new file mode 100644 index 000000000000..c1805e5f8964 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.c | |||
@@ -0,0 +1,518 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "wl1271_debugfs.h" | ||
25 | |||
26 | #include <linux/skbuff.h> | ||
27 | |||
28 | #include "wl1271.h" | ||
29 | #include "wl1271_acx.h" | ||
30 | #include "wl1271_ps.h" | ||
31 | |||
32 | /* ms */ | ||
33 | #define WL1271_DEBUGFS_STATS_LIFETIME 1000 | ||
34 | |||
35 | /* debugfs macros idea from mac80211 */ | ||
36 | |||
37 | #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ | ||
38 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ | ||
39 | size_t count, loff_t *ppos) \ | ||
40 | { \ | ||
41 | struct wl1271 *wl = file->private_data; \ | ||
42 | char buf[buflen]; \ | ||
43 | int res; \ | ||
44 | \ | ||
45 | res = scnprintf(buf, buflen, fmt "\n", ##value); \ | ||
46 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
47 | } \ | ||
48 | \ | ||
49 | static const struct file_operations name## _ops = { \ | ||
50 | .read = name## _read, \ | ||
51 | .open = wl1271_open_file_generic, \ | ||
52 | }; | ||
53 | |||
54 | #define DEBUGFS_ADD(name, parent) \ | ||
55 | wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ | ||
56 | wl, &name## _ops); \ | ||
57 | if (IS_ERR(wl->debugfs.name)) { \ | ||
58 | ret = PTR_ERR(wl->debugfs.name); \ | ||
59 | wl->debugfs.name = NULL; \ | ||
60 | goto out; \ | ||
61 | } | ||
62 | |||
63 | #define DEBUGFS_DEL(name) \ | ||
64 | do { \ | ||
65 | debugfs_remove(wl->debugfs.name); \ | ||
66 | wl->debugfs.name = NULL; \ | ||
67 | } while (0) | ||
68 | |||
69 | #define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ | ||
70 | static ssize_t sub## _ ##name## _read(struct file *file, \ | ||
71 | char __user *userbuf, \ | ||
72 | size_t count, loff_t *ppos) \ | ||
73 | { \ | ||
74 | struct wl1271 *wl = file->private_data; \ | ||
75 | char buf[buflen]; \ | ||
76 | int res; \ | ||
77 | \ | ||
78 | wl1271_debugfs_update_stats(wl); \ | ||
79 | \ | ||
80 | res = scnprintf(buf, buflen, fmt "\n", \ | ||
81 | wl->stats.fw_stats->sub.name); \ | ||
82 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
83 | } \ | ||
84 | \ | ||
85 | static const struct file_operations sub## _ ##name## _ops = { \ | ||
86 | .read = sub## _ ##name## _read, \ | ||
87 | .open = wl1271_open_file_generic, \ | ||
88 | }; | ||
89 | |||
90 | #define DEBUGFS_FWSTATS_ADD(sub, name) \ | ||
91 | DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) | ||
92 | |||
93 | #define DEBUGFS_FWSTATS_DEL(sub, name) \ | ||
94 | DEBUGFS_DEL(sub## _ ##name) | ||
95 | |||
96 | static void wl1271_debugfs_update_stats(struct wl1271 *wl) | ||
97 | { | ||
98 | int ret; | ||
99 | |||
100 | mutex_lock(&wl->mutex); | ||
101 | |||
102 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
103 | if (ret < 0) | ||
104 | goto out; | ||
105 | |||
106 | if (wl->state == WL1271_STATE_ON && | ||
107 | time_after(jiffies, wl->stats.fw_stats_update + | ||
108 | msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) { | ||
109 | wl1271_acx_statistics(wl, wl->stats.fw_stats); | ||
110 | wl->stats.fw_stats_update = jiffies; | ||
111 | } | ||
112 | |||
113 | wl1271_ps_elp_sleep(wl); | ||
114 | |||
115 | out: | ||
116 | mutex_unlock(&wl->mutex); | ||
117 | } | ||
118 | |||
119 | static int wl1271_open_file_generic(struct inode *inode, struct file *file) | ||
120 | { | ||
121 | file->private_data = inode->i_private; | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); | ||
126 | |||
127 | DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); | ||
128 | DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); | ||
129 | DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); | ||
130 | DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); | ||
131 | DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); | ||
132 | DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); | ||
133 | DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); | ||
134 | DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); | ||
135 | |||
136 | DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); | ||
137 | DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); | ||
138 | DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); | ||
139 | DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); | ||
140 | |||
141 | DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); | ||
142 | DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); | ||
143 | DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); | ||
144 | DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); | ||
145 | DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); | ||
146 | DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); | ||
147 | DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); | ||
148 | DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); | ||
149 | DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); | ||
150 | DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); | ||
151 | DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); | ||
152 | DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); | ||
153 | DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); | ||
154 | DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); | ||
155 | DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); | ||
156 | DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); | ||
157 | DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); | ||
158 | DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); | ||
159 | |||
160 | DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); | ||
161 | DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); | ||
162 | /* skipping wep.reserved */ | ||
163 | DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); | ||
164 | DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); | ||
165 | DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); | ||
166 | DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); | ||
167 | |||
168 | DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); | ||
169 | DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); | ||
170 | DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); | ||
171 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); | ||
172 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); | ||
173 | DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); | ||
174 | DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); | ||
175 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); | ||
176 | DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); | ||
177 | DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); | ||
178 | DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); | ||
179 | DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); | ||
180 | /* skipping cont_miss_bcns_spread for now */ | ||
181 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); | ||
182 | |||
183 | DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); | ||
184 | DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); | ||
185 | |||
186 | DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); | ||
187 | DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); | ||
188 | DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); | ||
189 | DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); | ||
190 | DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); | ||
191 | DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); | ||
192 | |||
193 | DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); | ||
194 | DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); | ||
195 | DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); | ||
196 | DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); | ||
197 | DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); | ||
198 | DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); | ||
199 | DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); | ||
200 | DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); | ||
201 | |||
202 | DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); | ||
203 | DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); | ||
204 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); | ||
205 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); | ||
206 | DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); | ||
207 | DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); | ||
208 | DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); | ||
209 | |||
210 | DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); | ||
211 | DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); | ||
212 | DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, | ||
213 | 20, "%u"); | ||
214 | DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); | ||
215 | DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); | ||
216 | |||
217 | DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); | ||
218 | DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", | ||
219 | wl->stats.excessive_retries); | ||
220 | |||
221 | static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, | ||
222 | size_t count, loff_t *ppos) | ||
223 | { | ||
224 | struct wl1271 *wl = file->private_data; | ||
225 | u32 queue_len; | ||
226 | char buf[20]; | ||
227 | int res; | ||
228 | |||
229 | queue_len = skb_queue_len(&wl->tx_queue); | ||
230 | |||
231 | res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); | ||
232 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
233 | } | ||
234 | |||
235 | static const struct file_operations tx_queue_len_ops = { | ||
236 | .read = tx_queue_len_read, | ||
237 | .open = wl1271_open_file_generic, | ||
238 | }; | ||
239 | |||
240 | static void wl1271_debugfs_delete_files(struct wl1271 *wl) | ||
241 | { | ||
242 | DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); | ||
243 | |||
244 | DEBUGFS_FWSTATS_DEL(rx, out_of_mem); | ||
245 | DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); | ||
246 | DEBUGFS_FWSTATS_DEL(rx, hw_stuck); | ||
247 | DEBUGFS_FWSTATS_DEL(rx, dropped); | ||
248 | DEBUGFS_FWSTATS_DEL(rx, fcs_err); | ||
249 | DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); | ||
250 | DEBUGFS_FWSTATS_DEL(rx, path_reset); | ||
251 | DEBUGFS_FWSTATS_DEL(rx, reset_counter); | ||
252 | |||
253 | DEBUGFS_FWSTATS_DEL(dma, rx_requested); | ||
254 | DEBUGFS_FWSTATS_DEL(dma, rx_errors); | ||
255 | DEBUGFS_FWSTATS_DEL(dma, tx_requested); | ||
256 | DEBUGFS_FWSTATS_DEL(dma, tx_errors); | ||
257 | |||
258 | DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); | ||
259 | DEBUGFS_FWSTATS_DEL(isr, fiqs); | ||
260 | DEBUGFS_FWSTATS_DEL(isr, rx_headers); | ||
261 | DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); | ||
262 | DEBUGFS_FWSTATS_DEL(isr, rx_rdys); | ||
263 | DEBUGFS_FWSTATS_DEL(isr, irqs); | ||
264 | DEBUGFS_FWSTATS_DEL(isr, tx_procs); | ||
265 | DEBUGFS_FWSTATS_DEL(isr, decrypt_done); | ||
266 | DEBUGFS_FWSTATS_DEL(isr, dma0_done); | ||
267 | DEBUGFS_FWSTATS_DEL(isr, dma1_done); | ||
268 | DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); | ||
269 | DEBUGFS_FWSTATS_DEL(isr, commands); | ||
270 | DEBUGFS_FWSTATS_DEL(isr, rx_procs); | ||
271 | DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); | ||
272 | DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); | ||
273 | DEBUGFS_FWSTATS_DEL(isr, pci_pm); | ||
274 | DEBUGFS_FWSTATS_DEL(isr, wakeups); | ||
275 | DEBUGFS_FWSTATS_DEL(isr, low_rssi); | ||
276 | |||
277 | DEBUGFS_FWSTATS_DEL(wep, addr_key_count); | ||
278 | DEBUGFS_FWSTATS_DEL(wep, default_key_count); | ||
279 | /* skipping wep.reserved */ | ||
280 | DEBUGFS_FWSTATS_DEL(wep, key_not_found); | ||
281 | DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); | ||
282 | DEBUGFS_FWSTATS_DEL(wep, packets); | ||
283 | DEBUGFS_FWSTATS_DEL(wep, interrupt); | ||
284 | |||
285 | DEBUGFS_FWSTATS_DEL(pwr, ps_enter); | ||
286 | DEBUGFS_FWSTATS_DEL(pwr, elp_enter); | ||
287 | DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); | ||
288 | DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); | ||
289 | DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); | ||
290 | DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); | ||
291 | DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); | ||
292 | DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); | ||
293 | DEBUGFS_FWSTATS_DEL(pwr, power_save_off); | ||
294 | DEBUGFS_FWSTATS_DEL(pwr, enable_ps); | ||
295 | DEBUGFS_FWSTATS_DEL(pwr, disable_ps); | ||
296 | DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); | ||
297 | /* skipping cont_miss_bcns_spread for now */ | ||
298 | DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); | ||
299 | |||
300 | DEBUGFS_FWSTATS_DEL(mic, rx_pkts); | ||
301 | DEBUGFS_FWSTATS_DEL(mic, calc_failure); | ||
302 | |||
303 | DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); | ||
304 | DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); | ||
305 | DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); | ||
306 | DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); | ||
307 | DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); | ||
308 | DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); | ||
309 | |||
310 | DEBUGFS_FWSTATS_DEL(event, heart_beat); | ||
311 | DEBUGFS_FWSTATS_DEL(event, calibration); | ||
312 | DEBUGFS_FWSTATS_DEL(event, rx_mismatch); | ||
313 | DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); | ||
314 | DEBUGFS_FWSTATS_DEL(event, rx_pool); | ||
315 | DEBUGFS_FWSTATS_DEL(event, oom_late); | ||
316 | DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); | ||
317 | DEBUGFS_FWSTATS_DEL(event, tx_stuck); | ||
318 | |||
319 | DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); | ||
320 | DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); | ||
321 | DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); | ||
322 | DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); | ||
323 | DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); | ||
324 | DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); | ||
325 | DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); | ||
326 | |||
327 | DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); | ||
328 | DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); | ||
329 | DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); | ||
330 | DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); | ||
331 | DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); | ||
332 | |||
333 | DEBUGFS_DEL(tx_queue_len); | ||
334 | DEBUGFS_DEL(retry_count); | ||
335 | DEBUGFS_DEL(excessive_retries); | ||
336 | } | ||
337 | |||
338 | static int wl1271_debugfs_add_files(struct wl1271 *wl) | ||
339 | { | ||
340 | int ret = 0; | ||
341 | |||
342 | DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); | ||
343 | |||
344 | DEBUGFS_FWSTATS_ADD(rx, out_of_mem); | ||
345 | DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); | ||
346 | DEBUGFS_FWSTATS_ADD(rx, hw_stuck); | ||
347 | DEBUGFS_FWSTATS_ADD(rx, dropped); | ||
348 | DEBUGFS_FWSTATS_ADD(rx, fcs_err); | ||
349 | DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); | ||
350 | DEBUGFS_FWSTATS_ADD(rx, path_reset); | ||
351 | DEBUGFS_FWSTATS_ADD(rx, reset_counter); | ||
352 | |||
353 | DEBUGFS_FWSTATS_ADD(dma, rx_requested); | ||
354 | DEBUGFS_FWSTATS_ADD(dma, rx_errors); | ||
355 | DEBUGFS_FWSTATS_ADD(dma, tx_requested); | ||
356 | DEBUGFS_FWSTATS_ADD(dma, tx_errors); | ||
357 | |||
358 | DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); | ||
359 | DEBUGFS_FWSTATS_ADD(isr, fiqs); | ||
360 | DEBUGFS_FWSTATS_ADD(isr, rx_headers); | ||
361 | DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); | ||
362 | DEBUGFS_FWSTATS_ADD(isr, rx_rdys); | ||
363 | DEBUGFS_FWSTATS_ADD(isr, irqs); | ||
364 | DEBUGFS_FWSTATS_ADD(isr, tx_procs); | ||
365 | DEBUGFS_FWSTATS_ADD(isr, decrypt_done); | ||
366 | DEBUGFS_FWSTATS_ADD(isr, dma0_done); | ||
367 | DEBUGFS_FWSTATS_ADD(isr, dma1_done); | ||
368 | DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); | ||
369 | DEBUGFS_FWSTATS_ADD(isr, commands); | ||
370 | DEBUGFS_FWSTATS_ADD(isr, rx_procs); | ||
371 | DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); | ||
372 | DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); | ||
373 | DEBUGFS_FWSTATS_ADD(isr, pci_pm); | ||
374 | DEBUGFS_FWSTATS_ADD(isr, wakeups); | ||
375 | DEBUGFS_FWSTATS_ADD(isr, low_rssi); | ||
376 | |||
377 | DEBUGFS_FWSTATS_ADD(wep, addr_key_count); | ||
378 | DEBUGFS_FWSTATS_ADD(wep, default_key_count); | ||
379 | /* skipping wep.reserved */ | ||
380 | DEBUGFS_FWSTATS_ADD(wep, key_not_found); | ||
381 | DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); | ||
382 | DEBUGFS_FWSTATS_ADD(wep, packets); | ||
383 | DEBUGFS_FWSTATS_ADD(wep, interrupt); | ||
384 | |||
385 | DEBUGFS_FWSTATS_ADD(pwr, ps_enter); | ||
386 | DEBUGFS_FWSTATS_ADD(pwr, elp_enter); | ||
387 | DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); | ||
388 | DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); | ||
389 | DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); | ||
390 | DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); | ||
391 | DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); | ||
392 | DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); | ||
393 | DEBUGFS_FWSTATS_ADD(pwr, power_save_off); | ||
394 | DEBUGFS_FWSTATS_ADD(pwr, enable_ps); | ||
395 | DEBUGFS_FWSTATS_ADD(pwr, disable_ps); | ||
396 | DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); | ||
397 | /* skipping cont_miss_bcns_spread for now */ | ||
398 | DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); | ||
399 | |||
400 | DEBUGFS_FWSTATS_ADD(mic, rx_pkts); | ||
401 | DEBUGFS_FWSTATS_ADD(mic, calc_failure); | ||
402 | |||
403 | DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); | ||
404 | DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); | ||
405 | DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); | ||
406 | DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); | ||
407 | DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); | ||
408 | DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); | ||
409 | |||
410 | DEBUGFS_FWSTATS_ADD(event, heart_beat); | ||
411 | DEBUGFS_FWSTATS_ADD(event, calibration); | ||
412 | DEBUGFS_FWSTATS_ADD(event, rx_mismatch); | ||
413 | DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); | ||
414 | DEBUGFS_FWSTATS_ADD(event, rx_pool); | ||
415 | DEBUGFS_FWSTATS_ADD(event, oom_late); | ||
416 | DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); | ||
417 | DEBUGFS_FWSTATS_ADD(event, tx_stuck); | ||
418 | |||
419 | DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); | ||
420 | DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); | ||
421 | DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); | ||
422 | DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); | ||
423 | DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); | ||
424 | DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); | ||
425 | DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); | ||
426 | |||
427 | DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); | ||
428 | DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); | ||
429 | DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); | ||
430 | DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); | ||
431 | DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); | ||
432 | |||
433 | DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); | ||
434 | DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); | ||
435 | DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); | ||
436 | |||
437 | out: | ||
438 | if (ret < 0) | ||
439 | wl1271_debugfs_delete_files(wl); | ||
440 | |||
441 | return ret; | ||
442 | } | ||
443 | |||
444 | void wl1271_debugfs_reset(struct wl1271 *wl) | ||
445 | { | ||
446 | memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); | ||
447 | wl->stats.retry_count = 0; | ||
448 | wl->stats.excessive_retries = 0; | ||
449 | } | ||
450 | |||
451 | int wl1271_debugfs_init(struct wl1271 *wl) | ||
452 | { | ||
453 | int ret; | ||
454 | |||
455 | wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); | ||
456 | |||
457 | if (IS_ERR(wl->debugfs.rootdir)) { | ||
458 | ret = PTR_ERR(wl->debugfs.rootdir); | ||
459 | wl->debugfs.rootdir = NULL; | ||
460 | goto err; | ||
461 | } | ||
462 | |||
463 | wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", | ||
464 | wl->debugfs.rootdir); | ||
465 | |||
466 | if (IS_ERR(wl->debugfs.fw_statistics)) { | ||
467 | ret = PTR_ERR(wl->debugfs.fw_statistics); | ||
468 | wl->debugfs.fw_statistics = NULL; | ||
469 | goto err_root; | ||
470 | } | ||
471 | |||
472 | wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), | ||
473 | GFP_KERNEL); | ||
474 | |||
475 | if (!wl->stats.fw_stats) { | ||
476 | ret = -ENOMEM; | ||
477 | goto err_fw; | ||
478 | } | ||
479 | |||
480 | wl->stats.fw_stats_update = jiffies; | ||
481 | |||
482 | ret = wl1271_debugfs_add_files(wl); | ||
483 | |||
484 | if (ret < 0) | ||
485 | goto err_file; | ||
486 | |||
487 | return 0; | ||
488 | |||
489 | err_file: | ||
490 | kfree(wl->stats.fw_stats); | ||
491 | wl->stats.fw_stats = NULL; | ||
492 | |||
493 | err_fw: | ||
494 | debugfs_remove(wl->debugfs.fw_statistics); | ||
495 | wl->debugfs.fw_statistics = NULL; | ||
496 | |||
497 | err_root: | ||
498 | debugfs_remove(wl->debugfs.rootdir); | ||
499 | wl->debugfs.rootdir = NULL; | ||
500 | |||
501 | err: | ||
502 | return ret; | ||
503 | } | ||
504 | |||
505 | void wl1271_debugfs_exit(struct wl1271 *wl) | ||
506 | { | ||
507 | wl1271_debugfs_delete_files(wl); | ||
508 | |||
509 | kfree(wl->stats.fw_stats); | ||
510 | wl->stats.fw_stats = NULL; | ||
511 | |||
512 | debugfs_remove(wl->debugfs.fw_statistics); | ||
513 | wl->debugfs.fw_statistics = NULL; | ||
514 | |||
515 | debugfs_remove(wl->debugfs.rootdir); | ||
516 | wl->debugfs.rootdir = NULL; | ||
517 | |||
518 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.h b/drivers/net/wireless/wl12xx/wl1271_debugfs.h new file mode 100644 index 000000000000..00a45b2669ad --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef WL1271_DEBUGFS_H | ||
25 | #define WL1271_DEBUGFS_H | ||
26 | |||
27 | #include "wl1271.h" | ||
28 | |||
29 | int wl1271_debugfs_init(struct wl1271 *wl); | ||
30 | void wl1271_debugfs_exit(struct wl1271 *wl); | ||
31 | void wl1271_debugfs_reset(struct wl1271 *wl); | ||
32 | |||
33 | #endif /* WL1271_DEBUGFS_H */ | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c new file mode 100644 index 000000000000..f3afd4a6ff33 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_event.c | |||
@@ -0,0 +1,125 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "wl1271.h" | ||
25 | #include "wl1271_reg.h" | ||
26 | #include "wl1271_spi.h" | ||
27 | #include "wl1271_event.h" | ||
28 | #include "wl1271_ps.h" | ||
29 | |||
30 | static int wl1271_event_scan_complete(struct wl1271 *wl, | ||
31 | struct event_mailbox *mbox) | ||
32 | { | ||
33 | wl1271_debug(DEBUG_EVENT, "status: 0x%x", | ||
34 | mbox->scheduled_scan_status); | ||
35 | |||
36 | if (wl->scanning) { | ||
37 | mutex_unlock(&wl->mutex); | ||
38 | ieee80211_scan_completed(wl->hw, false); | ||
39 | mutex_lock(&wl->mutex); | ||
40 | wl->scanning = false; | ||
41 | } | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static void wl1271_event_mbox_dump(struct event_mailbox *mbox) | ||
47 | { | ||
48 | wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); | ||
49 | wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); | ||
50 | wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); | ||
51 | } | ||
52 | |||
53 | static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) | ||
54 | { | ||
55 | int ret; | ||
56 | u32 vector; | ||
57 | |||
58 | wl1271_event_mbox_dump(mbox); | ||
59 | |||
60 | vector = mbox->events_vector & ~(mbox->events_mask); | ||
61 | wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); | ||
62 | |||
63 | if (vector & SCAN_COMPLETE_EVENT_ID) { | ||
64 | ret = wl1271_event_scan_complete(wl, mbox); | ||
65 | if (ret < 0) | ||
66 | return ret; | ||
67 | } | ||
68 | |||
69 | if (vector & BSS_LOSE_EVENT_ID) { | ||
70 | wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); | ||
71 | |||
72 | if (wl->psm_requested && wl->psm) { | ||
73 | ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
74 | if (ret < 0) | ||
75 | return ret; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | int wl1271_event_unmask(struct wl1271 *wl) | ||
83 | { | ||
84 | int ret; | ||
85 | |||
86 | ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask)); | ||
87 | if (ret < 0) | ||
88 | return ret; | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | void wl1271_event_mbox_config(struct wl1271 *wl) | ||
94 | { | ||
95 | wl->mbox_ptr[0] = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR); | ||
96 | wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); | ||
97 | |||
98 | wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", | ||
99 | wl->mbox_ptr[0], wl->mbox_ptr[1]); | ||
100 | } | ||
101 | |||
102 | int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) | ||
103 | { | ||
104 | struct event_mailbox mbox; | ||
105 | int ret; | ||
106 | |||
107 | wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); | ||
108 | |||
109 | if (mbox_num > 1) | ||
110 | return -EINVAL; | ||
111 | |||
112 | /* first we read the mbox descriptor */ | ||
113 | wl1271_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, | ||
114 | sizeof(struct event_mailbox)); | ||
115 | |||
116 | /* process the descriptor */ | ||
117 | ret = wl1271_event_process(wl, &mbox); | ||
118 | if (ret < 0) | ||
119 | return ret; | ||
120 | |||
121 | /* then we let the firmware know it can go on...*/ | ||
122 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h new file mode 100644 index 000000000000..2cdce7c34bf0 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_event.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_EVENT_H__ | ||
26 | #define __WL1271_EVENT_H__ | ||
27 | |||
28 | /* | ||
29 | * Mbox events | ||
30 | * | ||
31 | * The event mechanism is based on a pair of event buffers (buffers A and | ||
32 | * B) at fixed locations in the target's memory. The host processes one | ||
33 | * buffer while the other buffer continues to collect events. If the host | ||
34 | * is not processing events, an interrupt is issued to signal that a buffer | ||
35 | * is ready. Once the host is done with processing events from one buffer, | ||
36 | * it signals the target (with an ACK interrupt) that the event buffer is | ||
37 | * free. | ||
38 | */ | ||
39 | |||
40 | enum { | ||
41 | MEASUREMENT_START_EVENT_ID = BIT(8), | ||
42 | MEASUREMENT_COMPLETE_EVENT_ID = BIT(9), | ||
43 | SCAN_COMPLETE_EVENT_ID = BIT(10), | ||
44 | SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(11), | ||
45 | AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12), | ||
46 | PS_REPORT_EVENT_ID = BIT(13), | ||
47 | PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14), | ||
48 | DISCONNECT_EVENT_COMPLETE_ID = BIT(15), | ||
49 | JOIN_EVENT_COMPLETE_ID = BIT(16), | ||
50 | CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), | ||
51 | BSS_LOSE_EVENT_ID = BIT(18), | ||
52 | REGAINED_BSS_EVENT_ID = BIT(19), | ||
53 | ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), | ||
54 | SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), | ||
55 | SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), | ||
56 | SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), | ||
57 | PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), | ||
58 | DBG_EVENT_ID = BIT(26), | ||
59 | HEALTH_CHECK_REPLY_EVENT_ID = BIT(27), | ||
60 | PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), | ||
61 | PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), | ||
62 | BA_SESSION_TEAR_DOWN_EVENT_ID = BIT(30), | ||
63 | EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, | ||
64 | }; | ||
65 | |||
66 | struct event_debug_report { | ||
67 | u8 debug_event_id; | ||
68 | u8 num_params; | ||
69 | u16 pad; | ||
70 | u32 report_1; | ||
71 | u32 report_2; | ||
72 | u32 report_3; | ||
73 | } __attribute__ ((packed)); | ||
74 | |||
75 | #define NUM_OF_RSSI_SNR_TRIGGERS 8 | ||
76 | |||
77 | struct event_mailbox { | ||
78 | u32 events_vector; | ||
79 | u32 events_mask; | ||
80 | u32 reserved_1; | ||
81 | u32 reserved_2; | ||
82 | |||
83 | u8 dbg_event_id; | ||
84 | u8 num_relevant_params; | ||
85 | u16 reserved_3; | ||
86 | u32 event_report_p1; | ||
87 | u32 event_report_p2; | ||
88 | u32 event_report_p3; | ||
89 | |||
90 | u8 number_of_scan_results; | ||
91 | u8 scan_tag; | ||
92 | u8 reserved_4[2]; | ||
93 | u32 compl_scheduled_scan_status; | ||
94 | |||
95 | u16 scheduled_scan_attended_channels; | ||
96 | u8 soft_gemini_sense_info; | ||
97 | u8 soft_gemini_protective_info; | ||
98 | s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; | ||
99 | u8 channel_switch_status; | ||
100 | u8 scheduled_scan_status; | ||
101 | u8 ps_status; | ||
102 | |||
103 | u8 reserved_5[29]; | ||
104 | } __attribute__ ((packed)); | ||
105 | |||
106 | int wl1271_event_unmask(struct wl1271 *wl); | ||
107 | void wl1271_event_mbox_config(struct wl1271 *wl); | ||
108 | int wl1271_event_handle(struct wl1271 *wl, u8 mbox); | ||
109 | |||
110 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c new file mode 100644 index 000000000000..490df217605a --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_init.c | |||
@@ -0,0 +1,397 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | |||
27 | #include "wl1271_init.h" | ||
28 | #include "wl12xx_80211.h" | ||
29 | #include "wl1271_acx.h" | ||
30 | #include "wl1271_cmd.h" | ||
31 | #include "wl1271_reg.h" | ||
32 | |||
33 | static int wl1271_init_hwenc_config(struct wl1271 *wl) | ||
34 | { | ||
35 | int ret; | ||
36 | |||
37 | ret = wl1271_acx_feature_cfg(wl); | ||
38 | if (ret < 0) { | ||
39 | wl1271_warning("couldn't set feature config"); | ||
40 | return ret; | ||
41 | } | ||
42 | |||
43 | ret = wl1271_cmd_set_default_wep_key(wl, wl->default_key); | ||
44 | if (ret < 0) { | ||
45 | wl1271_warning("couldn't set default key"); | ||
46 | return ret; | ||
47 | } | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static int wl1271_init_templates_config(struct wl1271 *wl) | ||
53 | { | ||
54 | int ret; | ||
55 | |||
56 | /* send empty templates for fw memory reservation */ | ||
57 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, | ||
58 | sizeof(struct wl12xx_probe_req_template)); | ||
59 | if (ret < 0) | ||
60 | return ret; | ||
61 | |||
62 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, | ||
63 | sizeof(struct wl12xx_null_data_template)); | ||
64 | if (ret < 0) | ||
65 | return ret; | ||
66 | |||
67 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL, | ||
68 | sizeof(struct wl12xx_ps_poll_template)); | ||
69 | if (ret < 0) | ||
70 | return ret; | ||
71 | |||
72 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, | ||
73 | sizeof | ||
74 | (struct wl12xx_qos_null_data_template)); | ||
75 | if (ret < 0) | ||
76 | return ret; | ||
77 | |||
78 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL, | ||
79 | sizeof | ||
80 | (struct wl12xx_probe_resp_template)); | ||
81 | if (ret < 0) | ||
82 | return ret; | ||
83 | |||
84 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL, | ||
85 | sizeof | ||
86 | (struct wl12xx_beacon_template)); | ||
87 | if (ret < 0) | ||
88 | return ret; | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) | ||
94 | { | ||
95 | int ret; | ||
96 | |||
97 | ret = wl1271_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); | ||
98 | if (ret < 0) | ||
99 | return ret; | ||
100 | |||
101 | ret = wl1271_acx_rx_config(wl, config, filter); | ||
102 | if (ret < 0) | ||
103 | return ret; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int wl1271_init_phy_config(struct wl1271 *wl) | ||
109 | { | ||
110 | int ret; | ||
111 | |||
112 | ret = wl1271_acx_pd_threshold(wl); | ||
113 | if (ret < 0) | ||
114 | return ret; | ||
115 | |||
116 | ret = wl1271_acx_slot(wl, DEFAULT_SLOT_TIME); | ||
117 | if (ret < 0) | ||
118 | return ret; | ||
119 | |||
120 | ret = wl1271_acx_group_address_tbl(wl); | ||
121 | if (ret < 0) | ||
122 | return ret; | ||
123 | |||
124 | ret = wl1271_acx_service_period_timeout(wl); | ||
125 | if (ret < 0) | ||
126 | return ret; | ||
127 | |||
128 | ret = wl1271_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); | ||
129 | if (ret < 0) | ||
130 | return ret; | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static int wl1271_init_beacon_filter(struct wl1271 *wl) | ||
136 | { | ||
137 | int ret; | ||
138 | |||
139 | ret = wl1271_acx_beacon_filter_opt(wl); | ||
140 | if (ret < 0) | ||
141 | return ret; | ||
142 | |||
143 | ret = wl1271_acx_beacon_filter_table(wl); | ||
144 | if (ret < 0) | ||
145 | return ret; | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int wl1271_init_pta(struct wl1271 *wl) | ||
151 | { | ||
152 | int ret; | ||
153 | |||
154 | ret = wl1271_acx_sg_enable(wl); | ||
155 | if (ret < 0) | ||
156 | return ret; | ||
157 | |||
158 | ret = wl1271_acx_sg_cfg(wl); | ||
159 | if (ret < 0) | ||
160 | return ret; | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int wl1271_init_energy_detection(struct wl1271 *wl) | ||
166 | { | ||
167 | int ret; | ||
168 | |||
169 | ret = wl1271_acx_cca_threshold(wl); | ||
170 | if (ret < 0) | ||
171 | return ret; | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int wl1271_init_beacon_broadcast(struct wl1271 *wl) | ||
177 | { | ||
178 | int ret; | ||
179 | |||
180 | ret = wl1271_acx_bcn_dtim_options(wl); | ||
181 | if (ret < 0) | ||
182 | return ret; | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int wl1271_init_general_parms(struct wl1271 *wl) | ||
188 | { | ||
189 | struct wl1271_general_parms *gen_parms; | ||
190 | int ret; | ||
191 | |||
192 | gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); | ||
193 | if (!gen_parms) | ||
194 | return -ENOMEM; | ||
195 | |||
196 | gen_parms->id = TEST_CMD_INI_FILE_GENERAL_PARAM; | ||
197 | |||
198 | gen_parms->ref_clk = REF_CLK_38_4_E; | ||
199 | /* FIXME: magic numbers */ | ||
200 | gen_parms->settling_time = 5; | ||
201 | gen_parms->clk_valid_on_wakeup = 0; | ||
202 | gen_parms->dc2dcmode = 0; | ||
203 | gen_parms->single_dual_band = 0; | ||
204 | gen_parms->tx_bip_fem_autodetect = 1; | ||
205 | gen_parms->tx_bip_fem_manufacturer = 1; | ||
206 | gen_parms->settings = 1; | ||
207 | |||
208 | ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); | ||
209 | if (ret < 0) { | ||
210 | wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); | ||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | kfree(gen_parms); | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int wl1271_init_radio_parms(struct wl1271 *wl) | ||
219 | { | ||
220 | /* | ||
221 | * FIXME: All these magic numbers should be moved to some place where | ||
222 | * they can be configured (separate file?) | ||
223 | */ | ||
224 | |||
225 | struct wl1271_radio_parms *radio_parms; | ||
226 | int ret; | ||
227 | u8 compensation[] = { 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, 0xfc, 0x00, | ||
228 | 0x08, 0x10, 0xf0, 0xf8, 0x00, 0x0a, 0x14 }; | ||
229 | |||
230 | u8 tx_rate_limits_normal[] = { 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 }; | ||
231 | u8 tx_rate_limits_degraded[] = { 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 }; | ||
232 | |||
233 | u8 tx_channel_limits_11b[] = { 0x22, 0x50, 0x50, 0x50, | ||
234 | 0x50, 0x50, 0x50, 0x50, | ||
235 | 0x50, 0x50, 0x22, 0x50, | ||
236 | 0x22, 0x50 }; | ||
237 | |||
238 | u8 tx_channel_limits_ofdm[] = { 0x20, 0x50, 0x50, 0x50, | ||
239 | 0x50, 0x50, 0x50, 0x50, | ||
240 | 0x50, 0x50, 0x20, 0x50, | ||
241 | 0x20, 0x50 }; | ||
242 | |||
243 | u8 tx_pdv_rate_offsets[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
244 | |||
245 | u8 tx_ibias[] = { 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 }; | ||
246 | |||
247 | radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); | ||
248 | if (!radio_parms) | ||
249 | return -ENOMEM; | ||
250 | |||
251 | radio_parms->id = TEST_CMD_INI_FILE_RADIO_PARAM; | ||
252 | |||
253 | /* Static radio parameters */ | ||
254 | radio_parms->rx_trace_loss = 10; | ||
255 | radio_parms->tx_trace_loss = 10; | ||
256 | memcpy(radio_parms->rx_rssi_and_proc_compens, compensation, | ||
257 | sizeof(compensation)); | ||
258 | |||
259 | /* We don't set the 5GHz -- N/A */ | ||
260 | |||
261 | /* Dynamic radio parameters */ | ||
262 | radio_parms->tx_ref_pd_voltage = cpu_to_le16(0x24e); | ||
263 | radio_parms->tx_ref_power = 0x78; | ||
264 | radio_parms->tx_offset_db = 0x0; | ||
265 | |||
266 | memcpy(radio_parms->tx_rate_limits_normal, tx_rate_limits_normal, | ||
267 | sizeof(tx_rate_limits_normal)); | ||
268 | memcpy(radio_parms->tx_rate_limits_degraded, tx_rate_limits_degraded, | ||
269 | sizeof(tx_rate_limits_degraded)); | ||
270 | |||
271 | memcpy(radio_parms->tx_channel_limits_11b, tx_channel_limits_11b, | ||
272 | sizeof(tx_channel_limits_11b)); | ||
273 | memcpy(radio_parms->tx_channel_limits_ofdm, tx_channel_limits_ofdm, | ||
274 | sizeof(tx_channel_limits_ofdm)); | ||
275 | memcpy(radio_parms->tx_pdv_rate_offsets, tx_pdv_rate_offsets, | ||
276 | sizeof(tx_pdv_rate_offsets)); | ||
277 | memcpy(radio_parms->tx_ibias, tx_ibias, | ||
278 | sizeof(tx_ibias)); | ||
279 | |||
280 | radio_parms->rx_fem_insertion_loss = 0x14; | ||
281 | |||
282 | ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); | ||
283 | if (ret < 0) | ||
284 | wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); | ||
285 | |||
286 | kfree(radio_parms); | ||
287 | return ret; | ||
288 | } | ||
289 | |||
290 | int wl1271_hw_init(struct wl1271 *wl) | ||
291 | { | ||
292 | int ret; | ||
293 | |||
294 | ret = wl1271_init_general_parms(wl); | ||
295 | if (ret < 0) | ||
296 | return ret; | ||
297 | |||
298 | ret = wl1271_init_radio_parms(wl); | ||
299 | if (ret < 0) | ||
300 | return ret; | ||
301 | |||
302 | /* Template settings */ | ||
303 | ret = wl1271_init_templates_config(wl); | ||
304 | if (ret < 0) | ||
305 | return ret; | ||
306 | |||
307 | /* Default memory configuration */ | ||
308 | ret = wl1271_acx_init_mem_config(wl); | ||
309 | if (ret < 0) | ||
310 | return ret; | ||
311 | |||
312 | /* RX config */ | ||
313 | ret = wl1271_init_rx_config(wl, | ||
314 | RX_CFG_PROMISCUOUS | RX_CFG_TSF, | ||
315 | RX_FILTER_OPTION_DEF); | ||
316 | /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, | ||
317 | RX_FILTER_OPTION_FILTER_ALL); */ | ||
318 | if (ret < 0) | ||
319 | goto out_free_memmap; | ||
320 | |||
321 | /* PHY layer config */ | ||
322 | ret = wl1271_init_phy_config(wl); | ||
323 | if (ret < 0) | ||
324 | goto out_free_memmap; | ||
325 | |||
326 | /* Beacon filtering */ | ||
327 | ret = wl1271_init_beacon_filter(wl); | ||
328 | if (ret < 0) | ||
329 | goto out_free_memmap; | ||
330 | |||
331 | /* Configure TX patch complete interrupt behavior */ | ||
332 | ret = wl1271_acx_tx_config_options(wl); | ||
333 | if (ret < 0) | ||
334 | goto out_free_memmap; | ||
335 | |||
336 | /* RX complete interrupt pacing */ | ||
337 | ret = wl1271_acx_init_rx_interrupt(wl); | ||
338 | if (ret < 0) | ||
339 | goto out_free_memmap; | ||
340 | |||
341 | /* Bluetooth WLAN coexistence */ | ||
342 | ret = wl1271_init_pta(wl); | ||
343 | if (ret < 0) | ||
344 | goto out_free_memmap; | ||
345 | |||
346 | /* Energy detection */ | ||
347 | ret = wl1271_init_energy_detection(wl); | ||
348 | if (ret < 0) | ||
349 | goto out_free_memmap; | ||
350 | |||
351 | /* Beacons and boradcast settings */ | ||
352 | ret = wl1271_init_beacon_broadcast(wl); | ||
353 | if (ret < 0) | ||
354 | goto out_free_memmap; | ||
355 | |||
356 | /* Default fragmentation threshold */ | ||
357 | ret = wl1271_acx_frag_threshold(wl); | ||
358 | if (ret < 0) | ||
359 | goto out_free_memmap; | ||
360 | |||
361 | /* Default TID configuration */ | ||
362 | ret = wl1271_acx_tid_cfg(wl); | ||
363 | if (ret < 0) | ||
364 | goto out_free_memmap; | ||
365 | |||
366 | /* Default AC configuration */ | ||
367 | ret = wl1271_acx_ac_cfg(wl); | ||
368 | if (ret < 0) | ||
369 | goto out_free_memmap; | ||
370 | |||
371 | /* Configure TX rate classes */ | ||
372 | ret = wl1271_acx_rate_policies(wl); | ||
373 | if (ret < 0) | ||
374 | goto out_free_memmap; | ||
375 | |||
376 | /* Enable data path */ | ||
377 | ret = wl1271_cmd_data_path(wl, wl->channel, 1); | ||
378 | if (ret < 0) | ||
379 | goto out_free_memmap; | ||
380 | |||
381 | /* Configure for ELP power saving */ | ||
382 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); | ||
383 | if (ret < 0) | ||
384 | goto out_free_memmap; | ||
385 | |||
386 | /* Configure HW encryption */ | ||
387 | ret = wl1271_init_hwenc_config(wl); | ||
388 | if (ret < 0) | ||
389 | goto out_free_memmap; | ||
390 | |||
391 | return 0; | ||
392 | |||
393 | out_free_memmap: | ||
394 | kfree(wl->target_mem_map); | ||
395 | |||
396 | return ret; | ||
397 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.h b/drivers/net/wireless/wl12xx/wl1271_init.h new file mode 100644 index 000000000000..bd8ff0fa2272 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_init.h | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __WL1271_INIT_H__ | ||
25 | #define __WL1271_INIT_H__ | ||
26 | |||
27 | #include "wl1271.h" | ||
28 | |||
29 | int wl1271_hw_init_power_auth(struct wl1271 *wl); | ||
30 | int wl1271_hw_init(struct wl1271 *wl); | ||
31 | |||
32 | /* These are not really a TEST_CMD, but the ref driver uses them as such */ | ||
33 | #define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 | ||
34 | #define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E | ||
35 | |||
36 | struct wl1271_general_parms { | ||
37 | u8 id; | ||
38 | u8 padding[3]; | ||
39 | |||
40 | u8 ref_clk; | ||
41 | u8 settling_time; | ||
42 | u8 clk_valid_on_wakeup; | ||
43 | u8 dc2dcmode; | ||
44 | u8 single_dual_band; | ||
45 | |||
46 | u8 tx_bip_fem_autodetect; | ||
47 | u8 tx_bip_fem_manufacturer; | ||
48 | u8 settings; | ||
49 | } __attribute__ ((packed)); | ||
50 | |||
51 | enum ref_clk_enum { | ||
52 | REF_CLK_19_2_E, | ||
53 | REF_CLK_26_E, | ||
54 | REF_CLK_38_4_E, | ||
55 | REF_CLK_52_E | ||
56 | }; | ||
57 | |||
58 | #define RSSI_AND_PROCESS_COMPENSATION_SIZE 15 | ||
59 | #define NUMBER_OF_SUB_BANDS_5 7 | ||
60 | #define NUMBER_OF_RATE_GROUPS 6 | ||
61 | #define NUMBER_OF_CHANNELS_2_4 14 | ||
62 | #define NUMBER_OF_CHANNELS_5 35 | ||
63 | |||
64 | struct wl1271_radio_parms { | ||
65 | u8 id; | ||
66 | u8 padding[3]; | ||
67 | |||
68 | /* Static radio parameters */ | ||
69 | /* 2.4GHz */ | ||
70 | u8 rx_trace_loss; | ||
71 | u8 tx_trace_loss; | ||
72 | s8 rx_rssi_and_proc_compens[RSSI_AND_PROCESS_COMPENSATION_SIZE]; | ||
73 | |||
74 | /* 5GHz */ | ||
75 | u8 rx_trace_loss_5[NUMBER_OF_SUB_BANDS_5]; | ||
76 | u8 tx_trace_loss_5[NUMBER_OF_SUB_BANDS_5]; | ||
77 | s8 rx_rssi_and_proc_compens_5[RSSI_AND_PROCESS_COMPENSATION_SIZE]; | ||
78 | |||
79 | /* Dynamic radio parameters */ | ||
80 | /* 2.4GHz */ | ||
81 | s16 tx_ref_pd_voltage; | ||
82 | s8 tx_ref_power; | ||
83 | s8 tx_offset_db; | ||
84 | |||
85 | s8 tx_rate_limits_normal[NUMBER_OF_RATE_GROUPS]; | ||
86 | s8 tx_rate_limits_degraded[NUMBER_OF_RATE_GROUPS]; | ||
87 | |||
88 | s8 tx_channel_limits_11b[NUMBER_OF_CHANNELS_2_4]; | ||
89 | s8 tx_channel_limits_ofdm[NUMBER_OF_CHANNELS_2_4]; | ||
90 | s8 tx_pdv_rate_offsets[NUMBER_OF_RATE_GROUPS]; | ||
91 | |||
92 | u8 tx_ibias[NUMBER_OF_RATE_GROUPS]; | ||
93 | u8 rx_fem_insertion_loss; | ||
94 | |||
95 | u8 padding2; | ||
96 | |||
97 | /* 5GHz */ | ||
98 | s16 tx_ref_pd_voltage_5[NUMBER_OF_SUB_BANDS_5]; | ||
99 | s8 tx_ref_power_5[NUMBER_OF_SUB_BANDS_5]; | ||
100 | s8 tx_offset_db_5[NUMBER_OF_SUB_BANDS_5]; | ||
101 | |||
102 | s8 tx_rate_limits_normal_5[NUMBER_OF_RATE_GROUPS]; | ||
103 | s8 tx_rate_limits_degraded_5[NUMBER_OF_RATE_GROUPS]; | ||
104 | |||
105 | s8 tx_channel_limits_ofdm_5[NUMBER_OF_CHANNELS_5]; | ||
106 | s8 tx_pdv_rate_offsets_5[NUMBER_OF_RATE_GROUPS]; | ||
107 | |||
108 | /* FIXME: this is inconsistent with the types for 2.4GHz */ | ||
109 | s8 tx_ibias_5[NUMBER_OF_RATE_GROUPS]; | ||
110 | s8 rx_fem_insertion_loss_5[NUMBER_OF_SUB_BANDS_5]; | ||
111 | |||
112 | u8 padding3[2]; | ||
113 | } __attribute__ ((packed)); | ||
114 | |||
115 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c new file mode 100644 index 000000000000..4102d590b798 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -0,0 +1,1397 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/firmware.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/irq.h> | ||
30 | #include <linux/spi/spi.h> | ||
31 | #include <linux/crc32.h> | ||
32 | #include <linux/etherdevice.h> | ||
33 | #include <linux/spi/wl12xx.h> | ||
34 | |||
35 | #include "wl1271.h" | ||
36 | #include "wl12xx_80211.h" | ||
37 | #include "wl1271_reg.h" | ||
38 | #include "wl1271_spi.h" | ||
39 | #include "wl1271_event.h" | ||
40 | #include "wl1271_tx.h" | ||
41 | #include "wl1271_rx.h" | ||
42 | #include "wl1271_ps.h" | ||
43 | #include "wl1271_init.h" | ||
44 | #include "wl1271_debugfs.h" | ||
45 | #include "wl1271_cmd.h" | ||
46 | #include "wl1271_boot.h" | ||
47 | |||
48 | static int wl1271_plt_init(struct wl1271 *wl) | ||
49 | { | ||
50 | int ret; | ||
51 | |||
52 | ret = wl1271_acx_init_mem_config(wl); | ||
53 | if (ret < 0) | ||
54 | return ret; | ||
55 | |||
56 | ret = wl1271_cmd_data_path(wl, wl->channel, 1); | ||
57 | if (ret < 0) | ||
58 | return ret; | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static void wl1271_disable_interrupts(struct wl1271 *wl) | ||
64 | { | ||
65 | disable_irq(wl->irq); | ||
66 | } | ||
67 | |||
68 | static void wl1271_power_off(struct wl1271 *wl) | ||
69 | { | ||
70 | wl->set_power(false); | ||
71 | } | ||
72 | |||
73 | static void wl1271_power_on(struct wl1271 *wl) | ||
74 | { | ||
75 | wl->set_power(true); | ||
76 | } | ||
77 | |||
78 | static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status) | ||
79 | { | ||
80 | u32 total = 0; | ||
81 | int i; | ||
82 | |||
83 | /* | ||
84 | * FIXME: Reading the FW status directly from the registers seems to | ||
85 | * be the right thing to do, but it doesn't work. And in the | ||
86 | * reference driver, there is a workaround called | ||
87 | * USE_SDIO_24M_WORKAROUND, which reads the status from memory | ||
88 | * instead, so we do the same here. | ||
89 | */ | ||
90 | |||
91 | wl1271_spi_mem_read(wl, STATUS_MEM_ADDRESS, status, sizeof(*status)); | ||
92 | |||
93 | wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " | ||
94 | "drv_rx_counter = %d, tx_results_counter = %d)", | ||
95 | status->intr, | ||
96 | status->fw_rx_counter, | ||
97 | status->drv_rx_counter, | ||
98 | status->tx_results_counter); | ||
99 | |||
100 | /* update number of available TX blocks */ | ||
101 | for (i = 0; i < NUM_TX_QUEUES; i++) { | ||
102 | u32 cnt = status->tx_released_blks[i] - wl->tx_blocks_freed[i]; | ||
103 | wl->tx_blocks_freed[i] = status->tx_released_blks[i]; | ||
104 | wl->tx_blocks_available += cnt; | ||
105 | total += cnt; | ||
106 | } | ||
107 | |||
108 | /* if more blocks are available now, schedule some tx work */ | ||
109 | if (total && !skb_queue_empty(&wl->tx_queue)) | ||
110 | schedule_work(&wl->tx_work); | ||
111 | |||
112 | /* update the host-chipset time offset */ | ||
113 | wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime; | ||
114 | } | ||
115 | |||
116 | #define WL1271_IRQ_MAX_LOOPS 10 | ||
117 | static void wl1271_irq_work(struct work_struct *work) | ||
118 | { | ||
119 | u32 intr, ctr = WL1271_IRQ_MAX_LOOPS; | ||
120 | int ret; | ||
121 | struct wl1271 *wl = | ||
122 | container_of(work, struct wl1271, irq_work); | ||
123 | |||
124 | mutex_lock(&wl->mutex); | ||
125 | |||
126 | wl1271_debug(DEBUG_IRQ, "IRQ work"); | ||
127 | |||
128 | if (wl->state == WL1271_STATE_OFF) | ||
129 | goto out; | ||
130 | |||
131 | ret = wl1271_ps_elp_wakeup(wl, true); | ||
132 | if (ret < 0) | ||
133 | goto out; | ||
134 | |||
135 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); | ||
136 | |||
137 | intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
138 | if (!intr) { | ||
139 | wl1271_debug(DEBUG_IRQ, "Zero interrupt received."); | ||
140 | goto out_sleep; | ||
141 | } | ||
142 | |||
143 | intr &= WL1271_INTR_MASK; | ||
144 | |||
145 | do { | ||
146 | wl1271_fw_status(wl, wl->fw_status); | ||
147 | |||
148 | |||
149 | if (intr & (WL1271_ACX_INTR_EVENT_A | | ||
150 | WL1271_ACX_INTR_EVENT_B)) { | ||
151 | wl1271_debug(DEBUG_IRQ, | ||
152 | "WL1271_ACX_INTR_EVENT (0x%x)", intr); | ||
153 | if (intr & WL1271_ACX_INTR_EVENT_A) | ||
154 | wl1271_event_handle(wl, 0); | ||
155 | else | ||
156 | wl1271_event_handle(wl, 1); | ||
157 | } | ||
158 | |||
159 | if (intr & WL1271_ACX_INTR_INIT_COMPLETE) | ||
160 | wl1271_debug(DEBUG_IRQ, | ||
161 | "WL1271_ACX_INTR_INIT_COMPLETE"); | ||
162 | |||
163 | if (intr & WL1271_ACX_INTR_HW_AVAILABLE) | ||
164 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); | ||
165 | |||
166 | if (intr & WL1271_ACX_INTR_DATA) { | ||
167 | u8 tx_res_cnt = wl->fw_status->tx_results_counter - | ||
168 | wl->tx_results_count; | ||
169 | |||
170 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); | ||
171 | |||
172 | /* check for tx results */ | ||
173 | if (tx_res_cnt) | ||
174 | wl1271_tx_complete(wl, tx_res_cnt); | ||
175 | |||
176 | wl1271_rx(wl, wl->fw_status); | ||
177 | } | ||
178 | |||
179 | intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
180 | intr &= WL1271_INTR_MASK; | ||
181 | } while (intr && --ctr); | ||
182 | |||
183 | out_sleep: | ||
184 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
185 | WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); | ||
186 | wl1271_ps_elp_sleep(wl); | ||
187 | |||
188 | out: | ||
189 | mutex_unlock(&wl->mutex); | ||
190 | } | ||
191 | |||
192 | static irqreturn_t wl1271_irq(int irq, void *cookie) | ||
193 | { | ||
194 | struct wl1271 *wl; | ||
195 | unsigned long flags; | ||
196 | |||
197 | wl1271_debug(DEBUG_IRQ, "IRQ"); | ||
198 | |||
199 | wl = cookie; | ||
200 | |||
201 | /* complete the ELP completion */ | ||
202 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
203 | if (wl->elp_compl) { | ||
204 | complete(wl->elp_compl); | ||
205 | wl->elp_compl = NULL; | ||
206 | } | ||
207 | |||
208 | schedule_work(&wl->irq_work); | ||
209 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
210 | |||
211 | return IRQ_HANDLED; | ||
212 | } | ||
213 | |||
214 | static int wl1271_fetch_firmware(struct wl1271 *wl) | ||
215 | { | ||
216 | const struct firmware *fw; | ||
217 | int ret; | ||
218 | |||
219 | ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev); | ||
220 | |||
221 | if (ret < 0) { | ||
222 | wl1271_error("could not get firmware: %d", ret); | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | if (fw->size % 4) { | ||
227 | wl1271_error("firmware size is not multiple of 32 bits: %zu", | ||
228 | fw->size); | ||
229 | ret = -EILSEQ; | ||
230 | goto out; | ||
231 | } | ||
232 | |||
233 | wl->fw_len = fw->size; | ||
234 | wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); | ||
235 | |||
236 | if (!wl->fw) { | ||
237 | wl1271_error("could not allocate memory for the firmware"); | ||
238 | ret = -ENOMEM; | ||
239 | goto out; | ||
240 | } | ||
241 | |||
242 | memcpy(wl->fw, fw->data, wl->fw_len); | ||
243 | |||
244 | ret = 0; | ||
245 | |||
246 | out: | ||
247 | release_firmware(fw); | ||
248 | |||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | static int wl1271_fetch_nvs(struct wl1271 *wl) | ||
253 | { | ||
254 | const struct firmware *fw; | ||
255 | int ret; | ||
256 | |||
257 | ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev); | ||
258 | |||
259 | if (ret < 0) { | ||
260 | wl1271_error("could not get nvs file: %d", ret); | ||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | if (fw->size % 4) { | ||
265 | wl1271_error("nvs size is not multiple of 32 bits: %zu", | ||
266 | fw->size); | ||
267 | ret = -EILSEQ; | ||
268 | goto out; | ||
269 | } | ||
270 | |||
271 | wl->nvs_len = fw->size; | ||
272 | wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); | ||
273 | |||
274 | if (!wl->nvs) { | ||
275 | wl1271_error("could not allocate memory for the nvs file"); | ||
276 | ret = -ENOMEM; | ||
277 | goto out; | ||
278 | } | ||
279 | |||
280 | memcpy(wl->nvs, fw->data, wl->nvs_len); | ||
281 | |||
282 | ret = 0; | ||
283 | |||
284 | out: | ||
285 | release_firmware(fw); | ||
286 | |||
287 | return ret; | ||
288 | } | ||
289 | |||
290 | static void wl1271_fw_wakeup(struct wl1271 *wl) | ||
291 | { | ||
292 | u32 elp_reg; | ||
293 | |||
294 | elp_reg = ELPCTRL_WAKE_UP; | ||
295 | wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); | ||
296 | } | ||
297 | |||
298 | static int wl1271_setup(struct wl1271 *wl) | ||
299 | { | ||
300 | wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL); | ||
301 | if (!wl->fw_status) | ||
302 | return -ENOMEM; | ||
303 | |||
304 | wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL); | ||
305 | if (!wl->tx_res_if) { | ||
306 | kfree(wl->fw_status); | ||
307 | return -ENOMEM; | ||
308 | } | ||
309 | |||
310 | INIT_WORK(&wl->irq_work, wl1271_irq_work); | ||
311 | INIT_WORK(&wl->tx_work, wl1271_tx_work); | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int wl1271_chip_wakeup(struct wl1271 *wl) | ||
316 | { | ||
317 | int ret = 0; | ||
318 | |||
319 | wl1271_power_on(wl); | ||
320 | msleep(WL1271_POWER_ON_SLEEP); | ||
321 | wl1271_spi_reset(wl); | ||
322 | wl1271_spi_init(wl); | ||
323 | |||
324 | /* We don't need a real memory partition here, because we only want | ||
325 | * to use the registers at this point. */ | ||
326 | wl1271_set_partition(wl, | ||
327 | 0x00000000, | ||
328 | 0x00000000, | ||
329 | REGISTERS_BASE, | ||
330 | REGISTERS_DOWN_SIZE); | ||
331 | |||
332 | /* ELP module wake up */ | ||
333 | wl1271_fw_wakeup(wl); | ||
334 | |||
335 | /* whal_FwCtrl_BootSm() */ | ||
336 | |||
337 | /* 0. read chip id from CHIP_ID */ | ||
338 | wl->chip.id = wl1271_reg_read32(wl, CHIP_ID_B); | ||
339 | |||
340 | /* 1. check if chip id is valid */ | ||
341 | |||
342 | switch (wl->chip.id) { | ||
343 | case CHIP_ID_1271_PG10: | ||
344 | wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", | ||
345 | wl->chip.id); | ||
346 | |||
347 | ret = wl1271_setup(wl); | ||
348 | if (ret < 0) | ||
349 | goto out; | ||
350 | break; | ||
351 | case CHIP_ID_1271_PG20: | ||
352 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", | ||
353 | wl->chip.id); | ||
354 | |||
355 | ret = wl1271_setup(wl); | ||
356 | if (ret < 0) | ||
357 | goto out; | ||
358 | break; | ||
359 | default: | ||
360 | wl1271_error("unsupported chip id: 0x%x", wl->chip.id); | ||
361 | ret = -ENODEV; | ||
362 | goto out; | ||
363 | } | ||
364 | |||
365 | if (wl->fw == NULL) { | ||
366 | ret = wl1271_fetch_firmware(wl); | ||
367 | if (ret < 0) | ||
368 | goto out; | ||
369 | } | ||
370 | |||
371 | /* No NVS from netlink, try to get it from the filesystem */ | ||
372 | if (wl->nvs == NULL) { | ||
373 | ret = wl1271_fetch_nvs(wl); | ||
374 | if (ret < 0) | ||
375 | goto out; | ||
376 | } | ||
377 | |||
378 | out: | ||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | static void wl1271_filter_work(struct work_struct *work) | ||
383 | { | ||
384 | struct wl1271 *wl = | ||
385 | container_of(work, struct wl1271, filter_work); | ||
386 | int ret; | ||
387 | |||
388 | mutex_lock(&wl->mutex); | ||
389 | |||
390 | if (wl->state == WL1271_STATE_OFF) | ||
391 | goto out; | ||
392 | |||
393 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
394 | if (ret < 0) | ||
395 | goto out; | ||
396 | |||
397 | /* FIXME: replace the magic numbers with proper definitions */ | ||
398 | ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); | ||
399 | if (ret < 0) | ||
400 | goto out_sleep; | ||
401 | |||
402 | out_sleep: | ||
403 | wl1271_ps_elp_sleep(wl); | ||
404 | |||
405 | out: | ||
406 | mutex_unlock(&wl->mutex); | ||
407 | } | ||
408 | |||
409 | int wl1271_plt_start(struct wl1271 *wl) | ||
410 | { | ||
411 | int ret; | ||
412 | |||
413 | mutex_lock(&wl->mutex); | ||
414 | |||
415 | wl1271_notice("power up"); | ||
416 | |||
417 | if (wl->state != WL1271_STATE_OFF) { | ||
418 | wl1271_error("cannot go into PLT state because not " | ||
419 | "in off state: %d", wl->state); | ||
420 | ret = -EBUSY; | ||
421 | goto out; | ||
422 | } | ||
423 | |||
424 | wl->state = WL1271_STATE_PLT; | ||
425 | |||
426 | ret = wl1271_chip_wakeup(wl); | ||
427 | if (ret < 0) | ||
428 | goto out; | ||
429 | |||
430 | ret = wl1271_boot(wl); | ||
431 | if (ret < 0) | ||
432 | goto out; | ||
433 | |||
434 | wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); | ||
435 | |||
436 | ret = wl1271_plt_init(wl); | ||
437 | if (ret < 0) | ||
438 | goto out; | ||
439 | |||
440 | out: | ||
441 | mutex_unlock(&wl->mutex); | ||
442 | |||
443 | return ret; | ||
444 | } | ||
445 | |||
446 | int wl1271_plt_stop(struct wl1271 *wl) | ||
447 | { | ||
448 | int ret = 0; | ||
449 | |||
450 | mutex_lock(&wl->mutex); | ||
451 | |||
452 | wl1271_notice("power down"); | ||
453 | |||
454 | if (wl->state != WL1271_STATE_PLT) { | ||
455 | wl1271_error("cannot power down because not in PLT " | ||
456 | "state: %d", wl->state); | ||
457 | ret = -EBUSY; | ||
458 | goto out; | ||
459 | } | ||
460 | |||
461 | wl1271_disable_interrupts(wl); | ||
462 | wl1271_power_off(wl); | ||
463 | |||
464 | wl->state = WL1271_STATE_OFF; | ||
465 | |||
466 | out: | ||
467 | mutex_unlock(&wl->mutex); | ||
468 | |||
469 | return ret; | ||
470 | } | ||
471 | |||
472 | |||
473 | static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
474 | { | ||
475 | struct wl1271 *wl = hw->priv; | ||
476 | |||
477 | skb_queue_tail(&wl->tx_queue, skb); | ||
478 | |||
479 | /* | ||
480 | * The chip specific setup must run before the first TX packet - | ||
481 | * before that, the tx_work will not be initialized! | ||
482 | */ | ||
483 | |||
484 | schedule_work(&wl->tx_work); | ||
485 | |||
486 | /* | ||
487 | * The workqueue is slow to process the tx_queue and we need stop | ||
488 | * the queue here, otherwise the queue will get too long. | ||
489 | */ | ||
490 | if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) { | ||
491 | ieee80211_stop_queues(wl->hw); | ||
492 | |||
493 | /* | ||
494 | * FIXME: this is racy, the variable is not properly | ||
495 | * protected. Maybe fix this by removing the stupid | ||
496 | * variable altogether and checking the real queue state? | ||
497 | */ | ||
498 | wl->tx_queue_stopped = true; | ||
499 | } | ||
500 | |||
501 | return NETDEV_TX_OK; | ||
502 | } | ||
503 | |||
504 | static int wl1271_op_start(struct ieee80211_hw *hw) | ||
505 | { | ||
506 | struct wl1271 *wl = hw->priv; | ||
507 | int ret = 0; | ||
508 | |||
509 | wl1271_debug(DEBUG_MAC80211, "mac80211 start"); | ||
510 | |||
511 | mutex_lock(&wl->mutex); | ||
512 | |||
513 | if (wl->state != WL1271_STATE_OFF) { | ||
514 | wl1271_error("cannot start because not in off state: %d", | ||
515 | wl->state); | ||
516 | ret = -EBUSY; | ||
517 | goto out; | ||
518 | } | ||
519 | |||
520 | ret = wl1271_chip_wakeup(wl); | ||
521 | if (ret < 0) | ||
522 | goto out; | ||
523 | |||
524 | ret = wl1271_boot(wl); | ||
525 | if (ret < 0) | ||
526 | goto out; | ||
527 | |||
528 | ret = wl1271_hw_init(wl); | ||
529 | if (ret < 0) | ||
530 | goto out; | ||
531 | |||
532 | wl->state = WL1271_STATE_ON; | ||
533 | |||
534 | wl1271_info("firmware booted (%s)", wl->chip.fw_ver); | ||
535 | |||
536 | out: | ||
537 | if (ret < 0) | ||
538 | wl1271_power_off(wl); | ||
539 | |||
540 | mutex_unlock(&wl->mutex); | ||
541 | |||
542 | return ret; | ||
543 | } | ||
544 | |||
545 | static void wl1271_op_stop(struct ieee80211_hw *hw) | ||
546 | { | ||
547 | struct wl1271 *wl = hw->priv; | ||
548 | int i; | ||
549 | |||
550 | wl1271_info("down"); | ||
551 | |||
552 | wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
553 | |||
554 | mutex_lock(&wl->mutex); | ||
555 | |||
556 | WARN_ON(wl->state != WL1271_STATE_ON); | ||
557 | |||
558 | if (wl->scanning) { | ||
559 | mutex_unlock(&wl->mutex); | ||
560 | ieee80211_scan_completed(wl->hw, true); | ||
561 | mutex_lock(&wl->mutex); | ||
562 | wl->scanning = false; | ||
563 | } | ||
564 | |||
565 | wl->state = WL1271_STATE_OFF; | ||
566 | |||
567 | wl1271_disable_interrupts(wl); | ||
568 | |||
569 | mutex_unlock(&wl->mutex); | ||
570 | |||
571 | cancel_work_sync(&wl->irq_work); | ||
572 | cancel_work_sync(&wl->tx_work); | ||
573 | cancel_work_sync(&wl->filter_work); | ||
574 | |||
575 | mutex_lock(&wl->mutex); | ||
576 | |||
577 | /* let's notify MAC80211 about the remaining pending TX frames */ | ||
578 | wl1271_tx_flush(wl); | ||
579 | wl1271_power_off(wl); | ||
580 | |||
581 | memset(wl->bssid, 0, ETH_ALEN); | ||
582 | memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1); | ||
583 | wl->ssid_len = 0; | ||
584 | wl->listen_int = 1; | ||
585 | wl->bss_type = MAX_BSS_TYPE; | ||
586 | |||
587 | wl->rx_counter = 0; | ||
588 | wl->elp = false; | ||
589 | wl->psm = 0; | ||
590 | wl->tx_queue_stopped = false; | ||
591 | wl->power_level = WL1271_DEFAULT_POWER_LEVEL; | ||
592 | wl->tx_blocks_available = 0; | ||
593 | wl->tx_results_count = 0; | ||
594 | wl->tx_packets_count = 0; | ||
595 | wl->time_offset = 0; | ||
596 | wl->session_counter = 0; | ||
597 | for (i = 0; i < NUM_TX_QUEUES; i++) | ||
598 | wl->tx_blocks_freed[i] = 0; | ||
599 | |||
600 | wl1271_debugfs_reset(wl); | ||
601 | mutex_unlock(&wl->mutex); | ||
602 | } | ||
603 | |||
604 | static int wl1271_op_add_interface(struct ieee80211_hw *hw, | ||
605 | struct ieee80211_if_init_conf *conf) | ||
606 | { | ||
607 | struct wl1271 *wl = hw->priv; | ||
608 | DECLARE_MAC_BUF(mac); | ||
609 | int ret = 0; | ||
610 | |||
611 | wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", | ||
612 | conf->type, print_mac(mac, conf->mac_addr)); | ||
613 | |||
614 | mutex_lock(&wl->mutex); | ||
615 | |||
616 | switch (conf->type) { | ||
617 | case NL80211_IFTYPE_STATION: | ||
618 | wl->bss_type = BSS_TYPE_STA_BSS; | ||
619 | break; | ||
620 | case NL80211_IFTYPE_ADHOC: | ||
621 | wl->bss_type = BSS_TYPE_IBSS; | ||
622 | break; | ||
623 | default: | ||
624 | ret = -EOPNOTSUPP; | ||
625 | goto out; | ||
626 | } | ||
627 | |||
628 | /* FIXME: what if conf->mac_addr changes? */ | ||
629 | |||
630 | out: | ||
631 | mutex_unlock(&wl->mutex); | ||
632 | return ret; | ||
633 | } | ||
634 | |||
635 | static void wl1271_op_remove_interface(struct ieee80211_hw *hw, | ||
636 | struct ieee80211_if_init_conf *conf) | ||
637 | { | ||
638 | wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); | ||
639 | } | ||
640 | |||
641 | #if 0 | ||
642 | static int wl1271_op_config_interface(struct ieee80211_hw *hw, | ||
643 | struct ieee80211_vif *vif, | ||
644 | struct ieee80211_if_conf *conf) | ||
645 | { | ||
646 | struct wl1271 *wl = hw->priv; | ||
647 | struct sk_buff *beacon; | ||
648 | DECLARE_MAC_BUF(mac); | ||
649 | int ret; | ||
650 | |||
651 | wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %s", | ||
652 | print_mac(mac, conf->bssid)); | ||
653 | wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid, | ||
654 | conf->ssid_len); | ||
655 | |||
656 | mutex_lock(&wl->mutex); | ||
657 | |||
658 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
659 | if (ret < 0) | ||
660 | goto out; | ||
661 | |||
662 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); | ||
663 | |||
664 | ret = wl1271_cmd_build_null_data(wl); | ||
665 | if (ret < 0) | ||
666 | goto out_sleep; | ||
667 | |||
668 | wl->ssid_len = conf->ssid_len; | ||
669 | if (wl->ssid_len) | ||
670 | memcpy(wl->ssid, conf->ssid, wl->ssid_len); | ||
671 | |||
672 | if (wl->bss_type != BSS_TYPE_IBSS) { | ||
673 | /* FIXME: replace the magic numbers with proper definitions */ | ||
674 | ret = wl1271_cmd_join(wl, wl->bss_type, 5, 100, 1); | ||
675 | if (ret < 0) | ||
676 | goto out_sleep; | ||
677 | } | ||
678 | |||
679 | if (conf->changed & IEEE80211_IFCC_BEACON) { | ||
680 | beacon = ieee80211_beacon_get(hw, vif); | ||
681 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, | ||
682 | beacon->data, beacon->len); | ||
683 | |||
684 | if (ret < 0) { | ||
685 | dev_kfree_skb(beacon); | ||
686 | goto out_sleep; | ||
687 | } | ||
688 | |||
689 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, | ||
690 | beacon->data, beacon->len); | ||
691 | |||
692 | dev_kfree_skb(beacon); | ||
693 | |||
694 | if (ret < 0) | ||
695 | goto out_sleep; | ||
696 | |||
697 | /* FIXME: replace the magic numbers with proper definitions */ | ||
698 | ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); | ||
699 | |||
700 | if (ret < 0) | ||
701 | goto out_sleep; | ||
702 | } | ||
703 | |||
704 | out_sleep: | ||
705 | wl1271_ps_elp_sleep(wl); | ||
706 | |||
707 | out: | ||
708 | mutex_unlock(&wl->mutex); | ||
709 | |||
710 | return ret; | ||
711 | } | ||
712 | #endif | ||
713 | |||
714 | static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | ||
715 | { | ||
716 | struct wl1271 *wl = hw->priv; | ||
717 | struct ieee80211_conf *conf = &hw->conf; | ||
718 | int channel, ret = 0; | ||
719 | |||
720 | channel = ieee80211_frequency_to_channel(conf->channel->center_freq); | ||
721 | |||
722 | wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", | ||
723 | channel, | ||
724 | conf->flags & IEEE80211_CONF_PS ? "on" : "off", | ||
725 | conf->power_level); | ||
726 | |||
727 | mutex_lock(&wl->mutex); | ||
728 | |||
729 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
730 | if (ret < 0) | ||
731 | goto out; | ||
732 | |||
733 | if (channel != wl->channel) { | ||
734 | u8 old_channel = wl->channel; | ||
735 | wl->channel = channel; | ||
736 | |||
737 | /* FIXME: use beacon interval provided by mac80211 */ | ||
738 | ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); | ||
739 | if (ret < 0) { | ||
740 | wl->channel = old_channel; | ||
741 | goto out_sleep; | ||
742 | } | ||
743 | } | ||
744 | |||
745 | ret = wl1271_cmd_build_null_data(wl); | ||
746 | if (ret < 0) | ||
747 | goto out_sleep; | ||
748 | |||
749 | if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { | ||
750 | wl1271_info("psm enabled"); | ||
751 | |||
752 | wl->psm_requested = true; | ||
753 | |||
754 | /* | ||
755 | * We enter PSM only if we're already associated. | ||
756 | * If we're not, we'll enter it when joining an SSID, | ||
757 | * through the bss_info_changed() hook. | ||
758 | */ | ||
759 | ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); | ||
760 | } else if (!(conf->flags & IEEE80211_CONF_PS) && | ||
761 | wl->psm_requested) { | ||
762 | wl1271_info("psm disabled"); | ||
763 | |||
764 | wl->psm_requested = false; | ||
765 | |||
766 | if (wl->psm) | ||
767 | ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
768 | } | ||
769 | |||
770 | if (conf->power_level != wl->power_level) { | ||
771 | ret = wl1271_acx_tx_power(wl, conf->power_level); | ||
772 | if (ret < 0) | ||
773 | goto out; | ||
774 | |||
775 | wl->power_level = conf->power_level; | ||
776 | } | ||
777 | |||
778 | out_sleep: | ||
779 | wl1271_ps_elp_sleep(wl); | ||
780 | |||
781 | out: | ||
782 | mutex_unlock(&wl->mutex); | ||
783 | |||
784 | return ret; | ||
785 | } | ||
786 | |||
787 | #define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ | ||
788 | FIF_ALLMULTI | \ | ||
789 | FIF_FCSFAIL | \ | ||
790 | FIF_BCN_PRBRESP_PROMISC | \ | ||
791 | FIF_CONTROL | \ | ||
792 | FIF_OTHER_BSS) | ||
793 | |||
794 | static void wl1271_op_configure_filter(struct ieee80211_hw *hw, | ||
795 | unsigned int changed, | ||
796 | unsigned int *total, | ||
797 | int mc_count, | ||
798 | struct dev_addr_list *mc_list) | ||
799 | { | ||
800 | struct wl1271 *wl = hw->priv; | ||
801 | |||
802 | wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter"); | ||
803 | |||
804 | *total &= WL1271_SUPPORTED_FILTERS; | ||
805 | changed &= WL1271_SUPPORTED_FILTERS; | ||
806 | |||
807 | if (changed == 0) | ||
808 | return; | ||
809 | |||
810 | /* FIXME: wl->rx_config and wl->rx_filter are not protected */ | ||
811 | wl->rx_config = WL1271_DEFAULT_RX_CONFIG; | ||
812 | wl->rx_filter = WL1271_DEFAULT_RX_FILTER; | ||
813 | |||
814 | /* | ||
815 | * FIXME: workqueues need to be properly cancelled on stop(), for | ||
816 | * now let's just disable changing the filter settings. They will | ||
817 | * be updated any on config(). | ||
818 | */ | ||
819 | /* schedule_work(&wl->filter_work); */ | ||
820 | } | ||
821 | |||
822 | static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
823 | struct ieee80211_vif *vif, | ||
824 | struct ieee80211_sta *sta, | ||
825 | struct ieee80211_key_conf *key_conf) | ||
826 | { | ||
827 | struct wl1271 *wl = hw->priv; | ||
828 | const u8 *addr; | ||
829 | int ret; | ||
830 | u8 key_type; | ||
831 | |||
832 | static const u8 bcast_addr[ETH_ALEN] = | ||
833 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
834 | |||
835 | wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); | ||
836 | |||
837 | addr = sta ? sta->addr : bcast_addr; | ||
838 | |||
839 | wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); | ||
840 | wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); | ||
841 | wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", | ||
842 | key_conf->alg, key_conf->keyidx, | ||
843 | key_conf->keylen, key_conf->flags); | ||
844 | wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); | ||
845 | |||
846 | if (is_zero_ether_addr(addr)) { | ||
847 | /* We dont support TX only encryption */ | ||
848 | ret = -EOPNOTSUPP; | ||
849 | goto out; | ||
850 | } | ||
851 | |||
852 | mutex_lock(&wl->mutex); | ||
853 | |||
854 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
855 | if (ret < 0) | ||
856 | goto out_unlock; | ||
857 | |||
858 | switch (key_conf->alg) { | ||
859 | case ALG_WEP: | ||
860 | key_type = KEY_WEP; | ||
861 | |||
862 | key_conf->hw_key_idx = key_conf->keyidx; | ||
863 | break; | ||
864 | case ALG_TKIP: | ||
865 | key_type = KEY_TKIP; | ||
866 | |||
867 | key_conf->hw_key_idx = key_conf->keyidx; | ||
868 | break; | ||
869 | case ALG_CCMP: | ||
870 | key_type = KEY_AES; | ||
871 | |||
872 | key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
873 | break; | ||
874 | default: | ||
875 | wl1271_error("Unknown key algo 0x%x", key_conf->alg); | ||
876 | |||
877 | ret = -EOPNOTSUPP; | ||
878 | goto out_sleep; | ||
879 | } | ||
880 | |||
881 | switch (cmd) { | ||
882 | case SET_KEY: | ||
883 | ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE, | ||
884 | key_conf->keyidx, key_type, | ||
885 | key_conf->keylen, key_conf->key, | ||
886 | addr); | ||
887 | if (ret < 0) { | ||
888 | wl1271_error("Could not add or replace key"); | ||
889 | goto out_sleep; | ||
890 | } | ||
891 | break; | ||
892 | |||
893 | case DISABLE_KEY: | ||
894 | ret = wl1271_cmd_set_key(wl, KEY_REMOVE, | ||
895 | key_conf->keyidx, key_type, | ||
896 | key_conf->keylen, key_conf->key, | ||
897 | addr); | ||
898 | if (ret < 0) { | ||
899 | wl1271_error("Could not remove key"); | ||
900 | goto out_sleep; | ||
901 | } | ||
902 | break; | ||
903 | |||
904 | default: | ||
905 | wl1271_error("Unsupported key cmd 0x%x", cmd); | ||
906 | ret = -EOPNOTSUPP; | ||
907 | goto out_sleep; | ||
908 | |||
909 | break; | ||
910 | } | ||
911 | |||
912 | out_sleep: | ||
913 | wl1271_ps_elp_sleep(wl); | ||
914 | |||
915 | out_unlock: | ||
916 | mutex_unlock(&wl->mutex); | ||
917 | |||
918 | out: | ||
919 | return ret; | ||
920 | } | ||
921 | |||
922 | static int wl1271_op_hw_scan(struct ieee80211_hw *hw, | ||
923 | struct cfg80211_scan_request *req) | ||
924 | { | ||
925 | struct wl1271 *wl = hw->priv; | ||
926 | int ret; | ||
927 | u8 *ssid = NULL; | ||
928 | size_t ssid_len = 0; | ||
929 | |||
930 | wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan"); | ||
931 | |||
932 | if (req->n_ssids) { | ||
933 | ssid = req->ssids[0].ssid; | ||
934 | ssid_len = req->ssids[0].ssid_len; | ||
935 | } | ||
936 | |||
937 | mutex_lock(&wl->mutex); | ||
938 | |||
939 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
940 | if (ret < 0) | ||
941 | goto out; | ||
942 | |||
943 | ret = wl1271_cmd_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); | ||
944 | |||
945 | wl1271_ps_elp_sleep(wl); | ||
946 | |||
947 | out: | ||
948 | mutex_unlock(&wl->mutex); | ||
949 | |||
950 | return ret; | ||
951 | } | ||
952 | |||
953 | static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | ||
954 | { | ||
955 | struct wl1271 *wl = hw->priv; | ||
956 | int ret; | ||
957 | |||
958 | mutex_lock(&wl->mutex); | ||
959 | |||
960 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
961 | if (ret < 0) | ||
962 | goto out; | ||
963 | |||
964 | ret = wl1271_acx_rts_threshold(wl, (u16) value); | ||
965 | if (ret < 0) | ||
966 | wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret); | ||
967 | |||
968 | wl1271_ps_elp_sleep(wl); | ||
969 | |||
970 | out: | ||
971 | mutex_unlock(&wl->mutex); | ||
972 | |||
973 | return ret; | ||
974 | } | ||
975 | |||
976 | static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | ||
977 | struct ieee80211_vif *vif, | ||
978 | struct ieee80211_bss_conf *bss_conf, | ||
979 | u32 changed) | ||
980 | { | ||
981 | enum wl1271_cmd_ps_mode mode; | ||
982 | struct wl1271 *wl = hw->priv; | ||
983 | int ret; | ||
984 | |||
985 | wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed"); | ||
986 | |||
987 | mutex_lock(&wl->mutex); | ||
988 | |||
989 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
990 | if (ret < 0) | ||
991 | goto out; | ||
992 | |||
993 | if (changed & BSS_CHANGED_ASSOC) { | ||
994 | if (bss_conf->assoc) { | ||
995 | wl->aid = bss_conf->aid; | ||
996 | |||
997 | ret = wl1271_cmd_build_ps_poll(wl, wl->aid); | ||
998 | if (ret < 0) | ||
999 | goto out_sleep; | ||
1000 | |||
1001 | ret = wl1271_acx_aid(wl, wl->aid); | ||
1002 | if (ret < 0) | ||
1003 | goto out_sleep; | ||
1004 | |||
1005 | /* If we want to go in PSM but we're not there yet */ | ||
1006 | if (wl->psm_requested && !wl->psm) { | ||
1007 | mode = STATION_POWER_SAVE_MODE; | ||
1008 | ret = wl1271_ps_set_mode(wl, mode); | ||
1009 | if (ret < 0) | ||
1010 | goto out_sleep; | ||
1011 | } | ||
1012 | } | ||
1013 | } | ||
1014 | if (changed & BSS_CHANGED_ERP_SLOT) { | ||
1015 | if (bss_conf->use_short_slot) | ||
1016 | ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT); | ||
1017 | else | ||
1018 | ret = wl1271_acx_slot(wl, SLOT_TIME_LONG); | ||
1019 | if (ret < 0) { | ||
1020 | wl1271_warning("Set slot time failed %d", ret); | ||
1021 | goto out_sleep; | ||
1022 | } | ||
1023 | } | ||
1024 | |||
1025 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | ||
1026 | if (bss_conf->use_short_preamble) | ||
1027 | wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); | ||
1028 | else | ||
1029 | wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG); | ||
1030 | } | ||
1031 | |||
1032 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | ||
1033 | if (bss_conf->use_cts_prot) | ||
1034 | ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE); | ||
1035 | else | ||
1036 | ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE); | ||
1037 | if (ret < 0) { | ||
1038 | wl1271_warning("Set ctsprotect failed %d", ret); | ||
1039 | goto out_sleep; | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1043 | out_sleep: | ||
1044 | wl1271_ps_elp_sleep(wl); | ||
1045 | |||
1046 | out: | ||
1047 | mutex_unlock(&wl->mutex); | ||
1048 | } | ||
1049 | |||
1050 | |||
1051 | /* can't be const, mac80211 writes to this */ | ||
1052 | static struct ieee80211_rate wl1271_rates[] = { | ||
1053 | { .bitrate = 10, | ||
1054 | .hw_value = 0x1, | ||
1055 | .hw_value_short = 0x1, }, | ||
1056 | { .bitrate = 20, | ||
1057 | .hw_value = 0x2, | ||
1058 | .hw_value_short = 0x2, | ||
1059 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1060 | { .bitrate = 55, | ||
1061 | .hw_value = 0x4, | ||
1062 | .hw_value_short = 0x4, | ||
1063 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1064 | { .bitrate = 110, | ||
1065 | .hw_value = 0x20, | ||
1066 | .hw_value_short = 0x20, | ||
1067 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1068 | { .bitrate = 60, | ||
1069 | .hw_value = 0x8, | ||
1070 | .hw_value_short = 0x8, }, | ||
1071 | { .bitrate = 90, | ||
1072 | .hw_value = 0x10, | ||
1073 | .hw_value_short = 0x10, }, | ||
1074 | { .bitrate = 120, | ||
1075 | .hw_value = 0x40, | ||
1076 | .hw_value_short = 0x40, }, | ||
1077 | { .bitrate = 180, | ||
1078 | .hw_value = 0x80, | ||
1079 | .hw_value_short = 0x80, }, | ||
1080 | { .bitrate = 240, | ||
1081 | .hw_value = 0x200, | ||
1082 | .hw_value_short = 0x200, }, | ||
1083 | { .bitrate = 360, | ||
1084 | .hw_value = 0x400, | ||
1085 | .hw_value_short = 0x400, }, | ||
1086 | { .bitrate = 480, | ||
1087 | .hw_value = 0x800, | ||
1088 | .hw_value_short = 0x800, }, | ||
1089 | { .bitrate = 540, | ||
1090 | .hw_value = 0x1000, | ||
1091 | .hw_value_short = 0x1000, }, | ||
1092 | }; | ||
1093 | |||
1094 | /* can't be const, mac80211 writes to this */ | ||
1095 | static struct ieee80211_channel wl1271_channels[] = { | ||
1096 | { .hw_value = 1, .center_freq = 2412}, | ||
1097 | { .hw_value = 2, .center_freq = 2417}, | ||
1098 | { .hw_value = 3, .center_freq = 2422}, | ||
1099 | { .hw_value = 4, .center_freq = 2427}, | ||
1100 | { .hw_value = 5, .center_freq = 2432}, | ||
1101 | { .hw_value = 6, .center_freq = 2437}, | ||
1102 | { .hw_value = 7, .center_freq = 2442}, | ||
1103 | { .hw_value = 8, .center_freq = 2447}, | ||
1104 | { .hw_value = 9, .center_freq = 2452}, | ||
1105 | { .hw_value = 10, .center_freq = 2457}, | ||
1106 | { .hw_value = 11, .center_freq = 2462}, | ||
1107 | { .hw_value = 12, .center_freq = 2467}, | ||
1108 | { .hw_value = 13, .center_freq = 2472}, | ||
1109 | }; | ||
1110 | |||
1111 | /* can't be const, mac80211 writes to this */ | ||
1112 | static struct ieee80211_supported_band wl1271_band_2ghz = { | ||
1113 | .channels = wl1271_channels, | ||
1114 | .n_channels = ARRAY_SIZE(wl1271_channels), | ||
1115 | .bitrates = wl1271_rates, | ||
1116 | .n_bitrates = ARRAY_SIZE(wl1271_rates), | ||
1117 | }; | ||
1118 | |||
1119 | static const struct ieee80211_ops wl1271_ops = { | ||
1120 | .start = wl1271_op_start, | ||
1121 | .stop = wl1271_op_stop, | ||
1122 | .add_interface = wl1271_op_add_interface, | ||
1123 | .remove_interface = wl1271_op_remove_interface, | ||
1124 | .config = wl1271_op_config, | ||
1125 | /* .config_interface = wl1271_op_config_interface, */ | ||
1126 | .configure_filter = wl1271_op_configure_filter, | ||
1127 | .tx = wl1271_op_tx, | ||
1128 | .set_key = wl1271_op_set_key, | ||
1129 | .hw_scan = wl1271_op_hw_scan, | ||
1130 | .bss_info_changed = wl1271_op_bss_info_changed, | ||
1131 | .set_rts_threshold = wl1271_op_set_rts_threshold, | ||
1132 | }; | ||
1133 | |||
1134 | static int wl1271_register_hw(struct wl1271 *wl) | ||
1135 | { | ||
1136 | int ret; | ||
1137 | |||
1138 | if (wl->mac80211_registered) | ||
1139 | return 0; | ||
1140 | |||
1141 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
1142 | |||
1143 | ret = ieee80211_register_hw(wl->hw); | ||
1144 | if (ret < 0) { | ||
1145 | wl1271_error("unable to register mac80211 hw: %d", ret); | ||
1146 | return ret; | ||
1147 | } | ||
1148 | |||
1149 | wl->mac80211_registered = true; | ||
1150 | |||
1151 | wl1271_notice("loaded"); | ||
1152 | |||
1153 | return 0; | ||
1154 | } | ||
1155 | |||
1156 | static int wl1271_init_ieee80211(struct wl1271 *wl) | ||
1157 | { | ||
1158 | /* | ||
1159 | * The tx descriptor buffer and the TKIP space. | ||
1160 | * | ||
1161 | * FIXME: add correct 1271 descriptor size | ||
1162 | */ | ||
1163 | wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE; | ||
1164 | |||
1165 | /* unit us */ | ||
1166 | /* FIXME: find a proper value */ | ||
1167 | wl->hw->channel_change_time = 10000; | ||
1168 | |||
1169 | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | | ||
1170 | IEEE80211_HW_NOISE_DBM; | ||
1171 | |||
1172 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | ||
1173 | wl->hw->wiphy->max_scan_ssids = 1; | ||
1174 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; | ||
1175 | |||
1176 | SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); | ||
1177 | |||
1178 | return 0; | ||
1179 | } | ||
1180 | |||
1181 | static void wl1271_device_release(struct device *dev) | ||
1182 | { | ||
1183 | |||
1184 | } | ||
1185 | |||
1186 | static struct platform_device wl1271_device = { | ||
1187 | .name = "wl1271", | ||
1188 | .id = -1, | ||
1189 | |||
1190 | /* device model insists to have a release function */ | ||
1191 | .dev = { | ||
1192 | .release = wl1271_device_release, | ||
1193 | }, | ||
1194 | }; | ||
1195 | |||
1196 | #define WL1271_DEFAULT_CHANNEL 0 | ||
1197 | static int __devinit wl1271_probe(struct spi_device *spi) | ||
1198 | { | ||
1199 | struct wl12xx_platform_data *pdata; | ||
1200 | struct ieee80211_hw *hw; | ||
1201 | struct wl1271 *wl; | ||
1202 | int ret, i; | ||
1203 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
1204 | |||
1205 | pdata = spi->dev.platform_data; | ||
1206 | if (!pdata) { | ||
1207 | wl1271_error("no platform data"); | ||
1208 | return -ENODEV; | ||
1209 | } | ||
1210 | |||
1211 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); | ||
1212 | if (!hw) { | ||
1213 | wl1271_error("could not alloc ieee80211_hw"); | ||
1214 | return -ENOMEM; | ||
1215 | } | ||
1216 | |||
1217 | wl = hw->priv; | ||
1218 | memset(wl, 0, sizeof(*wl)); | ||
1219 | |||
1220 | wl->hw = hw; | ||
1221 | dev_set_drvdata(&spi->dev, wl); | ||
1222 | wl->spi = spi; | ||
1223 | |||
1224 | skb_queue_head_init(&wl->tx_queue); | ||
1225 | |||
1226 | INIT_WORK(&wl->filter_work, wl1271_filter_work); | ||
1227 | wl->channel = WL1271_DEFAULT_CHANNEL; | ||
1228 | wl->scanning = false; | ||
1229 | wl->default_key = 0; | ||
1230 | wl->listen_int = 1; | ||
1231 | wl->rx_counter = 0; | ||
1232 | wl->rx_config = WL1271_DEFAULT_RX_CONFIG; | ||
1233 | wl->rx_filter = WL1271_DEFAULT_RX_FILTER; | ||
1234 | wl->elp = false; | ||
1235 | wl->psm = 0; | ||
1236 | wl->psm_requested = false; | ||
1237 | wl->tx_queue_stopped = false; | ||
1238 | wl->power_level = WL1271_DEFAULT_POWER_LEVEL; | ||
1239 | |||
1240 | /* We use the default power on sleep time until we know which chip | ||
1241 | * we're using */ | ||
1242 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
1243 | wl->tx_frames[i] = NULL; | ||
1244 | |||
1245 | spin_lock_init(&wl->wl_lock); | ||
1246 | |||
1247 | /* | ||
1248 | * In case our MAC address is not correctly set, | ||
1249 | * we use a random but Nokia MAC. | ||
1250 | */ | ||
1251 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
1252 | get_random_bytes(wl->mac_addr + 3, 3); | ||
1253 | |||
1254 | wl->state = WL1271_STATE_OFF; | ||
1255 | mutex_init(&wl->mutex); | ||
1256 | |||
1257 | wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); | ||
1258 | if (!wl->rx_descriptor) { | ||
1259 | wl1271_error("could not allocate memory for rx descriptor"); | ||
1260 | ret = -ENOMEM; | ||
1261 | goto out_free; | ||
1262 | } | ||
1263 | |||
1264 | /* This is the only SPI value that we need to set here, the rest | ||
1265 | * comes from the board-peripherals file */ | ||
1266 | spi->bits_per_word = 32; | ||
1267 | |||
1268 | ret = spi_setup(spi); | ||
1269 | if (ret < 0) { | ||
1270 | wl1271_error("spi_setup failed"); | ||
1271 | goto out_free; | ||
1272 | } | ||
1273 | |||
1274 | wl->set_power = pdata->set_power; | ||
1275 | if (!wl->set_power) { | ||
1276 | wl1271_error("set power function missing in platform data"); | ||
1277 | ret = -ENODEV; | ||
1278 | goto out_free; | ||
1279 | } | ||
1280 | |||
1281 | wl->irq = spi->irq; | ||
1282 | if (wl->irq < 0) { | ||
1283 | wl1271_error("irq missing in platform data"); | ||
1284 | ret = -ENODEV; | ||
1285 | goto out_free; | ||
1286 | } | ||
1287 | |||
1288 | ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); | ||
1289 | if (ret < 0) { | ||
1290 | wl1271_error("request_irq() failed: %d", ret); | ||
1291 | goto out_free; | ||
1292 | } | ||
1293 | |||
1294 | set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | ||
1295 | |||
1296 | disable_irq(wl->irq); | ||
1297 | |||
1298 | ret = platform_device_register(&wl1271_device); | ||
1299 | if (ret) { | ||
1300 | wl1271_error("couldn't register platform device"); | ||
1301 | goto out_irq; | ||
1302 | } | ||
1303 | dev_set_drvdata(&wl1271_device.dev, wl); | ||
1304 | |||
1305 | ret = wl1271_init_ieee80211(wl); | ||
1306 | if (ret) | ||
1307 | goto out_platform; | ||
1308 | |||
1309 | ret = wl1271_register_hw(wl); | ||
1310 | if (ret) | ||
1311 | goto out_platform; | ||
1312 | |||
1313 | wl1271_debugfs_init(wl); | ||
1314 | |||
1315 | wl1271_notice("initialized"); | ||
1316 | |||
1317 | return 0; | ||
1318 | |||
1319 | out_platform: | ||
1320 | platform_device_unregister(&wl1271_device); | ||
1321 | |||
1322 | out_irq: | ||
1323 | free_irq(wl->irq, wl); | ||
1324 | |||
1325 | out_free: | ||
1326 | kfree(wl->rx_descriptor); | ||
1327 | wl->rx_descriptor = NULL; | ||
1328 | |||
1329 | ieee80211_free_hw(hw); | ||
1330 | |||
1331 | return ret; | ||
1332 | } | ||
1333 | |||
1334 | static int __devexit wl1271_remove(struct spi_device *spi) | ||
1335 | { | ||
1336 | struct wl1271 *wl = dev_get_drvdata(&spi->dev); | ||
1337 | |||
1338 | ieee80211_unregister_hw(wl->hw); | ||
1339 | |||
1340 | wl1271_debugfs_exit(wl); | ||
1341 | platform_device_unregister(&wl1271_device); | ||
1342 | free_irq(wl->irq, wl); | ||
1343 | kfree(wl->target_mem_map); | ||
1344 | kfree(wl->fw); | ||
1345 | wl->fw = NULL; | ||
1346 | kfree(wl->nvs); | ||
1347 | wl->nvs = NULL; | ||
1348 | |||
1349 | kfree(wl->rx_descriptor); | ||
1350 | wl->rx_descriptor = NULL; | ||
1351 | |||
1352 | kfree(wl->fw_status); | ||
1353 | kfree(wl->tx_res_if); | ||
1354 | |||
1355 | ieee80211_free_hw(wl->hw); | ||
1356 | |||
1357 | return 0; | ||
1358 | } | ||
1359 | |||
1360 | |||
1361 | static struct spi_driver wl1271_spi_driver = { | ||
1362 | .driver = { | ||
1363 | .name = "wl1271", | ||
1364 | .bus = &spi_bus_type, | ||
1365 | .owner = THIS_MODULE, | ||
1366 | }, | ||
1367 | |||
1368 | .probe = wl1271_probe, | ||
1369 | .remove = __devexit_p(wl1271_remove), | ||
1370 | }; | ||
1371 | |||
1372 | static int __init wl1271_init(void) | ||
1373 | { | ||
1374 | int ret; | ||
1375 | |||
1376 | ret = spi_register_driver(&wl1271_spi_driver); | ||
1377 | if (ret < 0) { | ||
1378 | wl1271_error("failed to register spi driver: %d", ret); | ||
1379 | goto out; | ||
1380 | } | ||
1381 | |||
1382 | out: | ||
1383 | return ret; | ||
1384 | } | ||
1385 | |||
1386 | static void __exit wl1271_exit(void) | ||
1387 | { | ||
1388 | spi_unregister_driver(&wl1271_spi_driver); | ||
1389 | |||
1390 | wl1271_notice("unloaded"); | ||
1391 | } | ||
1392 | |||
1393 | module_init(wl1271_init); | ||
1394 | module_exit(wl1271_exit); | ||
1395 | |||
1396 | MODULE_LICENSE("GPL"); | ||
1397 | MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c new file mode 100644 index 000000000000..1dc74b0c7736 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "wl1271_reg.h" | ||
25 | #include "wl1271_ps.h" | ||
26 | #include "wl1271_spi.h" | ||
27 | |||
28 | #define WL1271_WAKEUP_TIMEOUT 500 | ||
29 | |||
30 | /* Routines to toggle sleep mode while in ELP */ | ||
31 | void wl1271_ps_elp_sleep(struct wl1271 *wl) | ||
32 | { | ||
33 | /* | ||
34 | * FIXME: due to a problem in the firmware (causing a firmware | ||
35 | * crash), ELP entry is prevented below. Remove the "true" to | ||
36 | * re-enable ELP entry. | ||
37 | */ | ||
38 | if (true || wl->elp || !wl->psm) | ||
39 | return; | ||
40 | |||
41 | /* | ||
42 | * Go to ELP unless there is work already pending - pending work | ||
43 | * will immediately wakeup the chipset anyway. | ||
44 | */ | ||
45 | if (!work_pending(&wl->irq_work) && !work_pending(&wl->tx_work)) { | ||
46 | wl1271_debug(DEBUG_PSM, "chip to elp"); | ||
47 | wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); | ||
48 | wl->elp = true; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) | ||
53 | { | ||
54 | DECLARE_COMPLETION_ONSTACK(compl); | ||
55 | unsigned long flags; | ||
56 | int ret; | ||
57 | u32 start_time = jiffies; | ||
58 | bool pending = false; | ||
59 | |||
60 | if (!wl->elp) | ||
61 | return 0; | ||
62 | |||
63 | wl1271_debug(DEBUG_PSM, "waking up chip from elp"); | ||
64 | |||
65 | /* | ||
66 | * The spinlock is required here to synchronize both the work and | ||
67 | * the completion variable in one entity. | ||
68 | */ | ||
69 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
70 | if (work_pending(&wl->irq_work) || chip_awake) | ||
71 | pending = true; | ||
72 | else | ||
73 | wl->elp_compl = &compl; | ||
74 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
75 | |||
76 | wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); | ||
77 | |||
78 | if (!pending) { | ||
79 | ret = wait_for_completion_timeout( | ||
80 | &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); | ||
81 | if (ret == 0) { | ||
82 | wl1271_error("ELP wakeup timeout!"); | ||
83 | ret = -ETIMEDOUT; | ||
84 | goto err; | ||
85 | } else if (ret < 0) { | ||
86 | wl1271_error("ELP wakeup completion error."); | ||
87 | goto err; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | wl->elp = false; | ||
92 | |||
93 | wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", | ||
94 | jiffies_to_msecs(jiffies - start_time)); | ||
95 | goto out; | ||
96 | |||
97 | err: | ||
98 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
99 | wl->elp_compl = NULL; | ||
100 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
101 | return ret; | ||
102 | |||
103 | out: | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) | ||
108 | { | ||
109 | int ret; | ||
110 | |||
111 | switch (mode) { | ||
112 | case STATION_POWER_SAVE_MODE: | ||
113 | wl1271_debug(DEBUG_PSM, "entering psm"); | ||
114 | ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); | ||
115 | if (ret < 0) | ||
116 | return ret; | ||
117 | |||
118 | wl1271_ps_elp_sleep(wl); | ||
119 | if (ret < 0) | ||
120 | return ret; | ||
121 | |||
122 | wl->psm = 1; | ||
123 | break; | ||
124 | case STATION_ACTIVE_MODE: | ||
125 | default: | ||
126 | wl1271_debug(DEBUG_PSM, "leaving psm"); | ||
127 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
128 | if (ret < 0) | ||
129 | return ret; | ||
130 | |||
131 | ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE); | ||
132 | if (ret < 0) | ||
133 | return ret; | ||
134 | |||
135 | wl->psm = 0; | ||
136 | break; | ||
137 | } | ||
138 | |||
139 | return ret; | ||
140 | } | ||
141 | |||
142 | |||
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/wl1271_ps.h new file mode 100644 index 000000000000..de2bd3c7dc9c --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_ps.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __WL1271_PS_H__ | ||
25 | #define __WL1271_PS_H__ | ||
26 | |||
27 | #include "wl1271.h" | ||
28 | #include "wl1271_acx.h" | ||
29 | |||
30 | int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode); | ||
31 | void wl1271_ps_elp_sleep(struct wl1271 *wl); | ||
32 | int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); | ||
33 | |||
34 | |||
35 | #endif /* __WL1271_PS_H__ */ | ||
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h index 2de47cc32b8b..f8ed4a4fc691 100644 --- a/drivers/net/wireless/wl12xx/reg.h +++ b/drivers/net/wireless/wl12xx/wl1271_reg.h | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of wl12xx | 2 | * This file is part of wl12xx |
3 | * | 3 | * |
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | 4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. |
5 | * Copyright (C) 2008 Nokia Corporation | 5 | * Copyright (C) 2009 Nokia Corporation |
6 | * | 6 | * |
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | 7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License | 10 | * modify it under the terms of the GNU General Public License |
@@ -34,6 +34,7 @@ | |||
34 | #define REGISTERS_WORK_SIZE 0x0000b000 | 34 | #define REGISTERS_WORK_SIZE 0x0000b000 |
35 | 35 | ||
36 | #define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC | 36 | #define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC |
37 | #define STATUS_MEM_ADDRESS 0x40400 | ||
37 | 38 | ||
38 | /* ELP register commands */ | 39 | /* ELP register commands */ |
39 | #define ELPCTRL_WAKE_UP 0x1 | 40 | #define ELPCTRL_WAKE_UP 0x1 |
@@ -42,6 +43,25 @@ | |||
42 | /* ELP WLAN_READY bit */ | 43 | /* ELP WLAN_READY bit */ |
43 | #define ELPCTRL_WLAN_READY 0x2 | 44 | #define ELPCTRL_WLAN_READY 0x2 |
44 | 45 | ||
46 | /*=============================================== | ||
47 | Host Software Reset - 32bit RW | ||
48 | ------------------------------------------ | ||
49 | [31:1] Reserved | ||
50 | 0 SOFT_RESET Soft Reset - When this bit is set, | ||
51 | it holds the Wlan hardware in a soft reset state. | ||
52 | This reset disables all MAC and baseband processor | ||
53 | clocks except the CardBus/PCI interface clock. | ||
54 | It also initializes all MAC state machines except | ||
55 | the host interface. It does not reload the | ||
56 | contents of the EEPROM. When this bit is cleared | ||
57 | (not self-clearing), the Wlan hardware | ||
58 | exits the software reset state. | ||
59 | ===============================================*/ | ||
60 | #define ACX_REG_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000) | ||
61 | |||
62 | #define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) | ||
63 | #define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) | ||
64 | #define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) | ||
45 | /* | 65 | /* |
46 | * Interrupt registers. | 66 | * Interrupt registers. |
47 | * 64 bit interrupt sources registers ws ced. | 67 | * 64 bit interrupt sources registers ws ced. |
@@ -95,6 +115,9 @@ | |||
95 | #define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) | 115 | #define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) |
96 | #define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) | 116 | #define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) |
97 | 117 | ||
118 | #define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) | ||
119 | #define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) | ||
120 | |||
98 | /* Host Interrupts*/ | 121 | /* Host Interrupts*/ |
99 | #define HINT_MASK (REGISTERS_BASE + 0x0494) | 122 | #define HINT_MASK (REGISTERS_BASE + 0x0494) |
100 | #define HINT_MASK_SET (REGISTERS_BASE + 0x0498) | 123 | #define HINT_MASK_SET (REGISTERS_BASE + 0x0498) |
@@ -106,67 +129,6 @@ | |||
106 | #define HINT_ACK (REGISTERS_BASE + 0x04A8) | 129 | #define HINT_ACK (REGISTERS_BASE + 0x04A8) |
107 | #define HINT_TRIG (REGISTERS_BASE + 0x04AC) | 130 | #define HINT_TRIG (REGISTERS_BASE + 0x04AC) |
108 | 131 | ||
109 | /* Device Configuration registers*/ | ||
110 | #define SOR_CFG (REGISTERS_BASE + 0x0800) | ||
111 | #define ECPU_CTRL (REGISTERS_BASE + 0x0804) | ||
112 | #define HI_CFG (REGISTERS_BASE + 0x0808) | ||
113 | #define EE_START (REGISTERS_BASE + 0x080C) | ||
114 | |||
115 | #define CHIP_ID_B (REGISTERS_BASE + 0x5674) | ||
116 | |||
117 | #define CHIP_ID_1251_PG10 (0x7010101) | ||
118 | #define CHIP_ID_1251_PG11 (0x7020101) | ||
119 | #define CHIP_ID_1251_PG12 (0x7030101) | ||
120 | |||
121 | #define ENABLE (REGISTERS_BASE + 0x5450) | ||
122 | |||
123 | /* Power Management registers */ | ||
124 | #define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) | ||
125 | #define ELP_CMD (REGISTERS_BASE + 0x5808) | ||
126 | #define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) | ||
127 | #define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) | ||
128 | #define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) | ||
129 | |||
130 | #define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) | ||
131 | |||
132 | /* Scratch Pad registers*/ | ||
133 | #define SCR_PAD0 (REGISTERS_BASE + 0x5608) | ||
134 | #define SCR_PAD1 (REGISTERS_BASE + 0x560C) | ||
135 | #define SCR_PAD2 (REGISTERS_BASE + 0x5610) | ||
136 | #define SCR_PAD3 (REGISTERS_BASE + 0x5614) | ||
137 | #define SCR_PAD4 (REGISTERS_BASE + 0x5618) | ||
138 | #define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) | ||
139 | #define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) | ||
140 | #define SCR_PAD5 (REGISTERS_BASE + 0x5624) | ||
141 | #define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) | ||
142 | #define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) | ||
143 | #define SCR_PAD6 (REGISTERS_BASE + 0x5630) | ||
144 | #define SCR_PAD7 (REGISTERS_BASE + 0x5634) | ||
145 | #define SCR_PAD8 (REGISTERS_BASE + 0x5638) | ||
146 | #define SCR_PAD9 (REGISTERS_BASE + 0x563C) | ||
147 | |||
148 | /* Spare registers*/ | ||
149 | #define SPARE_A1 (REGISTERS_BASE + 0x0994) | ||
150 | #define SPARE_A2 (REGISTERS_BASE + 0x0998) | ||
151 | #define SPARE_A3 (REGISTERS_BASE + 0x099C) | ||
152 | #define SPARE_A4 (REGISTERS_BASE + 0x09A0) | ||
153 | #define SPARE_A5 (REGISTERS_BASE + 0x09A4) | ||
154 | #define SPARE_A6 (REGISTERS_BASE + 0x09A8) | ||
155 | #define SPARE_A7 (REGISTERS_BASE + 0x09AC) | ||
156 | #define SPARE_A8 (REGISTERS_BASE + 0x09B0) | ||
157 | #define SPARE_B1 (REGISTERS_BASE + 0x5420) | ||
158 | #define SPARE_B2 (REGISTERS_BASE + 0x5424) | ||
159 | #define SPARE_B3 (REGISTERS_BASE + 0x5428) | ||
160 | #define SPARE_B4 (REGISTERS_BASE + 0x542C) | ||
161 | #define SPARE_B5 (REGISTERS_BASE + 0x5430) | ||
162 | #define SPARE_B6 (REGISTERS_BASE + 0x5434) | ||
163 | #define SPARE_B7 (REGISTERS_BASE + 0x5438) | ||
164 | #define SPARE_B8 (REGISTERS_BASE + 0x543C) | ||
165 | |||
166 | enum wl12xx_acx_int_reg { | ||
167 | ACX_REG_INTERRUPT_TRIG, | ||
168 | ACX_REG_INTERRUPT_TRIG_H, | ||
169 | |||
170 | /*============================================= | 132 | /*============================================= |
171 | Host Interrupt Mask Register - 32bit (RW) | 133 | Host Interrupt Mask Register - 32bit (RW) |
172 | ------------------------------------------ | 134 | ------------------------------------------ |
@@ -195,7 +157,7 @@ enum wl12xx_acx_int_reg { | |||
195 | 21- - | 157 | 21- - |
196 | Default: 0x0001 | 158 | Default: 0x0001 |
197 | *==============================================*/ | 159 | *==============================================*/ |
198 | ACX_REG_INTERRUPT_MASK, | 160 | #define ACX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC) |
199 | 161 | ||
200 | /*============================================= | 162 | /*============================================= |
201 | Host Interrupt Mask Set 16bit, (Write only) | 163 | Host Interrupt Mask Set 16bit, (Write only) |
@@ -205,7 +167,7 @@ enum wl12xx_acx_int_reg { | |||
205 | without effecting the mask | 167 | without effecting the mask |
206 | state of other bits (0 = no effect). | 168 | state of other bits (0 = no effect). |
207 | ==============================================*/ | 169 | ==============================================*/ |
208 | ACX_REG_HINT_MASK_SET, | 170 | #define ACX_REG_HINT_MASK_SET (REGISTERS_BASE + 0x04E0) |
209 | 171 | ||
210 | /*============================================= | 172 | /*============================================= |
211 | Host Interrupt Mask Clear 16bit,(Write only) | 173 | Host Interrupt Mask Clear 16bit,(Write only) |
@@ -215,7 +177,7 @@ enum wl12xx_acx_int_reg { | |||
215 | without effecting the mask | 177 | without effecting the mask |
216 | state of other bits (0 = no effect). | 178 | state of other bits (0 = no effect). |
217 | =============================================*/ | 179 | =============================================*/ |
218 | ACX_REG_HINT_MASK_CLR, | 180 | #define ACX_REG_HINT_MASK_CLR (REGISTERS_BASE + 0x04E4) |
219 | 181 | ||
220 | /*============================================= | 182 | /*============================================= |
221 | Host Interrupt Status Nondestructive Read | 183 | Host Interrupt Status Nondestructive Read |
@@ -226,7 +188,7 @@ enum wl12xx_acx_int_reg { | |||
226 | Reading this register doesn't | 188 | Reading this register doesn't |
227 | effect its content. | 189 | effect its content. |
228 | =============================================*/ | 190 | =============================================*/ |
229 | ACX_REG_INTERRUPT_NO_CLEAR, | 191 | #define ACX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8) |
230 | 192 | ||
231 | /*============================================= | 193 | /*============================================= |
232 | Host Interrupt Status Clear on Read Register | 194 | Host Interrupt Status Clear on Read Register |
@@ -237,7 +199,7 @@ enum wl12xx_acx_int_reg { | |||
237 | Reading this register clears it, | 199 | Reading this register clears it, |
238 | thus making all interrupts inactive. | 200 | thus making all interrupts inactive. |
239 | ==============================================*/ | 201 | ==============================================*/ |
240 | ACX_REG_INTERRUPT_CLEAR, | 202 | #define ACX_REG_INTERRUPT_CLEAR (REGISTERS_BASE + 0x04F8) |
241 | 203 | ||
242 | /*============================================= | 204 | /*============================================= |
243 | Host Interrupt Acknowledge Register | 205 | Host Interrupt Acknowledge Register |
@@ -249,40 +211,13 @@ enum wl12xx_acx_int_reg { | |||
249 | HINT_STS_ND registers, thus making the | 211 | HINT_STS_ND registers, thus making the |
250 | assotiated interrupt inactive. (0-no effect) | 212 | assotiated interrupt inactive. (0-no effect) |
251 | ==============================================*/ | 213 | ==============================================*/ |
252 | ACX_REG_INTERRUPT_ACK, | 214 | #define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0) |
253 | 215 | ||
254 | /*=============================================== | 216 | #define RX_DRIVER_DUMMY_WRITE_ADDRESS (REGISTERS_BASE + 0x0534) |
255 | Host Software Reset - 32bit RW | 217 | #define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538) |
256 | ------------------------------------------ | ||
257 | [31:1] Reserved | ||
258 | 0 SOFT_RESET Soft Reset - When this bit is set, | ||
259 | it holds the Wlan hardware in a soft reset state. | ||
260 | This reset disables all MAC and baseband processor | ||
261 | clocks except the CardBus/PCI interface clock. | ||
262 | It also initializes all MAC state machines except | ||
263 | the host interface. It does not reload the | ||
264 | contents of the EEPROM. When this bit is cleared | ||
265 | (not self-clearing), the Wlan hardware | ||
266 | exits the software reset state. | ||
267 | ===============================================*/ | ||
268 | ACX_REG_SLV_SOFT_RESET, | ||
269 | |||
270 | /*=============================================== | ||
271 | EEPROM Burst Read Start - 32bit RW | ||
272 | ------------------------------------------ | ||
273 | [31:1] Reserved | ||
274 | 0 ACX_EE_START - EEPROM Burst Read Start 0 | ||
275 | Setting this bit starts a burst read from | ||
276 | the external EEPROM. | ||
277 | If this bit is set (after reset) before an EEPROM read/write, | ||
278 | the burst read starts at EEPROM address 0. | ||
279 | Otherwise, it starts at the address | ||
280 | following the address of the previous access. | ||
281 | TheWlan hardware hardware clears this bit automatically. | ||
282 | 218 | ||
283 | Default: 0x00000000 | 219 | /* Device Configuration registers*/ |
284 | *================================================*/ | 220 | #define SOR_CFG (REGISTERS_BASE + 0x0800) |
285 | ACX_REG_EE_START, | ||
286 | 221 | ||
287 | /* Embedded ARM CPU Control */ | 222 | /* Embedded ARM CPU Control */ |
288 | 223 | ||
@@ -304,10 +239,89 @@ enum wl12xx_acx_int_reg { | |||
304 | 1 halt eCPU | 239 | 1 halt eCPU |
305 | 0 enable eCPU | 240 | 0 enable eCPU |
306 | ===============================================*/ | 241 | ===============================================*/ |
307 | ACX_REG_ECPU_CONTROL, | 242 | #define ACX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804) |
243 | |||
244 | #define HI_CFG (REGISTERS_BASE + 0x0808) | ||
245 | |||
246 | /*=============================================== | ||
247 | EEPROM Burst Read Start - 32bit RW | ||
248 | ------------------------------------------ | ||
249 | [31:1] Reserved | ||
250 | 0 ACX_EE_START - EEPROM Burst Read Start 0 | ||
251 | Setting this bit starts a burst read from | ||
252 | the external EEPROM. | ||
253 | If this bit is set (after reset) before an EEPROM read/write, | ||
254 | the burst read starts at EEPROM address 0. | ||
255 | Otherwise, it starts at the address | ||
256 | following the address of the previous access. | ||
257 | TheWlan hardware hardware clears this bit automatically. | ||
258 | |||
259 | Default: 0x00000000 | ||
260 | *================================================*/ | ||
261 | #define ACX_REG_EE_START (REGISTERS_BASE + 0x080C) | ||
262 | |||
263 | #define OCP_POR_CTR (REGISTERS_BASE + 0x09B4) | ||
264 | #define OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8) | ||
265 | #define OCP_DATA_READ (REGISTERS_BASE + 0x09BC) | ||
266 | #define OCP_CMD (REGISTERS_BASE + 0x09C0) | ||
267 | |||
268 | #define WL1271_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8) | ||
269 | |||
270 | #define CHIP_ID_B (REGISTERS_BASE + 0x5674) | ||
271 | |||
272 | #define CHIP_ID_1271_PG10 (0x4030101) | ||
273 | #define CHIP_ID_1271_PG20 (0x4030111) | ||
274 | |||
275 | #define ENABLE (REGISTERS_BASE + 0x5450) | ||
276 | |||
277 | /* Power Management registers */ | ||
278 | #define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) | ||
279 | #define ELP_CMD (REGISTERS_BASE + 0x5808) | ||
280 | #define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) | ||
281 | #define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) | ||
282 | #define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) | ||
283 | |||
284 | #define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) | ||
285 | |||
286 | /* Scratch Pad registers*/ | ||
287 | #define SCR_PAD0 (REGISTERS_BASE + 0x5608) | ||
288 | #define SCR_PAD1 (REGISTERS_BASE + 0x560C) | ||
289 | #define SCR_PAD2 (REGISTERS_BASE + 0x5610) | ||
290 | #define SCR_PAD3 (REGISTERS_BASE + 0x5614) | ||
291 | #define SCR_PAD4 (REGISTERS_BASE + 0x5618) | ||
292 | #define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) | ||
293 | #define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) | ||
294 | #define SCR_PAD5 (REGISTERS_BASE + 0x5624) | ||
295 | #define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) | ||
296 | #define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) | ||
297 | #define SCR_PAD6 (REGISTERS_BASE + 0x5630) | ||
298 | #define SCR_PAD7 (REGISTERS_BASE + 0x5634) | ||
299 | #define SCR_PAD8 (REGISTERS_BASE + 0x5638) | ||
300 | #define SCR_PAD9 (REGISTERS_BASE + 0x563C) | ||
301 | |||
302 | /* Spare registers*/ | ||
303 | #define SPARE_A1 (REGISTERS_BASE + 0x0994) | ||
304 | #define SPARE_A2 (REGISTERS_BASE + 0x0998) | ||
305 | #define SPARE_A3 (REGISTERS_BASE + 0x099C) | ||
306 | #define SPARE_A4 (REGISTERS_BASE + 0x09A0) | ||
307 | #define SPARE_A5 (REGISTERS_BASE + 0x09A4) | ||
308 | #define SPARE_A6 (REGISTERS_BASE + 0x09A8) | ||
309 | #define SPARE_A7 (REGISTERS_BASE + 0x09AC) | ||
310 | #define SPARE_A8 (REGISTERS_BASE + 0x09B0) | ||
311 | #define SPARE_B1 (REGISTERS_BASE + 0x5420) | ||
312 | #define SPARE_B2 (REGISTERS_BASE + 0x5424) | ||
313 | #define SPARE_B3 (REGISTERS_BASE + 0x5428) | ||
314 | #define SPARE_B4 (REGISTERS_BASE + 0x542C) | ||
315 | #define SPARE_B5 (REGISTERS_BASE + 0x5430) | ||
316 | #define SPARE_B6 (REGISTERS_BASE + 0x5434) | ||
317 | #define SPARE_B7 (REGISTERS_BASE + 0x5438) | ||
318 | #define SPARE_B8 (REGISTERS_BASE + 0x543C) | ||
319 | |||
320 | #define PLL_PARAMETERS (REGISTERS_BASE + 0x6040) | ||
321 | #define WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008) | ||
322 | #define WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100) | ||
323 | #define DRPW_SCRATCH_START (DRPW_BASE + 0x002C) | ||
308 | 324 | ||
309 | ACX_REG_TABLE_LEN | ||
310 | }; | ||
311 | 325 | ||
312 | #define ACX_SLV_SOFT_RESET_BIT BIT(1) | 326 | #define ACX_SLV_SOFT_RESET_BIT BIT(1) |
313 | #define ACX_REG_EEPROM_START_BIT BIT(1) | 327 | #define ACX_REG_EEPROM_START_BIT BIT(1) |
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c new file mode 100644 index 000000000000..ad8b6904c5eb --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "wl1271.h" | ||
25 | #include "wl1271_acx.h" | ||
26 | #include "wl1271_reg.h" | ||
27 | #include "wl1271_rx.h" | ||
28 | #include "wl1271_spi.h" | ||
29 | |||
30 | static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status, | ||
31 | u32 drv_rx_counter) | ||
32 | { | ||
33 | return status->rx_pkt_descs[drv_rx_counter] & RX_MEM_BLOCK_MASK; | ||
34 | } | ||
35 | |||
36 | static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status, | ||
37 | u32 drv_rx_counter) | ||
38 | { | ||
39 | return (status->rx_pkt_descs[drv_rx_counter] & RX_BUF_SIZE_MASK) >> | ||
40 | RX_BUF_SIZE_SHIFT_DIV; | ||
41 | } | ||
42 | |||
43 | /* The values of this table must match the wl1271_rates[] array */ | ||
44 | static u8 wl1271_rx_rate_to_idx[] = { | ||
45 | /* MCS rates are used only with 11n */ | ||
46 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */ | ||
47 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */ | ||
48 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */ | ||
49 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */ | ||
50 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */ | ||
51 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */ | ||
52 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */ | ||
53 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */ | ||
54 | |||
55 | 11, /* WL1271_RATE_54 */ | ||
56 | 10, /* WL1271_RATE_48 */ | ||
57 | 9, /* WL1271_RATE_36 */ | ||
58 | 8, /* WL1271_RATE_24 */ | ||
59 | |||
60 | /* TI-specific rate */ | ||
61 | WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22 */ | ||
62 | |||
63 | 7, /* WL1271_RATE_18 */ | ||
64 | 6, /* WL1271_RATE_12 */ | ||
65 | 3, /* WL1271_RATE_11 */ | ||
66 | 5, /* WL1271_RATE_9 */ | ||
67 | 4, /* WL1271_RATE_6 */ | ||
68 | 2, /* WL1271_RATE_5_5 */ | ||
69 | 1, /* WL1271_RATE_2 */ | ||
70 | 0 /* WL1271_RATE_1 */ | ||
71 | }; | ||
72 | |||
73 | static void wl1271_rx_status(struct wl1271 *wl, | ||
74 | struct wl1271_rx_descriptor *desc, | ||
75 | struct ieee80211_rx_status *status, | ||
76 | u8 beacon) | ||
77 | { | ||
78 | memset(status, 0, sizeof(struct ieee80211_rx_status)); | ||
79 | |||
80 | if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) | ||
81 | status->band = IEEE80211_BAND_2GHZ; | ||
82 | else | ||
83 | wl1271_warning("unsupported band 0x%x", | ||
84 | desc->flags & WL1271_RX_DESC_BAND_MASK); | ||
85 | |||
86 | /* | ||
87 | * FIXME: Add mactime handling. For IBSS (ad-hoc) we need to get the | ||
88 | * timestamp from the beacon (acx_tsf_info). In BSS mode (infra) we | ||
89 | * only need the mactime for monitor mode. For now the mactime is | ||
90 | * not valid, so RX_FLAG_TSFT should not be set | ||
91 | */ | ||
92 | status->signal = desc->rssi; | ||
93 | |||
94 | /* FIXME: Should this be optimized? */ | ||
95 | status->qual = (desc->rssi - WL1271_RX_MIN_RSSI) * 100 / | ||
96 | (WL1271_RX_MAX_RSSI - WL1271_RX_MIN_RSSI); | ||
97 | status->qual = min(status->qual, 100); | ||
98 | status->qual = max(status->qual, 0); | ||
99 | |||
100 | /* | ||
101 | * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we | ||
102 | * need to divide by two for now, but TI has been discussing about | ||
103 | * changing it. This needs to be rechecked. | ||
104 | */ | ||
105 | status->noise = desc->rssi - (desc->snr >> 1); | ||
106 | |||
107 | status->freq = ieee80211_channel_to_frequency(desc->channel); | ||
108 | |||
109 | if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { | ||
110 | status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; | ||
111 | |||
112 | if (likely(!(desc->flags & WL1271_RX_DESC_DECRYPT_FAIL))) | ||
113 | status->flag |= RX_FLAG_DECRYPTED; | ||
114 | |||
115 | if (unlikely(desc->flags & WL1271_RX_DESC_MIC_FAIL)) | ||
116 | status->flag |= RX_FLAG_MMIC_ERROR; | ||
117 | } | ||
118 | |||
119 | status->rate_idx = wl1271_rx_rate_to_idx[desc->rate]; | ||
120 | |||
121 | if (status->rate_idx == WL1271_RX_RATE_UNSUPPORTED) | ||
122 | wl1271_warning("unsupported rate"); | ||
123 | } | ||
124 | |||
125 | static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) | ||
126 | { | ||
127 | struct ieee80211_rx_status rx_status; | ||
128 | struct wl1271_rx_descriptor *desc; | ||
129 | struct sk_buff *skb; | ||
130 | u16 *fc; | ||
131 | u8 *buf; | ||
132 | u8 beacon = 0; | ||
133 | |||
134 | skb = dev_alloc_skb(length); | ||
135 | if (!skb) { | ||
136 | wl1271_error("Couldn't allocate RX frame"); | ||
137 | return; | ||
138 | } | ||
139 | |||
140 | buf = skb_put(skb, length); | ||
141 | wl1271_spi_reg_read(wl, WL1271_SLV_MEM_DATA, buf, length, true); | ||
142 | |||
143 | /* the data read starts with the descriptor */ | ||
144 | desc = (struct wl1271_rx_descriptor *) buf; | ||
145 | |||
146 | /* now we pull the descriptor out of the buffer */ | ||
147 | skb_pull(skb, sizeof(*desc)); | ||
148 | |||
149 | fc = (u16 *)skb->data; | ||
150 | if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) | ||
151 | beacon = 1; | ||
152 | |||
153 | wl1271_rx_status(wl, desc, &rx_status, beacon); | ||
154 | |||
155 | wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, | ||
156 | beacon ? "beacon" : ""); | ||
157 | |||
158 | memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); | ||
159 | ieee80211_rx(wl->hw, skb); | ||
160 | } | ||
161 | |||
162 | void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) | ||
163 | { | ||
164 | struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; | ||
165 | u32 buf_size; | ||
166 | u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; | ||
167 | u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; | ||
168 | u32 mem_block; | ||
169 | |||
170 | while (drv_rx_counter != fw_rx_counter) { | ||
171 | mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); | ||
172 | buf_size = wl1271_rx_get_buf_size(status, drv_rx_counter); | ||
173 | |||
174 | if (buf_size == 0) { | ||
175 | wl1271_warning("received empty data"); | ||
176 | break; | ||
177 | } | ||
178 | |||
179 | wl->rx_mem_pool_addr.addr = | ||
180 | (mem_block << 8) + wl_mem_map->packet_memory_pool_start; | ||
181 | wl->rx_mem_pool_addr.addr_extra = | ||
182 | wl->rx_mem_pool_addr.addr + 4; | ||
183 | |||
184 | /* Choose the block we want to read */ | ||
185 | wl1271_spi_reg_write(wl, WL1271_SLV_REG_DATA, | ||
186 | &wl->rx_mem_pool_addr, | ||
187 | sizeof(wl->rx_mem_pool_addr), false); | ||
188 | |||
189 | wl1271_rx_handle_data(wl, buf_size); | ||
190 | |||
191 | wl->rx_counter++; | ||
192 | drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; | ||
193 | } | ||
194 | |||
195 | wl1271_reg_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); | ||
196 | |||
197 | /* This is a workaround for some problems in the chip */ | ||
198 | wl1271_reg_write32(wl, RX_DRIVER_DUMMY_WRITE_ADDRESS, 0x1); | ||
199 | |||
200 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/wl1271_rx.h new file mode 100644 index 000000000000..d1ca60e43a25 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_rx.h | |||
@@ -0,0 +1,121 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_RX_H__ | ||
26 | #define __WL1271_RX_H__ | ||
27 | |||
28 | #include <linux/bitops.h> | ||
29 | |||
30 | #define WL1271_RX_MAX_RSSI -30 | ||
31 | #define WL1271_RX_MIN_RSSI -95 | ||
32 | |||
33 | #define WL1271_RX_ALIGN_TO 4 | ||
34 | #define WL1271_RX_ALIGN(len) (((len) + WL1271_RX_ALIGN_TO - 1) & \ | ||
35 | ~(WL1271_RX_ALIGN_TO - 1)) | ||
36 | |||
37 | #define SHORT_PREAMBLE_BIT BIT(0) | ||
38 | #define OFDM_RATE_BIT BIT(6) | ||
39 | #define PBCC_RATE_BIT BIT(7) | ||
40 | |||
41 | #define PLCP_HEADER_LENGTH 8 | ||
42 | #define RX_DESC_PACKETID_SHIFT 11 | ||
43 | #define RX_MAX_PACKET_ID 3 | ||
44 | |||
45 | #define NUM_RX_PKT_DESC_MOD_MASK 7 | ||
46 | #define WL1271_RX_RATE_UNSUPPORTED 0xFF | ||
47 | |||
48 | #define RX_DESC_VALID_FCS 0x0001 | ||
49 | #define RX_DESC_MATCH_RXADDR1 0x0002 | ||
50 | #define RX_DESC_MCAST 0x0004 | ||
51 | #define RX_DESC_STAINTIM 0x0008 | ||
52 | #define RX_DESC_VIRTUAL_BM 0x0010 | ||
53 | #define RX_DESC_BCAST 0x0020 | ||
54 | #define RX_DESC_MATCH_SSID 0x0040 | ||
55 | #define RX_DESC_MATCH_BSSID 0x0080 | ||
56 | #define RX_DESC_ENCRYPTION_MASK 0x0300 | ||
57 | #define RX_DESC_MEASURMENT 0x0400 | ||
58 | #define RX_DESC_SEQNUM_MASK 0x1800 | ||
59 | #define RX_DESC_MIC_FAIL 0x2000 | ||
60 | #define RX_DESC_DECRYPT_FAIL 0x4000 | ||
61 | |||
62 | /* | ||
63 | * RX Descriptor flags: | ||
64 | * | ||
65 | * Bits 0-1 - band | ||
66 | * Bit 2 - STBC | ||
67 | * Bit 3 - A-MPDU | ||
68 | * Bit 4 - HT | ||
69 | * Bits 5-7 - encryption | ||
70 | */ | ||
71 | #define WL1271_RX_DESC_BAND_MASK 0x03 | ||
72 | #define WL1271_RX_DESC_ENCRYPT_MASK 0xE0 | ||
73 | |||
74 | #define WL1271_RX_DESC_BAND_BG 0x00 | ||
75 | #define WL1271_RX_DESC_BAND_J 0x01 | ||
76 | #define WL1271_RX_DESC_BAND_A 0x02 | ||
77 | |||
78 | #define WL1271_RX_DESC_STBC BIT(2) | ||
79 | #define WL1271_RX_DESC_A_MPDU BIT(3) | ||
80 | #define WL1271_RX_DESC_HT BIT(4) | ||
81 | |||
82 | #define WL1271_RX_DESC_ENCRYPT_WEP 0x20 | ||
83 | #define WL1271_RX_DESC_ENCRYPT_TKIP 0x40 | ||
84 | #define WL1271_RX_DESC_ENCRYPT_AES 0x60 | ||
85 | #define WL1271_RX_DESC_ENCRYPT_GEM 0x80 | ||
86 | |||
87 | /* | ||
88 | * RX Descriptor status | ||
89 | * | ||
90 | * Bits 0-2 - status | ||
91 | * Bits 3-7 - reserved | ||
92 | */ | ||
93 | #define WL1271_RX_DESC_STATUS_MASK 0x07 | ||
94 | |||
95 | #define WL1271_RX_DESC_SUCCESS 0x00 | ||
96 | #define WL1271_RX_DESC_DECRYPT_FAIL 0x01 | ||
97 | #define WL1271_RX_DESC_MIC_FAIL 0x02 | ||
98 | #define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03 | ||
99 | |||
100 | #define RX_MEM_BLOCK_MASK 0xFF | ||
101 | #define RX_BUF_SIZE_MASK 0xFFF00 | ||
102 | #define RX_BUF_SIZE_SHIFT_DIV 6 | ||
103 | |||
104 | struct wl1271_rx_descriptor { | ||
105 | u16 length; | ||
106 | u8 status; | ||
107 | u8 flags; | ||
108 | u8 rate; | ||
109 | u8 channel; | ||
110 | s8 rssi; | ||
111 | u8 snr; | ||
112 | u32 timestamp; | ||
113 | u8 packet_class; | ||
114 | u8 process_id; | ||
115 | u8 pad_len; | ||
116 | u8 reserved; | ||
117 | } __attribute__ ((packed)); | ||
118 | |||
119 | void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status); | ||
120 | |||
121 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c new file mode 100644 index 000000000000..4a12880c16a8 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c | |||
@@ -0,0 +1,382 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/crc7.h> | ||
27 | #include <linux/spi/spi.h> | ||
28 | |||
29 | #include "wl1271.h" | ||
30 | #include "wl12xx_80211.h" | ||
31 | #include "wl1271_spi.h" | ||
32 | |||
33 | static int wl1271_translate_reg_addr(struct wl1271 *wl, int addr) | ||
34 | { | ||
35 | return addr - wl->physical_reg_addr + wl->virtual_reg_addr; | ||
36 | } | ||
37 | |||
38 | static int wl1271_translate_mem_addr(struct wl1271 *wl, int addr) | ||
39 | { | ||
40 | return addr - wl->physical_mem_addr + wl->virtual_mem_addr; | ||
41 | } | ||
42 | |||
43 | |||
44 | void wl1271_spi_reset(struct wl1271 *wl) | ||
45 | { | ||
46 | u8 *cmd; | ||
47 | struct spi_transfer t; | ||
48 | struct spi_message m; | ||
49 | |||
50 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | ||
51 | if (!cmd) { | ||
52 | wl1271_error("could not allocate cmd for spi reset"); | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | memset(&t, 0, sizeof(t)); | ||
57 | spi_message_init(&m); | ||
58 | |||
59 | memset(cmd, 0xff, WSPI_INIT_CMD_LEN); | ||
60 | |||
61 | t.tx_buf = cmd; | ||
62 | t.len = WSPI_INIT_CMD_LEN; | ||
63 | spi_message_add_tail(&t, &m); | ||
64 | |||
65 | spi_sync(wl->spi, &m); | ||
66 | |||
67 | wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); | ||
68 | } | ||
69 | |||
70 | void wl1271_spi_init(struct wl1271 *wl) | ||
71 | { | ||
72 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; | ||
73 | struct spi_transfer t; | ||
74 | struct spi_message m; | ||
75 | |||
76 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | ||
77 | if (!cmd) { | ||
78 | wl1271_error("could not allocate cmd for spi init"); | ||
79 | return; | ||
80 | } | ||
81 | |||
82 | memset(crc, 0, sizeof(crc)); | ||
83 | memset(&t, 0, sizeof(t)); | ||
84 | spi_message_init(&m); | ||
85 | |||
86 | /* | ||
87 | * Set WSPI_INIT_COMMAND | ||
88 | * the data is being send from the MSB to LSB | ||
89 | */ | ||
90 | cmd[2] = 0xff; | ||
91 | cmd[3] = 0xff; | ||
92 | cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; | ||
93 | cmd[0] = 0; | ||
94 | cmd[7] = 0; | ||
95 | cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; | ||
96 | cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; | ||
97 | |||
98 | if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) | ||
99 | cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; | ||
100 | else | ||
101 | cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; | ||
102 | |||
103 | cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS | ||
104 | | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; | ||
105 | |||
106 | crc[0] = cmd[1]; | ||
107 | crc[1] = cmd[0]; | ||
108 | crc[2] = cmd[7]; | ||
109 | crc[3] = cmd[6]; | ||
110 | crc[4] = cmd[5]; | ||
111 | |||
112 | cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; | ||
113 | cmd[4] |= WSPI_INIT_CMD_END; | ||
114 | |||
115 | t.tx_buf = cmd; | ||
116 | t.len = WSPI_INIT_CMD_LEN; | ||
117 | spi_message_add_tail(&t, &m); | ||
118 | |||
119 | spi_sync(wl->spi, &m); | ||
120 | |||
121 | wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); | ||
122 | } | ||
123 | |||
124 | /* Set the SPI partitions to access the chip addresses | ||
125 | * | ||
126 | * There are two VIRTUAL (SPI) partitions (the memory partition and the | ||
127 | * registers partition), which are mapped to two different areas of the | ||
128 | * PHYSICAL (hardware) memory. This function also makes other checks to | ||
129 | * ensure that the partitions are not overlapping. In the diagram below, the | ||
130 | * memory partition comes before the register partition, but the opposite is | ||
131 | * also supported. | ||
132 | * | ||
133 | * PHYSICAL address | ||
134 | * space | ||
135 | * | ||
136 | * | | | ||
137 | * ...+----+--> mem_start | ||
138 | * VIRTUAL address ... | | | ||
139 | * space ... | | [PART_0] | ||
140 | * ... | | | ||
141 | * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size | ||
142 | * | | ... | | | ||
143 | * |MEM | ... | | | ||
144 | * | | ... | | | ||
145 | * part_size <--+----+... | | {unused area) | ||
146 | * | | ... | | | ||
147 | * |REG | ... | | | ||
148 | * part_size | | ... | | | ||
149 | * + <--+----+... ...+----+--> reg_start | ||
150 | * reg_size ... | | | ||
151 | * ... | | [PART_1] | ||
152 | * ... | | | ||
153 | * ...+----+--> reg_start + reg_size | ||
154 | * | | | ||
155 | * | ||
156 | */ | ||
157 | int wl1271_set_partition(struct wl1271 *wl, | ||
158 | u32 mem_start, u32 mem_size, | ||
159 | u32 reg_start, u32 reg_size) | ||
160 | { | ||
161 | struct wl1271_partition *partition; | ||
162 | struct spi_transfer t; | ||
163 | struct spi_message m; | ||
164 | size_t len, cmd_len; | ||
165 | u32 *cmd; | ||
166 | int addr; | ||
167 | |||
168 | cmd_len = sizeof(u32) + 2 * sizeof(struct wl1271_partition); | ||
169 | cmd = kzalloc(cmd_len, GFP_KERNEL); | ||
170 | if (!cmd) | ||
171 | return -ENOMEM; | ||
172 | |||
173 | spi_message_init(&m); | ||
174 | memset(&t, 0, sizeof(t)); | ||
175 | |||
176 | partition = (struct wl1271_partition *) (cmd + 1); | ||
177 | addr = HW_ACCESS_PART0_SIZE_ADDR; | ||
178 | len = 2 * sizeof(struct wl1271_partition); | ||
179 | |||
180 | *cmd |= WSPI_CMD_WRITE; | ||
181 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
182 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
183 | |||
184 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
185 | mem_start, mem_size); | ||
186 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
187 | reg_start, reg_size); | ||
188 | |||
189 | /* Make sure that the two partitions together don't exceed the | ||
190 | * address range */ | ||
191 | if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { | ||
192 | wl1271_debug(DEBUG_SPI, "Total size exceeds maximum virtual" | ||
193 | " address range. Truncating partition[0]."); | ||
194 | mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; | ||
195 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
196 | mem_start, mem_size); | ||
197 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
198 | reg_start, reg_size); | ||
199 | } | ||
200 | |||
201 | if ((mem_start < reg_start) && | ||
202 | ((mem_start + mem_size) > reg_start)) { | ||
203 | /* Guarantee that the memory partition doesn't overlap the | ||
204 | * registers partition */ | ||
205 | wl1271_debug(DEBUG_SPI, "End of partition[0] is " | ||
206 | "overlapping partition[1]. Adjusted."); | ||
207 | mem_size = reg_start - mem_start; | ||
208 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
209 | mem_start, mem_size); | ||
210 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
211 | reg_start, reg_size); | ||
212 | } else if ((reg_start < mem_start) && | ||
213 | ((reg_start + reg_size) > mem_start)) { | ||
214 | /* Guarantee that the register partition doesn't overlap the | ||
215 | * memory partition */ | ||
216 | wl1271_debug(DEBUG_SPI, "End of partition[1] is" | ||
217 | " overlapping partition[0]. Adjusted."); | ||
218 | reg_size = mem_start - reg_start; | ||
219 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
220 | mem_start, mem_size); | ||
221 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
222 | reg_start, reg_size); | ||
223 | } | ||
224 | |||
225 | partition[0].start = mem_start; | ||
226 | partition[0].size = mem_size; | ||
227 | partition[1].start = reg_start; | ||
228 | partition[1].size = reg_size; | ||
229 | |||
230 | wl->physical_mem_addr = mem_start; | ||
231 | wl->physical_reg_addr = reg_start; | ||
232 | |||
233 | wl->virtual_mem_addr = 0; | ||
234 | wl->virtual_reg_addr = mem_size; | ||
235 | |||
236 | t.tx_buf = cmd; | ||
237 | t.len = cmd_len; | ||
238 | spi_message_add_tail(&t, &m); | ||
239 | |||
240 | spi_sync(wl->spi, &m); | ||
241 | |||
242 | kfree(cmd); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, | ||
248 | size_t len, bool fixed) | ||
249 | { | ||
250 | struct spi_transfer t[3]; | ||
251 | struct spi_message m; | ||
252 | u8 *busy_buf; | ||
253 | u32 *cmd; | ||
254 | |||
255 | cmd = &wl->buffer_cmd; | ||
256 | busy_buf = wl->buffer_busyword; | ||
257 | |||
258 | *cmd = 0; | ||
259 | *cmd |= WSPI_CMD_READ; | ||
260 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
261 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
262 | |||
263 | if (fixed) | ||
264 | *cmd |= WSPI_CMD_FIXED; | ||
265 | |||
266 | spi_message_init(&m); | ||
267 | memset(t, 0, sizeof(t)); | ||
268 | |||
269 | t[0].tx_buf = cmd; | ||
270 | t[0].len = 4; | ||
271 | spi_message_add_tail(&t[0], &m); | ||
272 | |||
273 | /* Busy and non busy words read */ | ||
274 | t[1].rx_buf = busy_buf; | ||
275 | t[1].len = WL1271_BUSY_WORD_LEN; | ||
276 | spi_message_add_tail(&t[1], &m); | ||
277 | |||
278 | t[2].rx_buf = buf; | ||
279 | t[2].len = len; | ||
280 | spi_message_add_tail(&t[2], &m); | ||
281 | |||
282 | spi_sync(wl->spi, &m); | ||
283 | |||
284 | /* FIXME: check busy words */ | ||
285 | |||
286 | wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); | ||
287 | wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); | ||
288 | } | ||
289 | |||
290 | void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, | ||
291 | size_t len, bool fixed) | ||
292 | { | ||
293 | struct spi_transfer t[2]; | ||
294 | struct spi_message m; | ||
295 | u32 *cmd; | ||
296 | |||
297 | cmd = &wl->buffer_cmd; | ||
298 | |||
299 | *cmd = 0; | ||
300 | *cmd |= WSPI_CMD_WRITE; | ||
301 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
302 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
303 | |||
304 | if (fixed) | ||
305 | *cmd |= WSPI_CMD_FIXED; | ||
306 | |||
307 | spi_message_init(&m); | ||
308 | memset(t, 0, sizeof(t)); | ||
309 | |||
310 | t[0].tx_buf = cmd; | ||
311 | t[0].len = sizeof(*cmd); | ||
312 | spi_message_add_tail(&t[0], &m); | ||
313 | |||
314 | t[1].tx_buf = buf; | ||
315 | t[1].len = len; | ||
316 | spi_message_add_tail(&t[1], &m); | ||
317 | |||
318 | spi_sync(wl->spi, &m); | ||
319 | |||
320 | wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); | ||
321 | wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); | ||
322 | } | ||
323 | |||
324 | void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, | ||
325 | size_t len) | ||
326 | { | ||
327 | int physical; | ||
328 | |||
329 | physical = wl1271_translate_mem_addr(wl, addr); | ||
330 | |||
331 | wl1271_spi_read(wl, physical, buf, len, false); | ||
332 | } | ||
333 | |||
334 | void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, | ||
335 | size_t len) | ||
336 | { | ||
337 | int physical; | ||
338 | |||
339 | physical = wl1271_translate_mem_addr(wl, addr); | ||
340 | |||
341 | wl1271_spi_write(wl, physical, buf, len, false); | ||
342 | } | ||
343 | |||
344 | void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len, | ||
345 | bool fixed) | ||
346 | { | ||
347 | int physical; | ||
348 | |||
349 | physical = wl1271_translate_reg_addr(wl, addr); | ||
350 | |||
351 | wl1271_spi_read(wl, physical, buf, len, fixed); | ||
352 | } | ||
353 | |||
354 | void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len, | ||
355 | bool fixed) | ||
356 | { | ||
357 | int physical; | ||
358 | |||
359 | physical = wl1271_translate_reg_addr(wl, addr); | ||
360 | |||
361 | wl1271_spi_write(wl, physical, buf, len, fixed); | ||
362 | } | ||
363 | |||
364 | u32 wl1271_mem_read32(struct wl1271 *wl, int addr) | ||
365 | { | ||
366 | return wl1271_read32(wl, wl1271_translate_mem_addr(wl, addr)); | ||
367 | } | ||
368 | |||
369 | void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val) | ||
370 | { | ||
371 | wl1271_write32(wl, wl1271_translate_mem_addr(wl, addr), val); | ||
372 | } | ||
373 | |||
374 | u32 wl1271_reg_read32(struct wl1271 *wl, int addr) | ||
375 | { | ||
376 | return wl1271_read32(wl, wl1271_translate_reg_addr(wl, addr)); | ||
377 | } | ||
378 | |||
379 | void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val) | ||
380 | { | ||
381 | wl1271_write32(wl, wl1271_translate_reg_addr(wl, addr), val); | ||
382 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h new file mode 100644 index 000000000000..2c9968458646 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_spi.h | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_SPI_H__ | ||
26 | #define __WL1271_SPI_H__ | ||
27 | |||
28 | #include "wl1271_reg.h" | ||
29 | |||
30 | #define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 | ||
31 | |||
32 | #define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 | ||
33 | #define HW_ACCESS_PART0_START_ADDR 0x1FFC4 | ||
34 | #define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 | ||
35 | #define HW_ACCESS_PART1_START_ADDR 0x1FFCC | ||
36 | |||
37 | #define HW_ACCESS_REGISTER_SIZE 4 | ||
38 | |||
39 | #define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 | ||
40 | |||
41 | #define WSPI_CMD_READ 0x40000000 | ||
42 | #define WSPI_CMD_WRITE 0x00000000 | ||
43 | #define WSPI_CMD_FIXED 0x20000000 | ||
44 | #define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 | ||
45 | #define WSPI_CMD_BYTE_LENGTH_OFFSET 17 | ||
46 | #define WSPI_CMD_BYTE_ADDR 0x0001FFFF | ||
47 | |||
48 | #define WSPI_INIT_CMD_CRC_LEN 5 | ||
49 | |||
50 | #define WSPI_INIT_CMD_START 0x00 | ||
51 | #define WSPI_INIT_CMD_TX 0x40 | ||
52 | /* the extra bypass bit is sampled by the TNET as '1' */ | ||
53 | #define WSPI_INIT_CMD_BYPASS_BIT 0x80 | ||
54 | #define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 | ||
55 | #define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 | ||
56 | #define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 | ||
57 | #define WSPI_INIT_CMD_IOD 0x40 | ||
58 | #define WSPI_INIT_CMD_IP 0x20 | ||
59 | #define WSPI_INIT_CMD_CS 0x10 | ||
60 | #define WSPI_INIT_CMD_WS 0x08 | ||
61 | #define WSPI_INIT_CMD_WSPI 0x01 | ||
62 | #define WSPI_INIT_CMD_END 0x01 | ||
63 | |||
64 | #define WSPI_INIT_CMD_LEN 8 | ||
65 | |||
66 | #define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ | ||
67 | ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) | ||
68 | #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 | ||
69 | |||
70 | |||
71 | /* Raw target IO, address is not translated */ | ||
72 | void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, | ||
73 | size_t len, bool fixed); | ||
74 | void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, | ||
75 | size_t len, bool fixed); | ||
76 | |||
77 | /* Memory target IO, address is tranlated to partition 0 */ | ||
78 | void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, size_t len); | ||
79 | void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, size_t len); | ||
80 | u32 wl1271_mem_read32(struct wl1271 *wl, int addr); | ||
81 | void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val); | ||
82 | |||
83 | /* Registers IO */ | ||
84 | void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len, | ||
85 | bool fixed); | ||
86 | void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len, | ||
87 | bool fixed); | ||
88 | u32 wl1271_reg_read32(struct wl1271 *wl, int addr); | ||
89 | void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val); | ||
90 | |||
91 | /* INIT and RESET words */ | ||
92 | void wl1271_spi_reset(struct wl1271 *wl); | ||
93 | void wl1271_spi_init(struct wl1271 *wl); | ||
94 | int wl1271_set_partition(struct wl1271 *wl, | ||
95 | u32 part_start, u32 part_size, | ||
96 | u32 reg_start, u32 reg_size); | ||
97 | |||
98 | static inline u32 wl1271_read32(struct wl1271 *wl, int addr) | ||
99 | { | ||
100 | wl1271_spi_read(wl, addr, &wl->buffer_32, | ||
101 | sizeof(wl->buffer_32), false); | ||
102 | |||
103 | return wl->buffer_32; | ||
104 | } | ||
105 | |||
106 | static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) | ||
107 | { | ||
108 | wl->buffer_32 = val; | ||
109 | wl1271_spi_write(wl, addr, &wl->buffer_32, | ||
110 | sizeof(wl->buffer_32), false); | ||
111 | } | ||
112 | |||
113 | #endif /* __WL1271_SPI_H__ */ | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c new file mode 100644 index 000000000000..ff221258b941 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c | |||
@@ -0,0 +1,378 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | |||
27 | #include "wl1271.h" | ||
28 | #include "wl1271_spi.h" | ||
29 | #include "wl1271_reg.h" | ||
30 | #include "wl1271_ps.h" | ||
31 | #include "wl1271_tx.h" | ||
32 | |||
33 | static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) | ||
34 | { | ||
35 | int i; | ||
36 | |||
37 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
38 | if (wl->tx_frames[i] == NULL) { | ||
39 | wl->tx_frames[i] = skb; | ||
40 | return i; | ||
41 | } | ||
42 | |||
43 | return -EBUSY; | ||
44 | } | ||
45 | |||
46 | static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) | ||
47 | { | ||
48 | struct wl1271_tx_hw_descr *desc; | ||
49 | u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; | ||
50 | u32 total_blocks, excluded; | ||
51 | int id, ret = -EBUSY; | ||
52 | |||
53 | /* allocate free identifier for the packet */ | ||
54 | id = wl1271_tx_id(wl, skb); | ||
55 | if (id < 0) | ||
56 | return id; | ||
57 | |||
58 | /* approximate the number of blocks required for this packet | ||
59 | in the firmware */ | ||
60 | /* FIXME: try to figure out what is done here and make it cleaner */ | ||
61 | total_blocks = (skb->len) >> TX_HW_BLOCK_SHIFT_DIV; | ||
62 | excluded = (total_blocks << 2) + (skb->len & 0xff) + 34; | ||
63 | total_blocks += (excluded > 252) ? 2 : 1; | ||
64 | total_blocks += TX_HW_BLOCK_SPARE; | ||
65 | |||
66 | if (total_blocks <= wl->tx_blocks_available) { | ||
67 | desc = (struct wl1271_tx_hw_descr *)skb_push( | ||
68 | skb, total_len - skb->len); | ||
69 | |||
70 | desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; | ||
71 | desc->total_mem_blocks = total_blocks; | ||
72 | desc->id = id; | ||
73 | |||
74 | wl->tx_blocks_available -= total_blocks; | ||
75 | |||
76 | ret = 0; | ||
77 | |||
78 | wl1271_debug(DEBUG_TX, | ||
79 | "tx_allocate: size: %d, blocks: %d, id: %d", | ||
80 | total_len, total_blocks, id); | ||
81 | } else | ||
82 | wl->tx_frames[id] = NULL; | ||
83 | |||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, | ||
88 | u32 extra, struct ieee80211_tx_info *control) | ||
89 | { | ||
90 | struct wl1271_tx_hw_descr *desc; | ||
91 | int pad; | ||
92 | |||
93 | desc = (struct wl1271_tx_hw_descr *) skb->data; | ||
94 | |||
95 | /* configure packet life time */ | ||
96 | desc->start_time = jiffies_to_usecs(jiffies) - wl->time_offset; | ||
97 | desc->life_time = TX_HW_MGMT_PKT_LIFETIME_TU; | ||
98 | |||
99 | /* configure the tx attributes */ | ||
100 | desc->tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; | ||
101 | /* FIXME: do we know the packet priority? can we identify mgmt | ||
102 | packets, and use max prio for them at least? */ | ||
103 | desc->tid = 0; | ||
104 | desc->aid = TX_HW_DEFAULT_AID; | ||
105 | desc->reserved = 0; | ||
106 | |||
107 | /* align the length (and store in terms of words) */ | ||
108 | pad = WL1271_TX_ALIGN(skb->len); | ||
109 | desc->length = pad >> 2; | ||
110 | |||
111 | /* calculate number of padding bytes */ | ||
112 | pad = pad - skb->len; | ||
113 | desc->tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; | ||
114 | |||
115 | wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb, | ||
120 | struct ieee80211_tx_info *control) | ||
121 | { | ||
122 | |||
123 | struct wl1271_tx_hw_descr *desc; | ||
124 | int len; | ||
125 | |||
126 | /* FIXME: This is a workaround for getting non-aligned packets. | ||
127 | This happens at least with EAPOL packets from the user space. | ||
128 | Our DMA requires packets to be aligned on a 4-byte boundary. | ||
129 | */ | ||
130 | if (unlikely((long)skb->data & 0x03)) { | ||
131 | int offset = (4 - (long)skb->data) & 0x03; | ||
132 | wl1271_debug(DEBUG_TX, "skb offset %d", offset); | ||
133 | |||
134 | /* check whether the current skb can be used */ | ||
135 | if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { | ||
136 | unsigned char *src = skb->data; | ||
137 | |||
138 | /* align the buffer on a 4-byte boundary */ | ||
139 | skb_reserve(skb, offset); | ||
140 | memmove(skb->data, src, skb->len); | ||
141 | } else { | ||
142 | wl1271_info("No handler, fixme!"); | ||
143 | return -EINVAL; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | len = WL1271_TX_ALIGN(skb->len); | ||
148 | |||
149 | /* perform a fixed address block write with the packet */ | ||
150 | wl1271_spi_reg_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true); | ||
151 | |||
152 | /* write packet new counter into the write access register */ | ||
153 | wl->tx_packets_count++; | ||
154 | wl1271_reg_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); | ||
155 | |||
156 | desc = (struct wl1271_tx_hw_descr *) skb->data; | ||
157 | wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", | ||
158 | desc->id, skb, len, desc->length); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /* caller must hold wl->mutex */ | ||
164 | static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) | ||
165 | { | ||
166 | struct ieee80211_tx_info *info; | ||
167 | u32 extra = 0; | ||
168 | int ret = 0; | ||
169 | u8 idx; | ||
170 | |||
171 | if (!skb) | ||
172 | return -EINVAL; | ||
173 | |||
174 | info = IEEE80211_SKB_CB(skb); | ||
175 | |||
176 | if (info->control.hw_key && | ||
177 | info->control.hw_key->alg == ALG_TKIP) | ||
178 | extra = WL1271_TKIP_IV_SPACE; | ||
179 | |||
180 | if (info->control.hw_key) { | ||
181 | idx = info->control.hw_key->hw_key_idx; | ||
182 | |||
183 | /* FIXME: do we have to do this if we're not using WEP? */ | ||
184 | if (unlikely(wl->default_key != idx)) { | ||
185 | ret = wl1271_cmd_set_default_wep_key(wl, idx); | ||
186 | if (ret < 0) | ||
187 | return ret; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | ret = wl1271_tx_allocate(wl, skb, extra); | ||
192 | if (ret < 0) | ||
193 | return ret; | ||
194 | |||
195 | ret = wl1271_tx_fill_hdr(wl, skb, extra, info); | ||
196 | if (ret < 0) | ||
197 | return ret; | ||
198 | |||
199 | ret = wl1271_tx_send_packet(wl, skb, info); | ||
200 | if (ret < 0) | ||
201 | return ret; | ||
202 | |||
203 | return ret; | ||
204 | } | ||
205 | |||
206 | void wl1271_tx_work(struct work_struct *work) | ||
207 | { | ||
208 | struct wl1271 *wl = container_of(work, struct wl1271, tx_work); | ||
209 | struct sk_buff *skb; | ||
210 | bool woken_up = false; | ||
211 | int ret; | ||
212 | |||
213 | mutex_lock(&wl->mutex); | ||
214 | |||
215 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
216 | goto out; | ||
217 | |||
218 | while ((skb = skb_dequeue(&wl->tx_queue))) { | ||
219 | if (!woken_up) { | ||
220 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
221 | if (ret < 0) | ||
222 | goto out; | ||
223 | woken_up = true; | ||
224 | } | ||
225 | |||
226 | ret = wl1271_tx_frame(wl, skb); | ||
227 | if (ret == -EBUSY) { | ||
228 | /* firmware buffer is full, stop queues */ | ||
229 | wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, " | ||
230 | "stop queues"); | ||
231 | ieee80211_stop_queues(wl->hw); | ||
232 | wl->tx_queue_stopped = true; | ||
233 | skb_queue_head(&wl->tx_queue, skb); | ||
234 | goto out; | ||
235 | } else if (ret < 0) { | ||
236 | dev_kfree_skb(skb); | ||
237 | goto out; | ||
238 | } else if (wl->tx_queue_stopped) { | ||
239 | /* firmware buffer has space, restart queues */ | ||
240 | wl1271_debug(DEBUG_TX, | ||
241 | "complete_packet: waking queues"); | ||
242 | ieee80211_wake_queues(wl->hw); | ||
243 | wl->tx_queue_stopped = false; | ||
244 | } | ||
245 | } | ||
246 | |||
247 | out: | ||
248 | if (woken_up) | ||
249 | wl1271_ps_elp_sleep(wl); | ||
250 | |||
251 | mutex_unlock(&wl->mutex); | ||
252 | } | ||
253 | |||
254 | static void wl1271_tx_complete_packet(struct wl1271 *wl, | ||
255 | struct wl1271_tx_hw_res_descr *result) | ||
256 | { | ||
257 | |||
258 | struct ieee80211_tx_info *info; | ||
259 | struct sk_buff *skb; | ||
260 | u32 header_len; | ||
261 | int id = result->id; | ||
262 | |||
263 | /* check for id legality */ | ||
264 | if (id >= TX_HW_RESULT_QUEUE_LEN || wl->tx_frames[id] == NULL) { | ||
265 | wl1271_warning("TX result illegal id: %d", id); | ||
266 | return; | ||
267 | } | ||
268 | |||
269 | skb = wl->tx_frames[id]; | ||
270 | info = IEEE80211_SKB_CB(skb); | ||
271 | |||
272 | /* update packet status */ | ||
273 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { | ||
274 | if (result->status == TX_SUCCESS) | ||
275 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
276 | if (result->status & TX_RETRY_EXCEEDED) { | ||
277 | /* FIXME */ | ||
278 | /* info->status.excessive_retries = 1; */ | ||
279 | wl->stats.excessive_retries++; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /* FIXME */ | ||
284 | /* info->status.retry_count = result->ack_failures; */ | ||
285 | wl->stats.retry_count += result->ack_failures; | ||
286 | |||
287 | /* get header len */ | ||
288 | if (info->control.hw_key && | ||
289 | info->control.hw_key->alg == ALG_TKIP) | ||
290 | header_len = WL1271_TKIP_IV_SPACE + | ||
291 | sizeof(struct wl1271_tx_hw_descr); | ||
292 | else | ||
293 | header_len = sizeof(struct wl1271_tx_hw_descr); | ||
294 | |||
295 | wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" | ||
296 | " status 0x%x", | ||
297 | result->id, skb, result->ack_failures, | ||
298 | result->rate_class_index, result->status); | ||
299 | |||
300 | /* remove private header from packet */ | ||
301 | skb_pull(skb, header_len); | ||
302 | |||
303 | /* return the packet to the stack */ | ||
304 | ieee80211_tx_status(wl->hw, skb); | ||
305 | wl->tx_frames[result->id] = NULL; | ||
306 | } | ||
307 | |||
308 | /* Called upon reception of a TX complete interrupt */ | ||
309 | void wl1271_tx_complete(struct wl1271 *wl, u32 count) | ||
310 | { | ||
311 | struct wl1271_acx_mem_map *memmap = | ||
312 | (struct wl1271_acx_mem_map *)wl->target_mem_map; | ||
313 | u32 i; | ||
314 | |||
315 | wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); | ||
316 | |||
317 | /* read the tx results from the chipset */ | ||
318 | wl1271_spi_mem_read(wl, memmap->tx_result, | ||
319 | wl->tx_res_if, sizeof(*wl->tx_res_if)); | ||
320 | |||
321 | /* verify that the result buffer is not getting overrun */ | ||
322 | if (count > TX_HW_RESULT_QUEUE_LEN) { | ||
323 | wl1271_warning("TX result overflow from chipset: %d", count); | ||
324 | count = TX_HW_RESULT_QUEUE_LEN; | ||
325 | } | ||
326 | |||
327 | /* process the results */ | ||
328 | for (i = 0; i < count; i++) { | ||
329 | struct wl1271_tx_hw_res_descr *result; | ||
330 | u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; | ||
331 | |||
332 | /* process the packet */ | ||
333 | result = &(wl->tx_res_if->tx_results_queue[offset]); | ||
334 | wl1271_tx_complete_packet(wl, result); | ||
335 | |||
336 | wl->tx_results_count++; | ||
337 | } | ||
338 | |||
339 | /* write host counter to chipset (to ack) */ | ||
340 | wl1271_mem_write32(wl, memmap->tx_result + | ||
341 | offsetof(struct wl1271_tx_hw_res_if, | ||
342 | tx_result_host_counter), | ||
343 | wl->tx_res_if->tx_result_fw_counter); | ||
344 | } | ||
345 | |||
346 | /* caller must hold wl->mutex */ | ||
347 | void wl1271_tx_flush(struct wl1271 *wl) | ||
348 | { | ||
349 | int i; | ||
350 | struct sk_buff *skb; | ||
351 | struct ieee80211_tx_info *info; | ||
352 | |||
353 | /* TX failure */ | ||
354 | /* control->flags = 0; FIXME */ | ||
355 | |||
356 | while ((skb = skb_dequeue(&wl->tx_queue))) { | ||
357 | info = IEEE80211_SKB_CB(skb); | ||
358 | |||
359 | wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb); | ||
360 | |||
361 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | ||
362 | continue; | ||
363 | |||
364 | ieee80211_tx_status(wl->hw, skb); | ||
365 | } | ||
366 | |||
367 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
368 | if (wl->tx_frames[i] != NULL) { | ||
369 | skb = wl->tx_frames[i]; | ||
370 | info = IEEE80211_SKB_CB(skb); | ||
371 | |||
372 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | ||
373 | continue; | ||
374 | |||
375 | ieee80211_tx_status(wl->hw, skb); | ||
376 | wl->tx_frames[i] = NULL; | ||
377 | } | ||
378 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h new file mode 100644 index 000000000000..4a614067ddba --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_tx.h | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL1271_TX_H__ | ||
26 | #define __WL1271_TX_H__ | ||
27 | |||
28 | #define TX_HW_BLOCK_SPARE 2 | ||
29 | #define TX_HW_BLOCK_SHIFT_DIV 8 | ||
30 | |||
31 | #define TX_HW_MGMT_PKT_LIFETIME_TU 2000 | ||
32 | /* The chipset reference driver states, that the "aid" value 1 | ||
33 | * is for infra-BSS, but is still always used */ | ||
34 | #define TX_HW_DEFAULT_AID 1 | ||
35 | |||
36 | #define TX_HW_ATTR_SAVE_RETRIES BIT(0) | ||
37 | #define TX_HW_ATTR_HEADER_PAD BIT(1) | ||
38 | #define TX_HW_ATTR_SESSION_COUNTER (BIT(2) | BIT(3) | BIT(4)) | ||
39 | #define TX_HW_ATTR_RATE_POLICY (BIT(5) | BIT(6) | BIT(7) | \ | ||
40 | BIT(8) | BIT(9)) | ||
41 | #define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) | ||
42 | #define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) | ||
43 | |||
44 | #define TX_HW_ATTR_OFST_SAVE_RETRIES 0 | ||
45 | #define TX_HW_ATTR_OFST_HEADER_PAD 1 | ||
46 | #define TX_HW_ATTR_OFST_SESSION_COUNTER 2 | ||
47 | #define TX_HW_ATTR_OFST_RATE_POLICY 5 | ||
48 | #define TX_HW_ATTR_OFST_LAST_WORD_PAD 10 | ||
49 | #define TX_HW_ATTR_OFST_TX_CMPLT_REQ 12 | ||
50 | |||
51 | #define TX_HW_RESULT_QUEUE_LEN 16 | ||
52 | #define TX_HW_RESULT_QUEUE_LEN_MASK 0xf | ||
53 | |||
54 | #define WL1271_TX_ALIGN_TO 4 | ||
55 | #define WL1271_TX_ALIGN(len) (((len) + WL1271_TX_ALIGN_TO - 1) & \ | ||
56 | ~(WL1271_TX_ALIGN_TO - 1)) | ||
57 | #define WL1271_TKIP_IV_SPACE 4 | ||
58 | |||
59 | struct wl1271_tx_hw_descr { | ||
60 | /* Length of packet in words, including descriptor+header+data */ | ||
61 | u16 length; | ||
62 | /* Number of extra memory blocks to allocate for this packet in | ||
63 | addition to the number of blocks derived from the packet length */ | ||
64 | u8 extra_mem_blocks; | ||
65 | /* Total number of memory blocks allocated by the host for this packet. | ||
66 | Must be equal or greater than the actual blocks number allocated by | ||
67 | HW!! */ | ||
68 | u8 total_mem_blocks; | ||
69 | /* Device time (in us) when the packet arrived to the driver */ | ||
70 | u32 start_time; | ||
71 | /* Max delay in TUs until transmission. The last device time the | ||
72 | packet can be transmitted is: startTime+(1024*LifeTime) */ | ||
73 | u16 life_time; | ||
74 | /* Bitwise fields - see TX_ATTR... definitions above. */ | ||
75 | u16 tx_attr; | ||
76 | /* Packet identifier used also in the Tx-Result. */ | ||
77 | u8 id; | ||
78 | /* The packet TID value (as User-Priority) */ | ||
79 | u8 tid; | ||
80 | /* Identifier of the remote STA in IBSS, 1 in infra-BSS */ | ||
81 | u8 aid; | ||
82 | u8 reserved; | ||
83 | } __attribute__ ((packed)); | ||
84 | |||
85 | enum wl1271_tx_hw_res_status { | ||
86 | TX_SUCCESS = 0, | ||
87 | TX_HW_ERROR = 1, | ||
88 | TX_DISABLED = 2, | ||
89 | TX_RETRY_EXCEEDED = 3, | ||
90 | TX_TIMEOUT = 4, | ||
91 | TX_KEY_NOT_FOUND = 5, | ||
92 | TX_PEER_NOT_FOUND = 6, | ||
93 | TX_SESSION_MISMATCH = 7 | ||
94 | }; | ||
95 | |||
96 | struct wl1271_tx_hw_res_descr { | ||
97 | /* Packet Identifier - same value used in the Tx descriptor.*/ | ||
98 | u8 id; | ||
99 | /* The status of the transmission, indicating success or one of | ||
100 | several possible reasons for failure. */ | ||
101 | u8 status; | ||
102 | /* Total air access duration including all retrys and overheads.*/ | ||
103 | u16 medium_usage; | ||
104 | /* The time passed from host xfer to Tx-complete.*/ | ||
105 | u32 fw_handling_time; | ||
106 | /* Total media delay | ||
107 | (from 1st EDCA AIFS counter until TX Complete). */ | ||
108 | u32 medium_delay; | ||
109 | /* LS-byte of last TKIP seq-num (saved per AC for recovery). */ | ||
110 | u8 lsb_security_sequence_number; | ||
111 | /* Retry count - number of transmissions without successful ACK.*/ | ||
112 | u8 ack_failures; | ||
113 | /* The rate that succeeded getting ACK | ||
114 | (Valid only if status=SUCCESS). */ | ||
115 | u8 rate_class_index; | ||
116 | /* for 4-byte alignment. */ | ||
117 | u8 spare; | ||
118 | } __attribute__ ((packed)); | ||
119 | |||
120 | struct wl1271_tx_hw_res_if { | ||
121 | u32 tx_result_fw_counter; | ||
122 | u32 tx_result_host_counter; | ||
123 | struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN]; | ||
124 | } __attribute__ ((packed)); | ||
125 | |||
126 | void wl1271_tx_work(struct work_struct *work); | ||
127 | void wl1271_tx_complete(struct wl1271 *wl, u32 count); | ||
128 | void wl1271_tx_flush(struct wl1271 *wl); | ||
129 | |||
130 | #endif | ||
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 2c813d87092c..5e110a2328ae 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c | |||
@@ -1278,11 +1278,11 @@ int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) | |||
1278 | other_led = chip->link_led == LED1 ? LED2 : LED1; | 1278 | other_led = chip->link_led == LED1 ? LED2 : LED1; |
1279 | 1279 | ||
1280 | switch (status) { | 1280 | switch (status) { |
1281 | case LED_OFF: | 1281 | case ZD_LED_OFF: |
1282 | ioreqs[0].value = FW_LINK_OFF; | 1282 | ioreqs[0].value = FW_LINK_OFF; |
1283 | ioreqs[1].value = v[1] & ~(LED1|LED2); | 1283 | ioreqs[1].value = v[1] & ~(LED1|LED2); |
1284 | break; | 1284 | break; |
1285 | case LED_SCANNING: | 1285 | case ZD_LED_SCANNING: |
1286 | ioreqs[0].value = FW_LINK_OFF; | 1286 | ioreqs[0].value = FW_LINK_OFF; |
1287 | ioreqs[1].value = v[1] & ~other_led; | 1287 | ioreqs[1].value = v[1] & ~other_led; |
1288 | if (get_seconds() % 3 == 0) { | 1288 | if (get_seconds() % 3 == 0) { |
@@ -1291,7 +1291,7 @@ int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) | |||
1291 | ioreqs[1].value |= chip->link_led; | 1291 | ioreqs[1].value |= chip->link_led; |
1292 | } | 1292 | } |
1293 | break; | 1293 | break; |
1294 | case LED_ASSOCIATED: | 1294 | case ZD_LED_ASSOCIATED: |
1295 | ioreqs[0].value = FW_LINK_TX; | 1295 | ioreqs[0].value = FW_LINK_TX; |
1296 | ioreqs[1].value = v[1] & ~other_led; | 1296 | ioreqs[1].value = v[1] & ~other_led; |
1297 | ioreqs[1].value |= chip->link_led; | 1297 | ioreqs[1].value |= chip->link_led; |
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index ee42751d5cb0..678c139a840c 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h | |||
@@ -897,9 +897,9 @@ int zd_chip_lock_phy_regs(struct zd_chip *chip); | |||
897 | int zd_chip_unlock_phy_regs(struct zd_chip *chip); | 897 | int zd_chip_unlock_phy_regs(struct zd_chip *chip); |
898 | 898 | ||
899 | enum led_status { | 899 | enum led_status { |
900 | LED_OFF = 0, | 900 | ZD_LED_OFF = 0, |
901 | LED_SCANNING = 1, | 901 | ZD_LED_SCANNING = 1, |
902 | LED_ASSOCIATED = 2, | 902 | ZD_LED_ASSOCIATED = 2, |
903 | }; | 903 | }; |
904 | 904 | ||
905 | int zd_chip_control_leds(struct zd_chip *chip, enum led_status status); | 905 | int zd_chip_control_leds(struct zd_chip *chip, enum led_status status); |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 54abdd0c0045..55b7fbdc85dc 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -1013,7 +1013,7 @@ static void link_led_handler(struct work_struct *work) | |||
1013 | spin_unlock_irq(&mac->lock); | 1013 | spin_unlock_irq(&mac->lock); |
1014 | 1014 | ||
1015 | r = zd_chip_control_leds(chip, | 1015 | r = zd_chip_control_leds(chip, |
1016 | is_associated ? LED_ASSOCIATED : LED_SCANNING); | 1016 | is_associated ? ZD_LED_ASSOCIATED : ZD_LED_SCANNING); |
1017 | if (r) | 1017 | if (r) |
1018 | dev_dbg_f(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); | 1018 | dev_dbg_f(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); |
1019 | 1019 | ||
@@ -1038,5 +1038,5 @@ static void housekeeping_disable(struct zd_mac *mac) | |||
1038 | dev_dbg_f(zd_mac_dev(mac), "\n"); | 1038 | dev_dbg_f(zd_mac_dev(mac), "\n"); |
1039 | cancel_rearming_delayed_workqueue(zd_workqueue, | 1039 | cancel_rearming_delayed_workqueue(zd_workqueue, |
1040 | &mac->housekeeping.link_led_work); | 1040 | &mac->housekeeping.link_led_work); |
1041 | zd_chip_control_leds(&mac->chip, LED_OFF); | 1041 | zd_chip_control_leds(&mac->chip, ZD_LED_OFF); |
1042 | } | 1042 | } |
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 40ea41762247..593fc618a2ea 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c | |||
@@ -169,8 +169,14 @@ err_pci: | |||
169 | /* Get the word-offset for a SSB_SPROM_XXX define. */ | 169 | /* Get the word-offset for a SSB_SPROM_XXX define. */ |
170 | #define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16)) | 170 | #define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16)) |
171 | /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */ | 171 | /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */ |
172 | #define SPEX(_outvar, _offset, _mask, _shift) \ | 172 | #define SPEX16(_outvar, _offset, _mask, _shift) \ |
173 | out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) | 173 | out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) |
174 | #define SPEX32(_outvar, _offset, _mask, _shift) \ | ||
175 | out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \ | ||
176 | in[SPOFF(_offset)]) & (_mask)) >> (_shift)) | ||
177 | #define SPEX(_outvar, _offset, _mask, _shift) \ | ||
178 | SPEX16(_outvar, _offset, _mask, _shift) | ||
179 | |||
174 | 180 | ||
175 | static inline u8 ssb_crc8(u8 crc, u8 data) | 181 | static inline u8 ssb_crc8(u8 crc, u8 data) |
176 | { | 182 | { |
@@ -480,6 +486,8 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) | |||
480 | SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0); | 486 | SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0); |
481 | SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); | 487 | SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); |
482 | SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0); | 488 | SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0); |
489 | SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0); | ||
490 | SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0); | ||
483 | SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A, | 491 | SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A, |
484 | SSB_SPROM8_ANTAVAIL_A_SHIFT); | 492 | SSB_SPROM8_ANTAVAIL_A_SHIFT); |
485 | SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG, | 493 | SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG, |
@@ -490,12 +498,55 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) | |||
490 | SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0); | 498 | SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0); |
491 | SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A, | 499 | SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A, |
492 | SSB_SPROM8_ITSSI_A_SHIFT); | 500 | SSB_SPROM8_ITSSI_A_SHIFT); |
501 | SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0); | ||
502 | SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK, | ||
503 | SSB_SPROM8_MAXP_AL_SHIFT); | ||
493 | SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0); | 504 | SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0); |
494 | SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1, | 505 | SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1, |
495 | SSB_SPROM8_GPIOA_P1_SHIFT); | 506 | SSB_SPROM8_GPIOA_P1_SHIFT); |
496 | SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0); | 507 | SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0); |
497 | SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3, | 508 | SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3, |
498 | SSB_SPROM8_GPIOB_P3_SHIFT); | 509 | SSB_SPROM8_GPIOB_P3_SHIFT); |
510 | SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0); | ||
511 | SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G, | ||
512 | SSB_SPROM8_TRI5G_SHIFT); | ||
513 | SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0); | ||
514 | SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH, | ||
515 | SSB_SPROM8_TRI5GH_SHIFT); | ||
516 | SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0); | ||
517 | SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G, | ||
518 | SSB_SPROM8_RXPO5G_SHIFT); | ||
519 | SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0); | ||
520 | SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G, | ||
521 | SSB_SPROM8_RSSISMC2G_SHIFT); | ||
522 | SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G, | ||
523 | SSB_SPROM8_RSSISAV2G_SHIFT); | ||
524 | SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G, | ||
525 | SSB_SPROM8_BXA2G_SHIFT); | ||
526 | SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0); | ||
527 | SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G, | ||
528 | SSB_SPROM8_RSSISMC5G_SHIFT); | ||
529 | SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G, | ||
530 | SSB_SPROM8_RSSISAV5G_SHIFT); | ||
531 | SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G, | ||
532 | SSB_SPROM8_BXA5G_SHIFT); | ||
533 | SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0); | ||
534 | SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0); | ||
535 | SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0); | ||
536 | SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0); | ||
537 | SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0); | ||
538 | SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0); | ||
539 | SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0); | ||
540 | SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0); | ||
541 | SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0); | ||
542 | SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0); | ||
543 | SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0); | ||
544 | SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0); | ||
545 | SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0); | ||
546 | SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0); | ||
547 | SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0); | ||
548 | SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0); | ||
549 | SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0); | ||
499 | 550 | ||
500 | /* Extract the antenna gain values. */ | 551 | /* Extract the antenna gain values. */ |
501 | SPEX(antenna_gain.ghz24.a0, SSB_SPROM8_AGAIN01, | 552 | SPEX(antenna_gain.ghz24.a0, SSB_SPROM8_AGAIN01, |
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index cb3dc6027fd9..a8d71ed43a0e 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -480,10 +480,6 @@ enum nl80211_commands { | |||
480 | * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz) | 480 | * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz) |
481 | * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive | 481 | * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive |
482 | * scanning and include a zero-length SSID (wildcard) for wildcard scan | 482 | * scanning and include a zero-length SSID (wildcard) for wildcard scan |
483 | * @NL80211_ATTR_SCAN_GENERATION: the scan generation increases whenever the | ||
484 | * scan result list changes (BSS expired or added) so that applications | ||
485 | * can verify that they got a single, consistent snapshot (when all dump | ||
486 | * messages carried the same generation number) | ||
487 | * @NL80211_ATTR_BSS: scan result BSS | 483 | * @NL80211_ATTR_BSS: scan result BSS |
488 | * | 484 | * |
489 | * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain | 485 | * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain |
@@ -580,6 +576,14 @@ enum nl80211_commands { | |||
580 | * | 576 | * |
581 | * @NL80211_ATTR_PID: Process ID of a network namespace. | 577 | * @NL80211_ATTR_PID: Process ID of a network namespace. |
582 | * | 578 | * |
579 | * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for | ||
580 | * dumps. This number increases whenever the object list being | ||
581 | * dumped changes, and as such userspace can verify that it has | ||
582 | * obtained a complete and consistent snapshot by verifying that | ||
583 | * all dump messages contain the same generation number. If it | ||
584 | * changed then the list changed and the dump should be repeated | ||
585 | * completely from scratch. | ||
586 | * | ||
583 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 587 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
584 | * @__NL80211_ATTR_AFTER_LAST: internal use | 588 | * @__NL80211_ATTR_AFTER_LAST: internal use |
585 | */ | 589 | */ |
@@ -651,7 +655,7 @@ enum nl80211_attrs { | |||
651 | 655 | ||
652 | NL80211_ATTR_SCAN_FREQUENCIES, | 656 | NL80211_ATTR_SCAN_FREQUENCIES, |
653 | NL80211_ATTR_SCAN_SSIDS, | 657 | NL80211_ATTR_SCAN_SSIDS, |
654 | NL80211_ATTR_SCAN_GENERATION, | 658 | NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */ |
655 | NL80211_ATTR_BSS, | 659 | NL80211_ATTR_BSS, |
656 | 660 | ||
657 | NL80211_ATTR_REG_INITIATOR, | 661 | NL80211_ATTR_REG_INITIATOR, |
@@ -716,6 +720,9 @@ enum nl80211_attrs { | |||
716 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 | 720 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 |
717 | }; | 721 | }; |
718 | 722 | ||
723 | /* source-level API compatibility */ | ||
724 | #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION | ||
725 | |||
719 | /* | 726 | /* |
720 | * Allow user space programs to use #ifdef on new attributes by defining them | 727 | * Allow user space programs to use #ifdef on new attributes by defining them |
721 | * here | 728 | * here |
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 5ae8fa22d331..17ffc1f84d76 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h | |||
@@ -27,24 +27,54 @@ struct ssb_sprom { | |||
27 | u8 et1mdcport; /* MDIO for enet1 */ | 27 | u8 et1mdcport; /* MDIO for enet1 */ |
28 | u8 board_rev; /* Board revision number from SPROM. */ | 28 | u8 board_rev; /* Board revision number from SPROM. */ |
29 | u8 country_code; /* Country Code */ | 29 | u8 country_code; /* Country Code */ |
30 | u8 ant_available_a; /* A-PHY antenna available bits (up to 4) */ | 30 | u8 ant_available_a; /* 2GHz antenna available bits (up to 4) */ |
31 | u8 ant_available_bg; /* B/G-PHY antenna available bits (up to 4) */ | 31 | u8 ant_available_bg; /* 5GHz antenna available bits (up to 4) */ |
32 | u16 pa0b0; | 32 | u16 pa0b0; |
33 | u16 pa0b1; | 33 | u16 pa0b1; |
34 | u16 pa0b2; | 34 | u16 pa0b2; |
35 | u16 pa1b0; | 35 | u16 pa1b0; |
36 | u16 pa1b1; | 36 | u16 pa1b1; |
37 | u16 pa1b2; | 37 | u16 pa1b2; |
38 | u16 pa1lob0; | ||
39 | u16 pa1lob1; | ||
40 | u16 pa1lob2; | ||
41 | u16 pa1hib0; | ||
42 | u16 pa1hib1; | ||
43 | u16 pa1hib2; | ||
38 | u8 gpio0; /* GPIO pin 0 */ | 44 | u8 gpio0; /* GPIO pin 0 */ |
39 | u8 gpio1; /* GPIO pin 1 */ | 45 | u8 gpio1; /* GPIO pin 1 */ |
40 | u8 gpio2; /* GPIO pin 2 */ | 46 | u8 gpio2; /* GPIO pin 2 */ |
41 | u8 gpio3; /* GPIO pin 3 */ | 47 | u8 gpio3; /* GPIO pin 3 */ |
42 | u16 maxpwr_a; /* A-PHY Amplifier Max Power (in dBm Q5.2) */ | 48 | u16 maxpwr_bg; /* 2.4GHz Amplifier Max Power (in dBm Q5.2) */ |
43 | u16 maxpwr_bg; /* B/G-PHY Amplifier Max Power (in dBm Q5.2) */ | 49 | u16 maxpwr_al; /* 5.2GHz Amplifier Max Power (in dBm Q5.2) */ |
50 | u16 maxpwr_a; /* 5.3GHz Amplifier Max Power (in dBm Q5.2) */ | ||
51 | u16 maxpwr_ah; /* 5.8GHz Amplifier Max Power (in dBm Q5.2) */ | ||
44 | u8 itssi_a; /* Idle TSSI Target for A-PHY */ | 52 | u8 itssi_a; /* Idle TSSI Target for A-PHY */ |
45 | u8 itssi_bg; /* Idle TSSI Target for B/G-PHY */ | 53 | u8 itssi_bg; /* Idle TSSI Target for B/G-PHY */ |
46 | u16 boardflags_lo; /* Boardflags (low 16 bits) */ | 54 | u8 tri2g; /* 2.4GHz TX isolation */ |
47 | u16 boardflags_hi; /* Boardflags (high 16 bits) */ | 55 | u8 tri5gl; /* 5.2GHz TX isolation */ |
56 | u8 tri5g; /* 5.3GHz TX isolation */ | ||
57 | u8 tri5gh; /* 5.8GHz TX isolation */ | ||
58 | u8 rxpo2g; /* 2GHz RX power offset */ | ||
59 | u8 rxpo5g; /* 5GHz RX power offset */ | ||
60 | u8 rssisav2g; /* 2GHz RSSI params */ | ||
61 | u8 rssismc2g; | ||
62 | u8 rssismf2g; | ||
63 | u8 bxa2g; /* 2GHz BX arch */ | ||
64 | u8 rssisav5g; /* 5GHz RSSI params */ | ||
65 | u8 rssismc5g; | ||
66 | u8 rssismf5g; | ||
67 | u8 bxa5g; /* 5GHz BX arch */ | ||
68 | u16 cck2gpo; /* CCK power offset */ | ||
69 | u32 ofdm2gpo; /* 2.4GHz OFDM power offset */ | ||
70 | u32 ofdm5glpo; /* 5.2GHz OFDM power offset */ | ||
71 | u32 ofdm5gpo; /* 5.3GHz OFDM power offset */ | ||
72 | u32 ofdm5ghpo; /* 5.8GHz OFDM power offset */ | ||
73 | u16 boardflags_lo; /* Board flags (bits 0-15) */ | ||
74 | u16 boardflags_hi; /* Board flags (bits 16-31) */ | ||
75 | u16 boardflags2_lo; /* Board flags (bits 32-47) */ | ||
76 | u16 boardflags2_hi; /* Board flags (bits 48-63) */ | ||
77 | /* TODO store board flags in a single u64 */ | ||
48 | 78 | ||
49 | /* Antenna gain values for up to 4 antennas | 79 | /* Antenna gain values for up to 4 antennas |
50 | * on each band. Values in dBm/4 (Q5.2). Negative gain means the | 80 | * on each band. Values in dBm/4 (Q5.2). Negative gain means the |
@@ -58,7 +88,7 @@ struct ssb_sprom { | |||
58 | } ghz5; /* 5GHz band */ | 88 | } ghz5; /* 5GHz band */ |
59 | } antenna_gain; | 89 | } antenna_gain; |
60 | 90 | ||
61 | /* TODO - add any parameters needed from rev 2, 3, or 4 SPROMs */ | 91 | /* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */ |
62 | }; | 92 | }; |
63 | 93 | ||
64 | /* Information about the PCB the circuitry is soldered on. */ | 94 | /* Information about the PCB the circuitry is soldered on. */ |
diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index a01b982b5783..9ae9082eaeb4 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h | |||
@@ -162,7 +162,7 @@ | |||
162 | 162 | ||
163 | /* SPROM shadow area. If not otherwise noted, fields are | 163 | /* SPROM shadow area. If not otherwise noted, fields are |
164 | * two bytes wide. Note that the SPROM can _only_ be read | 164 | * two bytes wide. Note that the SPROM can _only_ be read |
165 | * in two-byte quantinies. | 165 | * in two-byte quantities. |
166 | */ | 166 | */ |
167 | #define SSB_SPROMSIZE_WORDS 64 | 167 | #define SSB_SPROMSIZE_WORDS 64 |
168 | #define SSB_SPROMSIZE_BYTES (SSB_SPROMSIZE_WORDS * sizeof(u16)) | 168 | #define SSB_SPROMSIZE_BYTES (SSB_SPROMSIZE_WORDS * sizeof(u16)) |
@@ -327,8 +327,11 @@ | |||
327 | #define SSB_SPROM5_GPIOB_P3_SHIFT 8 | 327 | #define SSB_SPROM5_GPIOB_P3_SHIFT 8 |
328 | 328 | ||
329 | /* SPROM Revision 8 */ | 329 | /* SPROM Revision 8 */ |
330 | #define SSB_SPROM8_BFLLO 0x1084 /* Boardflags (low 16 bits) */ | 330 | #define SSB_SPROM8_BOARDREV 0x1082 /* Board revision */ |
331 | #define SSB_SPROM8_BFLHI 0x1086 /* Boardflags Hi */ | 331 | #define SSB_SPROM8_BFLLO 0x1084 /* Board flags (bits 0-15) */ |
332 | #define SSB_SPROM8_BFLHI 0x1086 /* Board flags (bits 16-31) */ | ||
333 | #define SSB_SPROM8_BFL2LO 0x1088 /* Board flags (bits 32-47) */ | ||
334 | #define SSB_SPROM8_BFL2HI 0x108A /* Board flags (bits 48-63) */ | ||
332 | #define SSB_SPROM8_IL0MAC 0x108C /* 6 byte MAC address */ | 335 | #define SSB_SPROM8_IL0MAC 0x108C /* 6 byte MAC address */ |
333 | #define SSB_SPROM8_CCODE 0x1092 /* 2 byte country code */ | 336 | #define SSB_SPROM8_CCODE 0x1092 /* 2 byte country code */ |
334 | #define SSB_SPROM8_ANTAVAIL 0x109C /* Antenna available bitfields*/ | 337 | #define SSB_SPROM8_ANTAVAIL 0x109C /* Antenna available bitfields*/ |
@@ -354,14 +357,63 @@ | |||
354 | #define SSB_SPROM8_GPIOB_P2 0x00FF /* Pin 2 */ | 357 | #define SSB_SPROM8_GPIOB_P2 0x00FF /* Pin 2 */ |
355 | #define SSB_SPROM8_GPIOB_P3 0xFF00 /* Pin 3 */ | 358 | #define SSB_SPROM8_GPIOB_P3 0xFF00 /* Pin 3 */ |
356 | #define SSB_SPROM8_GPIOB_P3_SHIFT 8 | 359 | #define SSB_SPROM8_GPIOB_P3_SHIFT 8 |
357 | #define SSB_SPROM8_MAXP_BG 0x10C0 /* Max Power BG in path 1 */ | 360 | #define SSB_SPROM8_RSSIPARM2G 0x10A4 /* RSSI params for 2GHz */ |
358 | #define SSB_SPROM8_MAXP_BG_MASK 0x00FF /* Mask for Max Power BG */ | 361 | #define SSB_SPROM8_RSSISMF2G 0x000F |
362 | #define SSB_SPROM8_RSSISMC2G 0x00F0 | ||
363 | #define SSB_SPROM8_RSSISMC2G_SHIFT 4 | ||
364 | #define SSB_SPROM8_RSSISAV2G 0x0700 | ||
365 | #define SSB_SPROM8_RSSISAV2G_SHIFT 8 | ||
366 | #define SSB_SPROM8_BXA2G 0x1800 | ||
367 | #define SSB_SPROM8_BXA2G_SHIFT 11 | ||
368 | #define SSB_SPROM8_RSSIPARM5G 0x10A6 /* RSSI params for 5GHz */ | ||
369 | #define SSB_SPROM8_RSSISMF5G 0x000F | ||
370 | #define SSB_SPROM8_RSSISMC5G 0x00F0 | ||
371 | #define SSB_SPROM8_RSSISMC5G_SHIFT 4 | ||
372 | #define SSB_SPROM8_RSSISAV5G 0x0700 | ||
373 | #define SSB_SPROM8_RSSISAV5G_SHIFT 8 | ||
374 | #define SSB_SPROM8_BXA5G 0x1800 | ||
375 | #define SSB_SPROM8_BXA5G_SHIFT 11 | ||
376 | #define SSB_SPROM8_TRI25G 0x10A8 /* TX isolation 2.4&5.3GHz */ | ||
377 | #define SSB_SPROM8_TRI2G 0x00FF /* TX isolation 2.4GHz */ | ||
378 | #define SSB_SPROM8_TRI5G 0xFF00 /* TX isolation 5.3GHz */ | ||
379 | #define SSB_SPROM8_TRI5G_SHIFT 8 | ||
380 | #define SSB_SPROM8_TRI5GHL 0x10AA /* TX isolation 5.2/5.8GHz */ | ||
381 | #define SSB_SPROM8_TRI5GL 0x00FF /* TX isolation 5.2GHz */ | ||
382 | #define SSB_SPROM8_TRI5GH 0xFF00 /* TX isolation 5.8GHz */ | ||
383 | #define SSB_SPROM8_TRI5GH_SHIFT 8 | ||
384 | #define SSB_SPROM8_RXPO 0x10AC /* RX power offsets */ | ||
385 | #define SSB_SPROM8_RXPO2G 0x00FF /* 2GHz RX power offset */ | ||
386 | #define SSB_SPROM8_RXPO5G 0xFF00 /* 5GHz RX power offset */ | ||
387 | #define SSB_SPROM8_RXPO5G_SHIFT 8 | ||
388 | #define SSB_SPROM8_MAXP_BG 0x10C0 /* Max Power 2GHz in path 1 */ | ||
389 | #define SSB_SPROM8_MAXP_BG_MASK 0x00FF /* Mask for Max Power 2GHz */ | ||
359 | #define SSB_SPROM8_ITSSI_BG 0xFF00 /* Mask for path 1 itssi_bg */ | 390 | #define SSB_SPROM8_ITSSI_BG 0xFF00 /* Mask for path 1 itssi_bg */ |
360 | #define SSB_SPROM8_ITSSI_BG_SHIFT 8 | 391 | #define SSB_SPROM8_ITSSI_BG_SHIFT 8 |
361 | #define SSB_SPROM8_MAXP_A 0x10C8 /* Max Power A in path 1 */ | 392 | #define SSB_SPROM8_PA0B0 0x10C2 /* 2GHz power amp settings */ |
362 | #define SSB_SPROM8_MAXP_A_MASK 0x00FF /* Mask for Max Power A */ | 393 | #define SSB_SPROM8_PA0B1 0x10C4 |
394 | #define SSB_SPROM8_PA0B2 0x10C6 | ||
395 | #define SSB_SPROM8_MAXP_A 0x10C8 /* Max Power 5.3GHz */ | ||
396 | #define SSB_SPROM8_MAXP_A_MASK 0x00FF /* Mask for Max Power 5.3GHz */ | ||
363 | #define SSB_SPROM8_ITSSI_A 0xFF00 /* Mask for path 1 itssi_a */ | 397 | #define SSB_SPROM8_ITSSI_A 0xFF00 /* Mask for path 1 itssi_a */ |
364 | #define SSB_SPROM8_ITSSI_A_SHIFT 8 | 398 | #define SSB_SPROM8_ITSSI_A_SHIFT 8 |
399 | #define SSB_SPROM8_MAXP_AHL 0x10CA /* Max Power 5.2/5.8GHz */ | ||
400 | #define SSB_SPROM8_MAXP_AH_MASK 0x00FF /* Mask for Max Power 5.8GHz */ | ||
401 | #define SSB_SPROM8_MAXP_AL_MASK 0xFF00 /* Mask for Max Power 5.2GHz */ | ||
402 | #define SSB_SPROM8_MAXP_AL_SHIFT 8 | ||
403 | #define SSB_SPROM8_PA1B0 0x10CC /* 5.3GHz power amp settings */ | ||
404 | #define SSB_SPROM8_PA1B1 0x10CE | ||
405 | #define SSB_SPROM8_PA1B2 0x10D0 | ||
406 | #define SSB_SPROM8_PA1LOB0 0x10D2 /* 5.2GHz power amp settings */ | ||
407 | #define SSB_SPROM8_PA1LOB1 0x10D4 | ||
408 | #define SSB_SPROM8_PA1LOB2 0x10D6 | ||
409 | #define SSB_SPROM8_PA1HIB0 0x10D8 /* 5.8GHz power amp settings */ | ||
410 | #define SSB_SPROM8_PA1HIB1 0x10DA | ||
411 | #define SSB_SPROM8_PA1HIB2 0x10DC | ||
412 | #define SSB_SPROM8_CCK2GPO 0x1140 /* CCK power offset */ | ||
413 | #define SSB_SPROM8_OFDM2GPO 0x1142 /* 2.4GHz OFDM power offset */ | ||
414 | #define SSB_SPROM8_OFDM5GPO 0x1146 /* 5.3GHz OFDM power offset */ | ||
415 | #define SSB_SPROM8_OFDM5GLPO 0x114A /* 5.2GHz OFDM power offset */ | ||
416 | #define SSB_SPROM8_OFDM5GHPO 0x114E /* 5.8GHz OFDM power offset */ | ||
365 | 417 | ||
366 | /* Values for SSB_SPROM1_BINF_CCODE */ | 418 | /* Values for SSB_SPROM1_BINF_CCODE */ |
367 | enum { | 419 | enum { |
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index de8b4b18961b..09514252d84e 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h | |||
@@ -53,6 +53,7 @@ struct usbnet { | |||
53 | struct sk_buff_head rxq; | 53 | struct sk_buff_head rxq; |
54 | struct sk_buff_head txq; | 54 | struct sk_buff_head txq; |
55 | struct sk_buff_head done; | 55 | struct sk_buff_head done; |
56 | struct sk_buff_head rxq_pause; | ||
56 | struct urb *interrupt; | 57 | struct urb *interrupt; |
57 | struct tasklet_struct bh; | 58 | struct tasklet_struct bh; |
58 | 59 | ||
@@ -63,6 +64,7 @@ struct usbnet { | |||
63 | # define EVENT_RX_MEMORY 2 | 64 | # define EVENT_RX_MEMORY 2 |
64 | # define EVENT_STS_SPLIT 3 | 65 | # define EVENT_STS_SPLIT 3 |
65 | # define EVENT_LINK_RESET 4 | 66 | # define EVENT_LINK_RESET 4 |
67 | # define EVENT_RX_PAUSED 5 | ||
66 | }; | 68 | }; |
67 | 69 | ||
68 | static inline struct usb_driver *driver_of(struct usb_interface *intf) | 70 | static inline struct usb_driver *driver_of(struct usb_interface *intf) |
@@ -190,6 +192,10 @@ extern void usbnet_defer_kevent (struct usbnet *, int); | |||
190 | extern void usbnet_skb_return (struct usbnet *, struct sk_buff *); | 192 | extern void usbnet_skb_return (struct usbnet *, struct sk_buff *); |
191 | extern void usbnet_unlink_rx_urbs(struct usbnet *); | 193 | extern void usbnet_unlink_rx_urbs(struct usbnet *); |
192 | 194 | ||
195 | extern void usbnet_pause_rx(struct usbnet *); | ||
196 | extern void usbnet_resume_rx(struct usbnet *); | ||
197 | extern void usbnet_purge_paused_rxq(struct usbnet *); | ||
198 | |||
193 | extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd); | 199 | extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd); |
194 | extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd); | 200 | extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd); |
195 | extern u32 usbnet_get_link (struct net_device *net); | 201 | extern u32 usbnet_get_link (struct net_device *net); |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 64df51d9a89f..0b146bb2dd14 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -80,7 +80,6 @@ enum ieee80211_channel_flags { | |||
80 | * with cfg80211. | 80 | * with cfg80211. |
81 | * | 81 | * |
82 | * @center_freq: center frequency in MHz | 82 | * @center_freq: center frequency in MHz |
83 | * @max_bandwidth: maximum allowed bandwidth for this channel, in MHz | ||
84 | * @hw_value: hardware-specific value for the channel | 83 | * @hw_value: hardware-specific value for the channel |
85 | * @flags: channel flags from &enum ieee80211_channel_flags. | 84 | * @flags: channel flags from &enum ieee80211_channel_flags. |
86 | * @orig_flags: channel flags at registration time, used by regulatory | 85 | * @orig_flags: channel flags at registration time, used by regulatory |
@@ -97,7 +96,6 @@ enum ieee80211_channel_flags { | |||
97 | struct ieee80211_channel { | 96 | struct ieee80211_channel { |
98 | enum ieee80211_band band; | 97 | enum ieee80211_band band; |
99 | u16 center_freq; | 98 | u16 center_freq; |
100 | u8 max_bandwidth; | ||
101 | u16 hw_value; | 99 | u16 hw_value; |
102 | u32 flags; | 100 | u32 flags; |
103 | int max_antenna_gain; | 101 | int max_antenna_gain; |
@@ -372,6 +370,10 @@ struct rate_info { | |||
372 | * @txrate: current unicast bitrate to this station | 370 | * @txrate: current unicast bitrate to this station |
373 | * @rx_packets: packets received from this station | 371 | * @rx_packets: packets received from this station |
374 | * @tx_packets: packets transmitted to this station | 372 | * @tx_packets: packets transmitted to this station |
373 | * @generation: generation number for nl80211 dumps. | ||
374 | * This number should increase every time the list of stations | ||
375 | * changes, i.e. when a station is added or removed, so that | ||
376 | * userspace can tell whether it got a consistent snapshot. | ||
375 | */ | 377 | */ |
376 | struct station_info { | 378 | struct station_info { |
377 | u32 filled; | 379 | u32 filled; |
@@ -385,6 +387,8 @@ struct station_info { | |||
385 | struct rate_info txrate; | 387 | struct rate_info txrate; |
386 | u32 rx_packets; | 388 | u32 rx_packets; |
387 | u32 tx_packets; | 389 | u32 tx_packets; |
390 | |||
391 | int generation; | ||
388 | }; | 392 | }; |
389 | 393 | ||
390 | /** | 394 | /** |
@@ -444,6 +448,10 @@ enum mpath_info_flags { | |||
444 | * @flags: mesh path flags | 448 | * @flags: mesh path flags |
445 | * @discovery_timeout: total mesh path discovery timeout, in msecs | 449 | * @discovery_timeout: total mesh path discovery timeout, in msecs |
446 | * @discovery_retries: mesh path discovery retries | 450 | * @discovery_retries: mesh path discovery retries |
451 | * @generation: generation number for nl80211 dumps. | ||
452 | * This number should increase every time the list of mesh paths | ||
453 | * changes, i.e. when a station is added or removed, so that | ||
454 | * userspace can tell whether it got a consistent snapshot. | ||
447 | */ | 455 | */ |
448 | struct mpath_info { | 456 | struct mpath_info { |
449 | u32 filled; | 457 | u32 filled; |
@@ -454,6 +462,8 @@ struct mpath_info { | |||
454 | u32 discovery_timeout; | 462 | u32 discovery_timeout; |
455 | u8 discovery_retries; | 463 | u8 discovery_retries; |
456 | u8 flags; | 464 | u8 flags; |
465 | |||
466 | int generation; | ||
457 | }; | 467 | }; |
458 | 468 | ||
459 | /** | 469 | /** |
@@ -547,7 +557,6 @@ struct cfg80211_ssid { | |||
547 | struct cfg80211_scan_request { | 557 | struct cfg80211_scan_request { |
548 | struct cfg80211_ssid *ssids; | 558 | struct cfg80211_ssid *ssids; |
549 | int n_ssids; | 559 | int n_ssids; |
550 | struct ieee80211_channel **channels; | ||
551 | u32 n_channels; | 560 | u32 n_channels; |
552 | const u8 *ie; | 561 | const u8 *ie; |
553 | size_t ie_len; | 562 | size_t ie_len; |
@@ -556,6 +565,9 @@ struct cfg80211_scan_request { | |||
556 | struct wiphy *wiphy; | 565 | struct wiphy *wiphy; |
557 | struct net_device *dev; | 566 | struct net_device *dev; |
558 | bool aborted; | 567 | bool aborted; |
568 | |||
569 | /* keep last */ | ||
570 | struct ieee80211_channel *channels[0]; | ||
559 | }; | 571 | }; |
560 | 572 | ||
561 | /** | 573 | /** |
@@ -1096,6 +1108,9 @@ struct cfg80211_ops { | |||
1096 | * @net: the network namespace this wiphy currently lives in | 1108 | * @net: the network namespace this wiphy currently lives in |
1097 | * @netnsok: if set to false, do not allow changing the netns of this | 1109 | * @netnsok: if set to false, do not allow changing the netns of this |
1098 | * wiphy at all | 1110 | * wiphy at all |
1111 | * @ps_default: default for powersave, will be set depending on the | ||
1112 | * kernel's default on wiphy_new(), but can be changed by the | ||
1113 | * driver if it has a good reason to override the default | ||
1099 | */ | 1114 | */ |
1100 | struct wiphy { | 1115 | struct wiphy { |
1101 | /* assign these fields before you register the wiphy */ | 1116 | /* assign these fields before you register the wiphy */ |
@@ -1111,6 +1126,7 @@ struct wiphy { | |||
1111 | bool disable_beacon_hints; | 1126 | bool disable_beacon_hints; |
1112 | 1127 | ||
1113 | bool netnsok; | 1128 | bool netnsok; |
1129 | bool ps_default; | ||
1114 | 1130 | ||
1115 | enum cfg80211_signal_type signal_type; | 1131 | enum cfg80211_signal_type signal_type; |
1116 | 1132 | ||
@@ -1335,10 +1351,10 @@ struct wireless_dev { | |||
1335 | struct cfg80211_cached_keys *keys; | 1351 | struct cfg80211_cached_keys *keys; |
1336 | u8 *ie; | 1352 | u8 *ie; |
1337 | size_t ie_len; | 1353 | size_t ie_len; |
1338 | u8 bssid[ETH_ALEN]; | 1354 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
1339 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 1355 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
1340 | s8 default_key, default_mgmt_key; | 1356 | s8 default_key, default_mgmt_key; |
1341 | bool ps; | 1357 | bool ps, prev_bssid_valid; |
1342 | int ps_timeout; | 1358 | int ps_timeout; |
1343 | } wext; | 1359 | } wext; |
1344 | #endif | 1360 | #endif |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e2fb5767e1fa..76d43e12cc29 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -239,7 +239,14 @@ struct ieee80211_bss_conf { | |||
239 | * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU | 239 | * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU |
240 | * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211. | 240 | * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211. |
241 | * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted | 241 | * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted |
242 | * because the destination STA was in powersave mode. | 242 | * because the destination STA was in powersave mode. Note that to |
243 | * avoid race conditions, the filter must be set by the hardware or | ||
244 | * firmware upon receiving a frame that indicates that the station | ||
245 | * went to sleep (must be done on device to filter frames already on | ||
246 | * the queue) and may only be unset after mac80211 gives the OK for | ||
247 | * that by setting the IEEE80211_TX_CTL_CLEAR_PS_FILT (see above), | ||
248 | * since only then is it guaranteed that no more frames are in the | ||
249 | * hardware queue. | ||
243 | * @IEEE80211_TX_STAT_ACK: Frame was acknowledged | 250 | * @IEEE80211_TX_STAT_ACK: Frame was acknowledged |
244 | * @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status | 251 | * @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status |
245 | * is for the whole aggregation. | 252 | * is for the whole aggregation. |
@@ -261,6 +268,10 @@ struct ieee80211_bss_conf { | |||
261 | * @IEEE80211_TX_CTL_PSPOLL_RESPONSE: (internal?) | 268 | * @IEEE80211_TX_CTL_PSPOLL_RESPONSE: (internal?) |
262 | * This frame is a response to a PS-poll frame and should be sent | 269 | * This frame is a response to a PS-poll frame and should be sent |
263 | * although the station is in powersave mode. | 270 | * although the station is in powersave mode. |
271 | * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the | ||
272 | * transmit function after the current frame, this can be used | ||
273 | * by drivers to kick the DMA queue only if unset or when the | ||
274 | * queue gets full. | ||
264 | */ | 275 | */ |
265 | enum mac80211_tx_control_flags { | 276 | enum mac80211_tx_control_flags { |
266 | IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), | 277 | IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), |
@@ -281,6 +292,7 @@ enum mac80211_tx_control_flags { | |||
281 | IEEE80211_TX_INTFL_RETRIED = BIT(15), | 292 | IEEE80211_TX_INTFL_RETRIED = BIT(15), |
282 | IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), | 293 | IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), |
283 | IEEE80211_TX_CTL_PSPOLL_RESPONSE = BIT(17), | 294 | IEEE80211_TX_CTL_PSPOLL_RESPONSE = BIT(17), |
295 | IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), | ||
284 | }; | 296 | }; |
285 | 297 | ||
286 | /** | 298 | /** |
@@ -338,6 +350,21 @@ enum mac80211_rate_control_flags { | |||
338 | * | 350 | * |
339 | * When used for transmit status reporting, the driver should | 351 | * When used for transmit status reporting, the driver should |
340 | * always report the rate along with the flags it used. | 352 | * always report the rate along with the flags it used. |
353 | * | ||
354 | * &struct ieee80211_tx_info contains an array of these structs | ||
355 | * in the control information, and it will be filled by the rate | ||
356 | * control algorithm according to what should be sent. For example, | ||
357 | * if this array contains, in the format { <idx>, <count> } the | ||
358 | * information | ||
359 | * { 3, 2 }, { 2, 2 }, { 1, 4 }, { -1, 0 }, { -1, 0 } | ||
360 | * then this means that the frame should be transmitted | ||
361 | * up to twice at rate 3, up to twice at rate 2, and up to four | ||
362 | * times at rate 1 if it doesn't get acknowledged. Say it gets | ||
363 | * acknowledged by the peer after the fifth attempt, the status | ||
364 | * information should then contain | ||
365 | * { 3, 2 }, { 2, 2 }, { 1, 1 }, { -1, 0 } ... | ||
366 | * since it was transmitted twice at rate 3, twice at rate 2 | ||
367 | * and once at rate 1 after which we received an acknowledgement. | ||
341 | */ | 368 | */ |
342 | struct ieee80211_tx_rate { | 369 | struct ieee80211_tx_rate { |
343 | s8 idx; | 370 | s8 idx; |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 7dd77b6d4c9a..9db4ff836a3d 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -66,12 +66,12 @@ endmenu | |||
66 | config MAC80211_MESH | 66 | config MAC80211_MESH |
67 | bool "Enable mac80211 mesh networking (pre-802.11s) support" | 67 | bool "Enable mac80211 mesh networking (pre-802.11s) support" |
68 | depends on MAC80211 && EXPERIMENTAL | 68 | depends on MAC80211 && EXPERIMENTAL |
69 | depends on BROKEN | ||
70 | ---help--- | 69 | ---help--- |
71 | This options enables support of Draft 802.11s mesh networking. | 70 | This options enables support of Draft 802.11s mesh networking. |
72 | The implementation is based on Draft 1.08 of the Mesh Networking | 71 | The implementation is based on Draft 2.08 of the Mesh Networking |
73 | amendment. For more information visit http://o11s.org/. | 72 | amendment. However, no compliance with that draft is claimed or even |
74 | 73 | possible, as drafts leave a number of identifiers to be defined after | |
74 | ratification. For more information visit http://o11s.org/. | ||
75 | 75 | ||
76 | config MAC80211_LEDS | 76 | config MAC80211_LEDS |
77 | bool "Enable LED triggers" | 77 | bool "Enable LED triggers" |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4bbf5007799b..5608f6c68413 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -323,6 +323,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
323 | { | 323 | { |
324 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 324 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
325 | 325 | ||
326 | sinfo->generation = sdata->local->sta_generation; | ||
327 | |||
326 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | 328 | sinfo->filled = STATION_INFO_INACTIVE_TIME | |
327 | STATION_INFO_RX_BYTES | | 329 | STATION_INFO_RX_BYTES | |
328 | STATION_INFO_TX_BYTES | | 330 | STATION_INFO_TX_BYTES | |
@@ -909,6 +911,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | |||
909 | else | 911 | else |
910 | memset(next_hop, 0, ETH_ALEN); | 912 | memset(next_hop, 0, ETH_ALEN); |
911 | 913 | ||
914 | pinfo->generation = mesh_paths_generation; | ||
915 | |||
912 | pinfo->filled = MPATH_INFO_FRAME_QLEN | | 916 | pinfo->filled = MPATH_INFO_FRAME_QLEN | |
913 | MPATH_INFO_DSN | | 917 | MPATH_INFO_DSN | |
914 | MPATH_INFO_METRIC | | 918 | MPATH_INFO_METRIC | |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 630a438180fd..a6abc7dfd903 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -284,6 +284,7 @@ struct ieee80211_if_managed { | |||
284 | 284 | ||
285 | struct mutex mtx; | 285 | struct mutex mtx; |
286 | struct ieee80211_bss *associated; | 286 | struct ieee80211_bss *associated; |
287 | struct ieee80211_mgd_work *old_associate_work; | ||
287 | struct list_head work_list; | 288 | struct list_head work_list; |
288 | 289 | ||
289 | u8 bssid[ETH_ALEN]; | 290 | u8 bssid[ETH_ALEN]; |
@@ -354,7 +355,7 @@ struct ieee80211_if_mesh { | |||
354 | 355 | ||
355 | unsigned long timers_running; | 356 | unsigned long timers_running; |
356 | 357 | ||
357 | bool housekeeping; | 358 | unsigned long wrkq_flags; |
358 | 359 | ||
359 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; | 360 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; |
360 | size_t mesh_id_len; | 361 | size_t mesh_id_len; |
@@ -677,6 +678,7 @@ struct ieee80211_local { | |||
677 | struct list_head sta_list; | 678 | struct list_head sta_list; |
678 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 679 | struct sta_info *sta_hash[STA_HASH_SIZE]; |
679 | struct timer_list sta_cleanup; | 680 | struct timer_list sta_cleanup; |
681 | int sta_generation; | ||
680 | 682 | ||
681 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; | 683 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; |
682 | struct tasklet_struct tx_pending_tasklet; | 684 | struct tasklet_struct tx_pending_tasklet; |
@@ -713,7 +715,7 @@ struct ieee80211_local { | |||
713 | struct mutex scan_mtx; | 715 | struct mutex scan_mtx; |
714 | unsigned long scanning; | 716 | unsigned long scanning; |
715 | struct cfg80211_ssid scan_ssid; | 717 | struct cfg80211_ssid scan_ssid; |
716 | struct cfg80211_scan_request int_scan_req; | 718 | struct cfg80211_scan_request *int_scan_req; |
717 | struct cfg80211_scan_request *scan_req; | 719 | struct cfg80211_scan_request *scan_req; |
718 | struct ieee80211_channel *scan_channel; | 720 | struct ieee80211_channel *scan_channel; |
719 | const u8 *orig_ies; | 721 | const u8 *orig_ies; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0c4f8e122ed6..b03fd84777fa 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -765,9 +765,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
765 | supp_ht = supp_ht || sband->ht_cap.ht_supported; | 765 | supp_ht = supp_ht || sband->ht_cap.ht_supported; |
766 | } | 766 | } |
767 | 767 | ||
768 | local->int_scan_req.n_channels = channels; | 768 | local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + |
769 | local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL); | 769 | sizeof(void *) * channels, GFP_KERNEL); |
770 | if (!local->int_scan_req.channels) | 770 | if (!local->int_scan_req) |
771 | return -ENOMEM; | 771 | return -ENOMEM; |
772 | 772 | ||
773 | /* if low-level driver supports AP, we also support VLAN */ | 773 | /* if low-level driver supports AP, we also support VLAN */ |
@@ -882,13 +882,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
882 | 882 | ||
883 | /* alloc internal scan request */ | 883 | /* alloc internal scan request */ |
884 | i = 0; | 884 | i = 0; |
885 | local->int_scan_req.ssids = &local->scan_ssid; | 885 | local->int_scan_req->ssids = &local->scan_ssid; |
886 | local->int_scan_req.n_ssids = 1; | 886 | local->int_scan_req->n_ssids = 1; |
887 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 887 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
888 | if (!hw->wiphy->bands[band]) | 888 | if (!hw->wiphy->bands[band]) |
889 | continue; | 889 | continue; |
890 | for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) { | 890 | for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) { |
891 | local->int_scan_req.channels[i] = | 891 | local->int_scan_req->channels[i] = |
892 | &hw->wiphy->bands[band]->channels[j]; | 892 | &hw->wiphy->bands[band]->channels[j]; |
893 | i++; | 893 | i++; |
894 | } | 894 | } |
@@ -920,7 +920,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
920 | fail_workqueue: | 920 | fail_workqueue: |
921 | wiphy_unregister(local->hw.wiphy); | 921 | wiphy_unregister(local->hw.wiphy); |
922 | fail_wiphy_register: | 922 | fail_wiphy_register: |
923 | kfree(local->int_scan_req.channels); | 923 | kfree(local->int_scan_req->channels); |
924 | return result; | 924 | return result; |
925 | } | 925 | } |
926 | EXPORT_SYMBOL(ieee80211_register_hw); | 926 | EXPORT_SYMBOL(ieee80211_register_hw); |
@@ -962,7 +962,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
962 | wiphy_unregister(local->hw.wiphy); | 962 | wiphy_unregister(local->hw.wiphy); |
963 | ieee80211_wep_free(local); | 963 | ieee80211_wep_free(local); |
964 | ieee80211_led_exit(local); | 964 | ieee80211_led_exit(local); |
965 | kfree(local->int_scan_req.channels); | 965 | kfree(local->int_scan_req); |
966 | } | 966 | } |
967 | EXPORT_SYMBOL(ieee80211_unregister_hw); | 967 | EXPORT_SYMBOL(ieee80211_unregister_hw); |
968 | 968 | ||
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 2f4f518ab45c..3185e18c8214 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -47,14 +47,14 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) | |||
47 | struct ieee80211_local *local = sdata->local; | 47 | struct ieee80211_local *local = sdata->local; |
48 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 48 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
49 | 49 | ||
50 | ifmsh->housekeeping = true; | 50 | ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; |
51 | 51 | ||
52 | if (local->quiescing) { | 52 | if (local->quiescing) { |
53 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | 53 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); |
54 | return; | 54 | return; |
55 | } | 55 | } |
56 | 56 | ||
57 | ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); | 57 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
58 | } | 58 | } |
59 | 59 | ||
60 | /** | 60 | /** |
@@ -320,30 +320,6 @@ struct mesh_table *mesh_table_alloc(int size_order) | |||
320 | return newtbl; | 320 | return newtbl; |
321 | } | 321 | } |
322 | 322 | ||
323 | static void __mesh_table_free(struct mesh_table *tbl) | ||
324 | { | ||
325 | kfree(tbl->hash_buckets); | ||
326 | kfree(tbl->hashwlock); | ||
327 | kfree(tbl); | ||
328 | } | ||
329 | |||
330 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs) | ||
331 | { | ||
332 | struct hlist_head *mesh_hash; | ||
333 | struct hlist_node *p, *q; | ||
334 | int i; | ||
335 | |||
336 | mesh_hash = tbl->hash_buckets; | ||
337 | for (i = 0; i <= tbl->hash_mask; i++) { | ||
338 | spin_lock(&tbl->hashwlock[i]); | ||
339 | hlist_for_each_safe(p, q, &mesh_hash[i]) { | ||
340 | tbl->free_node(p, free_leafs); | ||
341 | atomic_dec(&tbl->entries); | ||
342 | } | ||
343 | spin_unlock(&tbl->hashwlock[i]); | ||
344 | } | ||
345 | __mesh_table_free(tbl); | ||
346 | } | ||
347 | 323 | ||
348 | static void ieee80211_mesh_path_timer(unsigned long data) | 324 | static void ieee80211_mesh_path_timer(unsigned long data) |
349 | { | 325 | { |
@@ -357,63 +333,79 @@ static void ieee80211_mesh_path_timer(unsigned long data) | |||
357 | return; | 333 | return; |
358 | } | 334 | } |
359 | 335 | ||
360 | ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); | 336 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
361 | } | 337 | } |
362 | 338 | ||
363 | struct mesh_table *mesh_table_grow(struct mesh_table *tbl) | 339 | /** |
364 | { | 340 | * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame |
365 | struct mesh_table *newtbl; | 341 | * @hdr: 802.11 frame header |
366 | struct hlist_head *oldhash; | 342 | * @fc: frame control field |
367 | struct hlist_node *p, *q; | 343 | * @meshda: destination address in the mesh |
368 | int i; | 344 | * @meshsa: source address address in the mesh. Same as TA, as frame is |
369 | 345 | * locally originated. | |
370 | if (atomic_read(&tbl->entries) | 346 | * |
371 | < tbl->mean_chain_len * (tbl->hash_mask + 1)) | 347 | * Return the length of the 802.11 (does not include a mesh control header) |
372 | goto endgrow; | 348 | */ |
373 | 349 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char | |
374 | newtbl = mesh_table_alloc(tbl->size_order + 1); | 350 | *meshda, char *meshsa) { |
375 | if (!newtbl) | 351 | if (is_multicast_ether_addr(meshda)) { |
376 | goto endgrow; | 352 | *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
377 | 353 | /* DA TA SA */ | |
378 | newtbl->free_node = tbl->free_node; | 354 | memcpy(hdr->addr1, meshda, ETH_ALEN); |
379 | newtbl->mean_chain_len = tbl->mean_chain_len; | 355 | memcpy(hdr->addr2, meshsa, ETH_ALEN); |
380 | newtbl->copy_node = tbl->copy_node; | 356 | memcpy(hdr->addr3, meshsa, ETH_ALEN); |
381 | atomic_set(&newtbl->entries, atomic_read(&tbl->entries)); | 357 | return 24; |
382 | 358 | } else { | |
383 | oldhash = tbl->hash_buckets; | 359 | *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | |
384 | for (i = 0; i <= tbl->hash_mask; i++) | 360 | IEEE80211_FCTL_TODS); |
385 | hlist_for_each(p, &oldhash[i]) | 361 | /* RA TA DA SA */ |
386 | if (tbl->copy_node(p, newtbl) < 0) | 362 | memset(hdr->addr1, 0, ETH_ALEN); /* RA is resolved later */ |
387 | goto errcopy; | 363 | memcpy(hdr->addr2, meshsa, ETH_ALEN); |
388 | 364 | memcpy(hdr->addr3, meshda, ETH_ALEN); | |
389 | return newtbl; | 365 | memcpy(hdr->addr4, meshsa, ETH_ALEN); |
390 | 366 | return 30; | |
391 | errcopy: | ||
392 | for (i = 0; i <= newtbl->hash_mask; i++) { | ||
393 | hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) | ||
394 | tbl->free_node(p, 0); | ||
395 | } | 367 | } |
396 | __mesh_table_free(newtbl); | ||
397 | endgrow: | ||
398 | return NULL; | ||
399 | } | 368 | } |
400 | 369 | ||
401 | /** | 370 | /** |
402 | * ieee80211_new_mesh_header - create a new mesh header | 371 | * ieee80211_new_mesh_header - create a new mesh header |
403 | * @meshhdr: uninitialized mesh header | 372 | * @meshhdr: uninitialized mesh header |
404 | * @sdata: mesh interface to be used | 373 | * @sdata: mesh interface to be used |
374 | * @addr4: addr4 of the mesh frame (1st in ae header) | ||
375 | * may be NULL | ||
376 | * @addr5: addr5 of the mesh frame (1st or 2nd in ae header) | ||
377 | * may be NULL unless addr6 is present | ||
378 | * @addr6: addr6 of the mesh frame (2nd or 3rd in ae header) | ||
379 | * may be NULL unless addr5 is present | ||
405 | * | 380 | * |
406 | * Return the header length. | 381 | * Return the header length. |
407 | */ | 382 | */ |
408 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | 383 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, |
409 | struct ieee80211_sub_if_data *sdata) | 384 | struct ieee80211_sub_if_data *sdata, char *addr4, |
385 | char *addr5, char *addr6) | ||
410 | { | 386 | { |
411 | meshhdr->flags = 0; | 387 | int aelen = 0; |
388 | memset(meshhdr, 0, sizeof(meshhdr)); | ||
412 | meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; | 389 | meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; |
413 | put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); | 390 | put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); |
414 | sdata->u.mesh.mesh_seqnum++; | 391 | sdata->u.mesh.mesh_seqnum++; |
415 | 392 | if (addr4) { | |
416 | return 6; | 393 | meshhdr->flags |= MESH_FLAGS_AE_A4; |
394 | aelen += ETH_ALEN; | ||
395 | memcpy(meshhdr->eaddr1, addr4, ETH_ALEN); | ||
396 | } | ||
397 | if (addr5 && addr6) { | ||
398 | meshhdr->flags |= MESH_FLAGS_AE_A5_A6; | ||
399 | aelen += 2 * ETH_ALEN; | ||
400 | if (!addr4) { | ||
401 | memcpy(meshhdr->eaddr1, addr5, ETH_ALEN); | ||
402 | memcpy(meshhdr->eaddr2, addr6, ETH_ALEN); | ||
403 | } else { | ||
404 | memcpy(meshhdr->eaddr2, addr5, ETH_ALEN); | ||
405 | memcpy(meshhdr->eaddr3, addr6, ETH_ALEN); | ||
406 | } | ||
407 | } | ||
408 | return 6 + aelen; | ||
417 | } | 409 | } |
418 | 410 | ||
419 | static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | 411 | static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, |
@@ -433,7 +425,6 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | |||
433 | if (free_plinks != sdata->u.mesh.accepting_plinks) | 425 | if (free_plinks != sdata->u.mesh.accepting_plinks) |
434 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 426 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); |
435 | 427 | ||
436 | ifmsh->housekeeping = false; | ||
437 | mod_timer(&ifmsh->housekeeping_timer, | 428 | mod_timer(&ifmsh->housekeeping_timer, |
438 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); | 429 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); |
439 | } | 430 | } |
@@ -470,10 +461,12 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
470 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 461 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
471 | struct ieee80211_local *local = sdata->local; | 462 | struct ieee80211_local *local = sdata->local; |
472 | 463 | ||
473 | ifmsh->housekeeping = true; | 464 | ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; |
474 | ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); | 465 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
466 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; | ||
475 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | | 467 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | |
476 | BSS_CHANGED_BEACON_ENABLED); | 468 | BSS_CHANGED_BEACON_ENABLED | |
469 | BSS_CHANGED_BEACON_INT); | ||
477 | } | 470 | } |
478 | 471 | ||
479 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | 472 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) |
@@ -608,7 +601,13 @@ static void ieee80211_mesh_work(struct work_struct *work) | |||
608 | ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval))) | 601 | ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval))) |
609 | mesh_path_start_discovery(sdata); | 602 | mesh_path_start_discovery(sdata); |
610 | 603 | ||
611 | if (ifmsh->housekeeping) | 604 | if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags)) |
605 | mesh_mpath_table_grow(); | ||
606 | |||
607 | if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags)) | ||
608 | mesh_mpp_table_grow(); | ||
609 | |||
610 | if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) | ||
612 | ieee80211_mesh_housekeeping(sdata, ifmsh); | 611 | ieee80211_mesh_housekeeping(sdata, ifmsh); |
613 | } | 612 | } |
614 | 613 | ||
@@ -619,7 +618,7 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) | |||
619 | rcu_read_lock(); | 618 | rcu_read_lock(); |
620 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | 619 | list_for_each_entry_rcu(sdata, &local->interfaces, list) |
621 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 620 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
622 | ieee80211_queue_work(local->hw.workqueue, &sdata->u.mesh.work); | 621 | ieee80211_queue_work(&local->hw, &sdata->u.mesh.work); |
623 | rcu_read_unlock(); | 622 | rcu_read_unlock(); |
624 | } | 623 | } |
625 | 624 | ||
@@ -692,7 +691,7 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
692 | case IEEE80211_STYPE_PROBE_RESP: | 691 | case IEEE80211_STYPE_PROBE_RESP: |
693 | case IEEE80211_STYPE_BEACON: | 692 | case IEEE80211_STYPE_BEACON: |
694 | skb_queue_tail(&ifmsh->skb_queue, skb); | 693 | skb_queue_tail(&ifmsh->skb_queue, skb); |
695 | ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); | 694 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
696 | return RX_QUEUED; | 695 | return RX_QUEUED; |
697 | } | 696 | } |
698 | 697 | ||
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 2a2ed182cb7e..eb23fc639b2b 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -44,6 +44,23 @@ enum mesh_path_flags { | |||
44 | }; | 44 | }; |
45 | 45 | ||
46 | /** | 46 | /** |
47 | * enum mesh_deferred_task_flags - mac80211 mesh deferred tasks | ||
48 | * | ||
49 | * | ||
50 | * | ||
51 | * @MESH_WORK_HOUSEKEEPING: run the periodic mesh housekeeping tasks | ||
52 | * @MESH_WORK_GROW_MPATH_TABLE: the mesh path table is full and needs | ||
53 | * to grow. | ||
54 | * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to | ||
55 | * grow | ||
56 | */ | ||
57 | enum mesh_deferred_task_flags { | ||
58 | MESH_WORK_HOUSEKEEPING, | ||
59 | MESH_WORK_GROW_MPATH_TABLE, | ||
60 | MESH_WORK_GROW_MPP_TABLE, | ||
61 | }; | ||
62 | |||
63 | /** | ||
47 | * struct mesh_path - mac80211 mesh path structure | 64 | * struct mesh_path - mac80211 mesh path structure |
48 | * | 65 | * |
49 | * @dst: mesh path destination mac address | 66 | * @dst: mesh path destination mac address |
@@ -61,7 +78,7 @@ enum mesh_path_flags { | |||
61 | * retry | 78 | * retry |
62 | * @discovery_retries: number of discovery retries | 79 | * @discovery_retries: number of discovery retries |
63 | * @flags: mesh path flags, as specified on &enum mesh_path_flags | 80 | * @flags: mesh path flags, as specified on &enum mesh_path_flags |
64 | * @state_lock: mesh pat state lock | 81 | * @state_lock: mesh path state lock |
65 | * | 82 | * |
66 | * | 83 | * |
67 | * The combination of dst and sdata is unique in the mesh path table. Since the | 84 | * The combination of dst and sdata is unique in the mesh path table. Since the |
@@ -174,6 +191,7 @@ struct mesh_rmc { | |||
174 | */ | 191 | */ |
175 | #define MESH_PATH_REFRESH_TIME 1000 | 192 | #define MESH_PATH_REFRESH_TIME 1000 |
176 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) | 193 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) |
194 | #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ | ||
177 | 195 | ||
178 | #define MESH_MAX_PREQ_RETRIES 4 | 196 | #define MESH_MAX_PREQ_RETRIES 4 |
179 | #define MESH_PATH_EXPIRE (600 * HZ) | 197 | #define MESH_PATH_EXPIRE (600 * HZ) |
@@ -193,8 +211,11 @@ struct mesh_rmc { | |||
193 | 211 | ||
194 | /* Public interfaces */ | 212 | /* Public interfaces */ |
195 | /* Various */ | 213 | /* Various */ |
214 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, | ||
215 | char *da, char *sa); | ||
196 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | 216 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, |
197 | struct ieee80211_sub_if_data *sdata); | 217 | struct ieee80211_sub_if_data *sdata, char *addr4, |
218 | char *addr5, char *addr6); | ||
198 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, | 219 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, |
199 | struct ieee80211_sub_if_data *sdata); | 220 | struct ieee80211_sub_if_data *sdata); |
200 | bool mesh_matches_local(struct ieee802_11_elems *ie, | 221 | bool mesh_matches_local(struct ieee802_11_elems *ie, |
@@ -246,7 +267,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
246 | /* Mesh tables */ | 267 | /* Mesh tables */ |
247 | struct mesh_table *mesh_table_alloc(int size_order); | 268 | struct mesh_table *mesh_table_alloc(int size_order); |
248 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs); | 269 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs); |
249 | struct mesh_table *mesh_table_grow(struct mesh_table *tbl); | 270 | void mesh_mpath_table_grow(void); |
271 | void mesh_mpp_table_grow(void); | ||
250 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | 272 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, |
251 | struct mesh_table *tbl); | 273 | struct mesh_table *tbl); |
252 | /* Mesh paths */ | 274 | /* Mesh paths */ |
@@ -265,6 +287,8 @@ void mesh_path_discard_frame(struct sk_buff *skb, | |||
265 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); | 287 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); |
266 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); | 288 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); |
267 | 289 | ||
290 | extern int mesh_paths_generation; | ||
291 | |||
268 | #ifdef CONFIG_MAC80211_MESH | 292 | #ifdef CONFIG_MAC80211_MESH |
269 | extern int mesh_allocated; | 293 | extern int mesh_allocated; |
270 | 294 | ||
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 11ab71a68ff9..ef1efd362691 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -397,7 +397,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
397 | 397 | ||
398 | static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | 398 | static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, |
399 | struct ieee80211_mgmt *mgmt, | 399 | struct ieee80211_mgmt *mgmt, |
400 | u8 *preq_elem, u32 metric) { | 400 | u8 *preq_elem, u32 metric) |
401 | { | ||
401 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 402 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
402 | struct mesh_path *mpath; | 403 | struct mesh_path *mpath; |
403 | u8 *dst_addr, *orig_addr; | 404 | u8 *dst_addr, *orig_addr; |
@@ -430,7 +431,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
430 | if ((!(mpath->flags & MESH_PATH_DSN_VALID)) || | 431 | if ((!(mpath->flags & MESH_PATH_DSN_VALID)) || |
431 | DSN_LT(mpath->dsn, dst_dsn)) { | 432 | DSN_LT(mpath->dsn, dst_dsn)) { |
432 | mpath->dsn = dst_dsn; | 433 | mpath->dsn = dst_dsn; |
433 | mpath->flags &= MESH_PATH_DSN_VALID; | 434 | mpath->flags |= MESH_PATH_DSN_VALID; |
434 | } else if ((!(dst_flags & MP_F_DO)) && | 435 | } else if ((!(dst_flags & MP_F_DO)) && |
435 | (mpath->flags & MESH_PATH_ACTIVE)) { | 436 | (mpath->flags & MESH_PATH_ACTIVE)) { |
436 | reply = true; | 437 | reply = true; |
@@ -660,14 +661,14 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) | |||
660 | spin_unlock(&ifmsh->mesh_preq_queue_lock); | 661 | spin_unlock(&ifmsh->mesh_preq_queue_lock); |
661 | 662 | ||
662 | if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) | 663 | if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) |
663 | ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); | 664 | ieee80211_queue_work(&sdata->local->hw, &ifmsh->work); |
664 | 665 | ||
665 | else if (time_before(jiffies, ifmsh->last_preq)) { | 666 | else if (time_before(jiffies, ifmsh->last_preq)) { |
666 | /* avoid long wait if did not send preqs for a long time | 667 | /* avoid long wait if did not send preqs for a long time |
667 | * and jiffies wrapped around | 668 | * and jiffies wrapped around |
668 | */ | 669 | */ |
669 | ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; | 670 | ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; |
670 | ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); | 671 | ieee80211_queue_work(&sdata->local->hw, &ifmsh->work); |
671 | } else | 672 | } else |
672 | mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + | 673 | mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + |
673 | min_preq_int_jiff(sdata)); | 674 | min_preq_int_jiff(sdata)); |
@@ -791,7 +792,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
791 | } | 792 | } |
792 | 793 | ||
793 | if (mpath->flags & MESH_PATH_ACTIVE) { | 794 | if (mpath->flags & MESH_PATH_ACTIVE) { |
794 | if (time_after(jiffies, mpath->exp_time - | 795 | if (time_after(jiffies, mpath->exp_time + |
795 | msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) | 796 | msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) |
796 | && !memcmp(sdata->dev->dev_addr, hdr->addr4, | 797 | && !memcmp(sdata->dev->dev_addr, hdr->addr4, |
797 | ETH_ALEN) | 798 | ETH_ALEN) |
@@ -810,10 +811,8 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
810 | } | 811 | } |
811 | 812 | ||
812 | if (skb_queue_len(&mpath->frame_queue) >= | 813 | if (skb_queue_len(&mpath->frame_queue) >= |
813 | MESH_FRAME_QUEUE_LEN) { | 814 | MESH_FRAME_QUEUE_LEN) |
814 | skb_to_free = mpath->frame_queue.next; | 815 | skb_to_free = skb_dequeue(&mpath->frame_queue); |
815 | skb_unlink(skb_to_free, &mpath->frame_queue); | ||
816 | } | ||
817 | 816 | ||
818 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 817 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
819 | skb_queue_tail(&mpath->frame_queue, skb); | 818 | skb_queue_tail(&mpath->frame_queue, skb); |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 04b9e4d61b8e..751c4d0e2b36 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -38,6 +38,71 @@ struct mpath_node { | |||
38 | static struct mesh_table *mesh_paths; | 38 | static struct mesh_table *mesh_paths; |
39 | static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ | 39 | static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ |
40 | 40 | ||
41 | int mesh_paths_generation; | ||
42 | static void __mesh_table_free(struct mesh_table *tbl) | ||
43 | { | ||
44 | kfree(tbl->hash_buckets); | ||
45 | kfree(tbl->hashwlock); | ||
46 | kfree(tbl); | ||
47 | } | ||
48 | |||
49 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs) | ||
50 | { | ||
51 | struct hlist_head *mesh_hash; | ||
52 | struct hlist_node *p, *q; | ||
53 | int i; | ||
54 | |||
55 | mesh_hash = tbl->hash_buckets; | ||
56 | for (i = 0; i <= tbl->hash_mask; i++) { | ||
57 | spin_lock(&tbl->hashwlock[i]); | ||
58 | hlist_for_each_safe(p, q, &mesh_hash[i]) { | ||
59 | tbl->free_node(p, free_leafs); | ||
60 | atomic_dec(&tbl->entries); | ||
61 | } | ||
62 | spin_unlock(&tbl->hashwlock[i]); | ||
63 | } | ||
64 | __mesh_table_free(tbl); | ||
65 | } | ||
66 | |||
67 | static struct mesh_table *mesh_table_grow(struct mesh_table *tbl) | ||
68 | { | ||
69 | struct mesh_table *newtbl; | ||
70 | struct hlist_head *oldhash; | ||
71 | struct hlist_node *p, *q; | ||
72 | int i; | ||
73 | |||
74 | if (atomic_read(&tbl->entries) | ||
75 | < tbl->mean_chain_len * (tbl->hash_mask + 1)) | ||
76 | goto endgrow; | ||
77 | |||
78 | newtbl = mesh_table_alloc(tbl->size_order + 1); | ||
79 | if (!newtbl) | ||
80 | goto endgrow; | ||
81 | |||
82 | newtbl->free_node = tbl->free_node; | ||
83 | newtbl->mean_chain_len = tbl->mean_chain_len; | ||
84 | newtbl->copy_node = tbl->copy_node; | ||
85 | atomic_set(&newtbl->entries, atomic_read(&tbl->entries)); | ||
86 | |||
87 | oldhash = tbl->hash_buckets; | ||
88 | for (i = 0; i <= tbl->hash_mask; i++) | ||
89 | hlist_for_each(p, &oldhash[i]) | ||
90 | if (tbl->copy_node(p, newtbl) < 0) | ||
91 | goto errcopy; | ||
92 | |||
93 | return newtbl; | ||
94 | |||
95 | errcopy: | ||
96 | for (i = 0; i <= newtbl->hash_mask; i++) { | ||
97 | hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) | ||
98 | tbl->free_node(p, 0); | ||
99 | } | ||
100 | __mesh_table_free(newtbl); | ||
101 | endgrow: | ||
102 | return NULL; | ||
103 | } | ||
104 | |||
105 | |||
41 | /* This lock will have the grow table function as writer and add / delete nodes | 106 | /* This lock will have the grow table function as writer and add / delete nodes |
42 | * as readers. When reading the table (i.e. doing lookups) we are well protected | 107 | * as readers. When reading the table (i.e. doing lookups) we are well protected |
43 | * by RCU | 108 | * by RCU |
@@ -185,6 +250,8 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data | |||
185 | */ | 250 | */ |
186 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | 251 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) |
187 | { | 252 | { |
253 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
254 | struct ieee80211_local *local = sdata->local; | ||
188 | struct mesh_path *mpath, *new_mpath; | 255 | struct mesh_path *mpath, *new_mpath; |
189 | struct mpath_node *node, *new_node; | 256 | struct mpath_node *node, *new_node; |
190 | struct hlist_head *bucket; | 257 | struct hlist_head *bucket; |
@@ -193,8 +260,6 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
193 | int err = 0; | 260 | int err = 0; |
194 | u32 hash_idx; | 261 | u32 hash_idx; |
195 | 262 | ||
196 | might_sleep(); | ||
197 | |||
198 | if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) | 263 | if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) |
199 | /* never add ourselves as neighbours */ | 264 | /* never add ourselves as neighbours */ |
200 | return -ENOTSUPP; | 265 | return -ENOTSUPP; |
@@ -206,11 +271,11 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
206 | return -ENOSPC; | 271 | return -ENOSPC; |
207 | 272 | ||
208 | err = -ENOMEM; | 273 | err = -ENOMEM; |
209 | new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); | 274 | new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC); |
210 | if (!new_mpath) | 275 | if (!new_mpath) |
211 | goto err_path_alloc; | 276 | goto err_path_alloc; |
212 | 277 | ||
213 | new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); | 278 | new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC); |
214 | if (!new_node) | 279 | if (!new_node) |
215 | goto err_node_alloc; | 280 | goto err_node_alloc; |
216 | 281 | ||
@@ -243,23 +308,13 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
243 | mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1)) | 308 | mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1)) |
244 | grow = 1; | 309 | grow = 1; |
245 | 310 | ||
311 | mesh_paths_generation++; | ||
312 | |||
246 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 313 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); |
247 | read_unlock(&pathtbl_resize_lock); | 314 | read_unlock(&pathtbl_resize_lock); |
248 | if (grow) { | 315 | if (grow) { |
249 | struct mesh_table *oldtbl, *newtbl; | 316 | set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); |
250 | 317 | ieee80211_queue_work(&local->hw, &ifmsh->work); | |
251 | write_lock(&pathtbl_resize_lock); | ||
252 | oldtbl = mesh_paths; | ||
253 | newtbl = mesh_table_grow(mesh_paths); | ||
254 | if (!newtbl) { | ||
255 | write_unlock(&pathtbl_resize_lock); | ||
256 | return 0; | ||
257 | } | ||
258 | rcu_assign_pointer(mesh_paths, newtbl); | ||
259 | write_unlock(&pathtbl_resize_lock); | ||
260 | |||
261 | synchronize_rcu(); | ||
262 | mesh_table_free(oldtbl, false); | ||
263 | } | 318 | } |
264 | return 0; | 319 | return 0; |
265 | 320 | ||
@@ -274,9 +329,46 @@ err_path_alloc: | |||
274 | return err; | 329 | return err; |
275 | } | 330 | } |
276 | 331 | ||
332 | void mesh_mpath_table_grow(void) | ||
333 | { | ||
334 | struct mesh_table *oldtbl, *newtbl; | ||
335 | |||
336 | write_lock(&pathtbl_resize_lock); | ||
337 | oldtbl = mesh_paths; | ||
338 | newtbl = mesh_table_grow(mesh_paths); | ||
339 | if (!newtbl) { | ||
340 | write_unlock(&pathtbl_resize_lock); | ||
341 | return; | ||
342 | } | ||
343 | rcu_assign_pointer(mesh_paths, newtbl); | ||
344 | write_unlock(&pathtbl_resize_lock); | ||
345 | |||
346 | synchronize_rcu(); | ||
347 | mesh_table_free(oldtbl, false); | ||
348 | } | ||
349 | |||
350 | void mesh_mpp_table_grow(void) | ||
351 | { | ||
352 | struct mesh_table *oldtbl, *newtbl; | ||
353 | |||
354 | write_lock(&pathtbl_resize_lock); | ||
355 | oldtbl = mpp_paths; | ||
356 | newtbl = mesh_table_grow(mpp_paths); | ||
357 | if (!newtbl) { | ||
358 | write_unlock(&pathtbl_resize_lock); | ||
359 | return; | ||
360 | } | ||
361 | rcu_assign_pointer(mpp_paths, newtbl); | ||
362 | write_unlock(&pathtbl_resize_lock); | ||
363 | |||
364 | synchronize_rcu(); | ||
365 | mesh_table_free(oldtbl, false); | ||
366 | } | ||
277 | 367 | ||
278 | int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | 368 | int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) |
279 | { | 369 | { |
370 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
371 | struct ieee80211_local *local = sdata->local; | ||
280 | struct mesh_path *mpath, *new_mpath; | 372 | struct mesh_path *mpath, *new_mpath; |
281 | struct mpath_node *node, *new_node; | 373 | struct mpath_node *node, *new_node; |
282 | struct hlist_head *bucket; | 374 | struct hlist_head *bucket; |
@@ -285,8 +377,6 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
285 | int err = 0; | 377 | int err = 0; |
286 | u32 hash_idx; | 378 | u32 hash_idx; |
287 | 379 | ||
288 | might_sleep(); | ||
289 | |||
290 | if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) | 380 | if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) |
291 | /* never add ourselves as neighbours */ | 381 | /* never add ourselves as neighbours */ |
292 | return -ENOTSUPP; | 382 | return -ENOTSUPP; |
@@ -295,11 +385,11 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
295 | return -ENOTSUPP; | 385 | return -ENOTSUPP; |
296 | 386 | ||
297 | err = -ENOMEM; | 387 | err = -ENOMEM; |
298 | new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); | 388 | new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC); |
299 | if (!new_mpath) | 389 | if (!new_mpath) |
300 | goto err_path_alloc; | 390 | goto err_path_alloc; |
301 | 391 | ||
302 | new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); | 392 | new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC); |
303 | if (!new_node) | 393 | if (!new_node) |
304 | goto err_node_alloc; | 394 | goto err_node_alloc; |
305 | 395 | ||
@@ -333,20 +423,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
333 | spin_unlock(&mpp_paths->hashwlock[hash_idx]); | 423 | spin_unlock(&mpp_paths->hashwlock[hash_idx]); |
334 | read_unlock(&pathtbl_resize_lock); | 424 | read_unlock(&pathtbl_resize_lock); |
335 | if (grow) { | 425 | if (grow) { |
336 | struct mesh_table *oldtbl, *newtbl; | 426 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); |
337 | 427 | ieee80211_queue_work(&local->hw, &ifmsh->work); | |
338 | write_lock(&pathtbl_resize_lock); | ||
339 | oldtbl = mpp_paths; | ||
340 | newtbl = mesh_table_grow(mpp_paths); | ||
341 | if (!newtbl) { | ||
342 | write_unlock(&pathtbl_resize_lock); | ||
343 | return 0; | ||
344 | } | ||
345 | rcu_assign_pointer(mpp_paths, newtbl); | ||
346 | write_unlock(&pathtbl_resize_lock); | ||
347 | |||
348 | synchronize_rcu(); | ||
349 | mesh_table_free(oldtbl, false); | ||
350 | } | 428 | } |
351 | return 0; | 429 | return 0; |
352 | 430 | ||
@@ -484,6 +562,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) | |||
484 | 562 | ||
485 | err = -ENXIO; | 563 | err = -ENXIO; |
486 | enddel: | 564 | enddel: |
565 | mesh_paths_generation++; | ||
487 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 566 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); |
488 | read_unlock(&pathtbl_resize_lock); | 567 | read_unlock(&pathtbl_resize_lock); |
489 | return err; | 568 | return err; |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index cb14253587f1..ffcbad75e09b 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -409,7 +409,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
409 | baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt; | 409 | baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt; |
410 | if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) { | 410 | if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) { |
411 | baseaddr += 4; | 411 | baseaddr += 4; |
412 | baselen -= 4; | 412 | baselen += 4; |
413 | } | 413 | } |
414 | ieee802_11_parse_elems(baseaddr, len - baselen, &elems); | 414 | ieee802_11_parse_elems(baseaddr, len - baselen, &elems); |
415 | if (!elems.peer_link) { | 415 | if (!elems.peer_link) { |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6d5a1ee0445f..c374d2d73fa4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -880,10 +880,11 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
880 | } | 880 | } |
881 | 881 | ||
882 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | 882 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, |
883 | struct ieee80211_bss *bss, | 883 | struct ieee80211_mgd_work *wk, |
884 | u32 bss_info_changed) | 884 | u32 bss_info_changed) |
885 | { | 885 | { |
886 | struct ieee80211_local *local = sdata->local; | 886 | struct ieee80211_local *local = sdata->local; |
887 | struct ieee80211_bss *bss = wk->bss; | ||
887 | 888 | ||
888 | bss_info_changed |= BSS_CHANGED_ASSOC; | 889 | bss_info_changed |= BSS_CHANGED_ASSOC; |
889 | /* set timing information */ | 890 | /* set timing information */ |
@@ -896,6 +897,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
896 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); | 897 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); |
897 | 898 | ||
898 | sdata->u.mgd.associated = bss; | 899 | sdata->u.mgd.associated = bss; |
900 | sdata->u.mgd.old_associate_work = wk; | ||
899 | memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); | 901 | memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); |
900 | 902 | ||
901 | /* just to be sure */ | 903 | /* just to be sure */ |
@@ -1010,7 +1012,8 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | |||
1010 | return RX_MGMT_NONE; | 1012 | return RX_MGMT_NONE; |
1011 | } | 1013 | } |
1012 | 1014 | ||
1013 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | 1015 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, |
1016 | bool deauth) | ||
1014 | { | 1017 | { |
1015 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1018 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1016 | struct ieee80211_local *local = sdata->local; | 1019 | struct ieee80211_local *local = sdata->local; |
@@ -1028,6 +1031,16 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | |||
1028 | ifmgd->associated = NULL; | 1031 | ifmgd->associated = NULL; |
1029 | memset(ifmgd->bssid, 0, ETH_ALEN); | 1032 | memset(ifmgd->bssid, 0, ETH_ALEN); |
1030 | 1033 | ||
1034 | if (deauth) { | ||
1035 | kfree(ifmgd->old_associate_work); | ||
1036 | ifmgd->old_associate_work = NULL; | ||
1037 | } else { | ||
1038 | struct ieee80211_mgd_work *wk = ifmgd->old_associate_work; | ||
1039 | |||
1040 | wk->state = IEEE80211_MGD_STATE_IDLE; | ||
1041 | list_add(&wk->list, &ifmgd->work_list); | ||
1042 | } | ||
1043 | |||
1031 | /* | 1044 | /* |
1032 | * we need to commit the associated = NULL change because the | 1045 | * we need to commit the associated = NULL change because the |
1033 | * scan code uses that to determine whether this iface should | 1046 | * scan code uses that to determine whether this iface should |
@@ -1345,7 +1358,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1345 | sdata->dev->name, bssid, reason_code); | 1358 | sdata->dev->name, bssid, reason_code); |
1346 | 1359 | ||
1347 | if (!wk) { | 1360 | if (!wk) { |
1348 | ieee80211_set_disassoc(sdata); | 1361 | ieee80211_set_disassoc(sdata, true); |
1349 | } else { | 1362 | } else { |
1350 | list_del(&wk->list); | 1363 | list_del(&wk->list); |
1351 | kfree(wk); | 1364 | kfree(wk); |
@@ -1378,7 +1391,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1378 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", | 1391 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", |
1379 | sdata->dev->name, reason_code); | 1392 | sdata->dev->name, reason_code); |
1380 | 1393 | ||
1381 | ieee80211_set_disassoc(sdata); | 1394 | ieee80211_set_disassoc(sdata, false); |
1382 | return RX_MGMT_CFG80211_DISASSOC; | 1395 | return RX_MGMT_CFG80211_DISASSOC; |
1383 | } | 1396 | } |
1384 | 1397 | ||
@@ -1581,7 +1594,8 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1581 | * ieee80211_set_associated() will tell the driver */ | 1594 | * ieee80211_set_associated() will tell the driver */ |
1582 | bss_conf->aid = aid; | 1595 | bss_conf->aid = aid; |
1583 | bss_conf->assoc_capability = capab_info; | 1596 | bss_conf->assoc_capability = capab_info; |
1584 | ieee80211_set_associated(sdata, wk->bss, changed); | 1597 | /* this will take ownership of wk */ |
1598 | ieee80211_set_associated(sdata, wk, changed); | ||
1585 | 1599 | ||
1586 | /* | 1600 | /* |
1587 | * Start timer to probe the connection to the AP now. | 1601 | * Start timer to probe the connection to the AP now. |
@@ -1590,7 +1604,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1590 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); | 1604 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
1591 | mod_beacon_timer(sdata); | 1605 | mod_beacon_timer(sdata); |
1592 | 1606 | ||
1593 | kfree(wk); | ||
1594 | return RX_MGMT_CFG80211_ASSOC; | 1607 | return RX_MGMT_CFG80211_ASSOC; |
1595 | } | 1608 | } |
1596 | 1609 | ||
@@ -2096,7 +2109,7 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2096 | printk(KERN_DEBUG "No probe response from AP %pM" | 2109 | printk(KERN_DEBUG "No probe response from AP %pM" |
2097 | " after %dms, disconnecting.\n", | 2110 | " after %dms, disconnecting.\n", |
2098 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 2111 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
2099 | ieee80211_set_disassoc(sdata); | 2112 | ieee80211_set_disassoc(sdata, true); |
2100 | mutex_unlock(&ifmgd->mtx); | 2113 | mutex_unlock(&ifmgd->mtx); |
2101 | /* | 2114 | /* |
2102 | * must be outside lock due to cfg80211, | 2115 | * must be outside lock due to cfg80211, |
@@ -2500,7 +2513,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2500 | 2513 | ||
2501 | if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { | 2514 | if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { |
2502 | bssid = req->bss->bssid; | 2515 | bssid = req->bss->bssid; |
2503 | ieee80211_set_disassoc(sdata); | 2516 | ieee80211_set_disassoc(sdata, true); |
2504 | } else list_for_each_entry(wk, &ifmgd->work_list, list) { | 2517 | } else list_for_each_entry(wk, &ifmgd->work_list, list) { |
2505 | if (&wk->bss->cbss == req->bss) { | 2518 | if (&wk->bss->cbss == req->bss) { |
2506 | bssid = req->bss->bssid; | 2519 | bssid = req->bss->bssid; |
@@ -2552,7 +2565,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2552 | return -ENOLINK; | 2565 | return -ENOLINK; |
2553 | } | 2566 | } |
2554 | 2567 | ||
2555 | ieee80211_set_disassoc(sdata); | 2568 | ieee80211_set_disassoc(sdata, false); |
2556 | 2569 | ||
2557 | mutex_unlock(&ifmgd->mtx); | 2570 | mutex_unlock(&ifmgd->mtx); |
2558 | 2571 | ||
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 7c5142988bbb..007164919e02 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/random.h> | 51 | #include <linux/random.h> |
52 | #include <linux/ieee80211.h> | 52 | #include <linux/ieee80211.h> |
53 | #include <net/mac80211.h> | 53 | #include <net/mac80211.h> |
54 | #include "mesh.h" | ||
54 | #include "rate.h" | 55 | #include "rate.h" |
55 | #include "rc80211_minstrel.h" | 56 | #include "rc80211_minstrel.h" |
56 | 57 | ||
@@ -155,12 +156,16 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
155 | struct sk_buff *skb) | 156 | struct sk_buff *skb) |
156 | { | 157 | { |
157 | struct minstrel_sta_info *mi = priv_sta; | 158 | struct minstrel_sta_info *mi = priv_sta; |
159 | struct minstrel_priv *mp = (struct minstrel_priv *)priv; | ||
158 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 160 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
159 | struct ieee80211_tx_rate *ar = info->status.rates; | 161 | struct ieee80211_tx_rate *ar = info->status.rates; |
162 | struct ieee80211_local *local = hw_to_local(mp->hw); | ||
163 | struct sta_info *si; | ||
160 | int i, ndx; | 164 | int i, ndx; |
161 | int success; | 165 | int success; |
162 | 166 | ||
163 | success = !!(info->flags & IEEE80211_TX_STAT_ACK); | 167 | success = !!(info->flags & IEEE80211_TX_STAT_ACK); |
168 | si = sta_info_get(local, sta->addr); | ||
164 | 169 | ||
165 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 170 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
166 | if (ar[i].idx < 0) | 171 | if (ar[i].idx < 0) |
@@ -172,8 +177,17 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
172 | 177 | ||
173 | mi->r[ndx].attempts += ar[i].count; | 178 | mi->r[ndx].attempts += ar[i].count; |
174 | 179 | ||
175 | if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) | 180 | if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) { |
176 | mi->r[ndx].success += success; | 181 | mi->r[ndx].success += success; |
182 | if (si) { | ||
183 | si->fail_avg = (18050 - mi->r[ndx].probability) | ||
184 | / 180; | ||
185 | WARN_ON(si->fail_avg > 100); | ||
186 | if (si->fail_avg == 100 && | ||
187 | ieee80211_vif_is_mesh(&si->sdata->vif)) | ||
188 | mesh_plink_broken(si); | ||
189 | } | ||
190 | } | ||
177 | } | 191 | } |
178 | 192 | ||
179 | if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0)) | 193 | if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0)) |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 25a669c86e14..4cd9e45b1443 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -489,12 +489,21 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
489 | { | 489 | { |
490 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 490 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
491 | unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); | 491 | unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); |
492 | char *dev_addr = rx->dev->dev_addr; | ||
492 | 493 | ||
493 | if (ieee80211_is_data(hdr->frame_control)) { | 494 | if (ieee80211_is_data(hdr->frame_control)) { |
494 | if (!ieee80211_has_a4(hdr->frame_control)) | 495 | if (is_multicast_ether_addr(hdr->addr1)) { |
495 | return RX_DROP_MONITOR; | 496 | if (ieee80211_has_tods(hdr->frame_control) || |
496 | if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0) | 497 | !ieee80211_has_fromds(hdr->frame_control)) |
497 | return RX_DROP_MONITOR; | 498 | return RX_DROP_MONITOR; |
499 | if (memcmp(hdr->addr3, dev_addr, ETH_ALEN) == 0) | ||
500 | return RX_DROP_MONITOR; | ||
501 | } else { | ||
502 | if (!ieee80211_has_a4(hdr->frame_control)) | ||
503 | return RX_DROP_MONITOR; | ||
504 | if (memcmp(hdr->addr4, dev_addr, ETH_ALEN) == 0) | ||
505 | return RX_DROP_MONITOR; | ||
506 | } | ||
498 | } | 507 | } |
499 | 508 | ||
500 | /* If there is not an established peer link and this is not a peer link | 509 | /* If there is not an established peer link and this is not a peer link |
@@ -527,7 +536,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
527 | 536 | ||
528 | if (ieee80211_is_data(hdr->frame_control) && | 537 | if (ieee80211_is_data(hdr->frame_control) && |
529 | is_multicast_ether_addr(hdr->addr1) && | 538 | is_multicast_ether_addr(hdr->addr1) && |
530 | mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->sdata)) | 539 | mesh_rmc_check(hdr->addr3, msh_h_get(hdr, hdrlen), rx->sdata)) |
531 | return RX_DROP_MONITOR; | 540 | return RX_DROP_MONITOR; |
532 | #undef msh_h_get | 541 | #undef msh_h_get |
533 | 542 | ||
@@ -1495,7 +1504,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1495 | /* illegal frame */ | 1504 | /* illegal frame */ |
1496 | return RX_DROP_MONITOR; | 1505 | return RX_DROP_MONITOR; |
1497 | 1506 | ||
1498 | if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){ | 1507 | if (!is_multicast_ether_addr(hdr->addr1) && |
1508 | (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6)) { | ||
1499 | struct mesh_path *mppath; | 1509 | struct mesh_path *mppath; |
1500 | 1510 | ||
1501 | rcu_read_lock(); | 1511 | rcu_read_lock(); |
@@ -1512,7 +1522,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1512 | rcu_read_unlock(); | 1522 | rcu_read_unlock(); |
1513 | } | 1523 | } |
1514 | 1524 | ||
1515 | if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) | 1525 | /* Frame has reached destination. Don't forward */ |
1526 | if (!is_multicast_ether_addr(hdr->addr1) && | ||
1527 | compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) | ||
1516 | return RX_CONTINUE; | 1528 | return RX_CONTINUE; |
1517 | 1529 | ||
1518 | mesh_hdr->ttl--; | 1530 | mesh_hdr->ttl--; |
@@ -1532,22 +1544,21 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1532 | rx->dev->name); | 1544 | rx->dev->name); |
1533 | 1545 | ||
1534 | fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; | 1546 | fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; |
1535 | /* | ||
1536 | * Save TA to addr1 to send TA a path error if a | ||
1537 | * suitable next hop is not found | ||
1538 | */ | ||
1539 | memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN); | ||
1540 | memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN); | 1547 | memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN); |
1541 | info = IEEE80211_SKB_CB(fwd_skb); | 1548 | info = IEEE80211_SKB_CB(fwd_skb); |
1542 | memset(info, 0, sizeof(*info)); | 1549 | memset(info, 0, sizeof(*info)); |
1543 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 1550 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
1544 | info->control.vif = &rx->sdata->vif; | 1551 | info->control.vif = &rx->sdata->vif; |
1545 | ieee80211_select_queue(local, fwd_skb); | 1552 | ieee80211_select_queue(local, fwd_skb); |
1546 | if (is_multicast_ether_addr(fwd_hdr->addr3)) | 1553 | if (!is_multicast_ether_addr(fwd_hdr->addr1)) { |
1547 | memcpy(fwd_hdr->addr1, fwd_hdr->addr3, | 1554 | int err; |
1555 | /* | ||
1556 | * Save TA to addr1 to send TA a path error if a | ||
1557 | * suitable next hop is not found | ||
1558 | */ | ||
1559 | memcpy(fwd_hdr->addr1, fwd_hdr->addr2, | ||
1548 | ETH_ALEN); | 1560 | ETH_ALEN); |
1549 | else { | 1561 | err = mesh_nexthop_lookup(fwd_skb, sdata); |
1550 | int err = mesh_nexthop_lookup(fwd_skb, sdata); | ||
1551 | /* Failed to immediately resolve next hop: | 1562 | /* Failed to immediately resolve next hop: |
1552 | * fwded frame was dropped or will be added | 1563 | * fwded frame was dropped or will be added |
1553 | * later to the pending skb queue. */ | 1564 | * later to the pending skb queue. */ |
@@ -1560,7 +1571,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1560 | } | 1571 | } |
1561 | } | 1572 | } |
1562 | 1573 | ||
1563 | if (is_multicast_ether_addr(hdr->addr3) || | 1574 | if (is_multicast_ether_addr(hdr->addr1) || |
1564 | rx->dev->flags & IFF_PROMISC) | 1575 | rx->dev->flags & IFF_PROMISC) |
1565 | return RX_CONTINUE; | 1576 | return RX_CONTINUE; |
1566 | else | 1577 | else |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 244f53f3c8b4..e091cbc3434f 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -277,7 +277,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
277 | if (test_bit(SCAN_HW_SCANNING, &local->scanning)) | 277 | if (test_bit(SCAN_HW_SCANNING, &local->scanning)) |
278 | ieee80211_restore_scan_ies(local); | 278 | ieee80211_restore_scan_ies(local); |
279 | 279 | ||
280 | if (local->scan_req != &local->int_scan_req) | 280 | if (local->scan_req != local->int_scan_req) |
281 | cfg80211_scan_done(local->scan_req, aborted); | 281 | cfg80211_scan_done(local->scan_req, aborted); |
282 | local->scan_req = NULL; | 282 | local->scan_req = NULL; |
283 | 283 | ||
@@ -423,7 +423,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
423 | local->scan_req = req; | 423 | local->scan_req = req; |
424 | local->scan_sdata = sdata; | 424 | local->scan_sdata = sdata; |
425 | 425 | ||
426 | if (req != &local->int_scan_req && | 426 | if (req != local->int_scan_req && |
427 | sdata->vif.type == NL80211_IFTYPE_STATION && | 427 | sdata->vif.type == NL80211_IFTYPE_STATION && |
428 | !list_empty(&ifmgd->work_list)) { | 428 | !list_empty(&ifmgd->work_list)) { |
429 | /* actually wait for the work it's doing to finish/time out */ | 429 | /* actually wait for the work it's doing to finish/time out */ |
@@ -743,10 +743,10 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | |||
743 | if (local->scan_req) | 743 | if (local->scan_req) |
744 | goto unlock; | 744 | goto unlock; |
745 | 745 | ||
746 | memcpy(local->int_scan_req.ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); | 746 | memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); |
747 | local->int_scan_req.ssids[0].ssid_len = ssid_len; | 747 | local->int_scan_req->ssids[0].ssid_len = ssid_len; |
748 | 748 | ||
749 | ret = __ieee80211_start_scan(sdata, &sdata->local->int_scan_req); | 749 | ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req); |
750 | unlock: | 750 | unlock: |
751 | mutex_unlock(&local->scan_mtx); | 751 | mutex_unlock(&local->scan_mtx); |
752 | return ret; | 752 | return ret; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a360bceeba59..eec001491e66 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -349,6 +349,7 @@ int sta_info_insert(struct sta_info *sta) | |||
349 | goto out_free; | 349 | goto out_free; |
350 | } | 350 | } |
351 | list_add(&sta->list, &local->sta_list); | 351 | list_add(&sta->list, &local->sta_list); |
352 | local->sta_generation++; | ||
352 | local->num_sta++; | 353 | local->num_sta++; |
353 | sta_info_hash_add(local, sta); | 354 | sta_info_hash_add(local, sta); |
354 | 355 | ||
@@ -485,6 +486,7 @@ static void __sta_info_unlink(struct sta_info **sta) | |||
485 | } | 486 | } |
486 | 487 | ||
487 | local->num_sta--; | 488 | local->num_sta--; |
489 | local->sta_generation++; | ||
488 | 490 | ||
489 | if (local->ops->sta_notify) { | 491 | if (local->ops->sta_notify) { |
490 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 492 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7cffaa046b33..0c08d1e60cb5 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -317,30 +317,30 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) | |||
317 | if (!atomic_read(&tx->sdata->bss->num_sta_ps)) | 317 | if (!atomic_read(&tx->sdata->bss->num_sta_ps)) |
318 | return TX_CONTINUE; | 318 | return TX_CONTINUE; |
319 | 319 | ||
320 | /* buffered in hardware */ | ||
321 | if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) { | ||
322 | info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; | ||
323 | |||
324 | return TX_CONTINUE; | ||
325 | } | ||
326 | |||
320 | /* buffered in mac80211 */ | 327 | /* buffered in mac80211 */ |
321 | if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) { | 328 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) |
322 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) | 329 | purge_old_ps_buffers(tx->local); |
323 | purge_old_ps_buffers(tx->local); | 330 | |
324 | if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= | 331 | if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) { |
325 | AP_MAX_BC_BUFFER) { | ||
326 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 332 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
327 | if (net_ratelimit()) { | 333 | if (net_ratelimit()) |
328 | printk(KERN_DEBUG "%s: BC TX buffer full - " | 334 | printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n", |
329 | "dropping the oldest frame\n", | 335 | tx->dev->name); |
330 | tx->dev->name); | ||
331 | } | ||
332 | #endif | 336 | #endif |
333 | dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); | 337 | dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); |
334 | } else | 338 | } else |
335 | tx->local->total_ps_buffered++; | 339 | tx->local->total_ps_buffered++; |
336 | skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); | ||
337 | return TX_QUEUED; | ||
338 | } | ||
339 | 340 | ||
340 | /* buffered in hardware */ | 341 | skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); |
341 | info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; | ||
342 | 342 | ||
343 | return TX_CONTINUE; | 343 | return TX_QUEUED; |
344 | } | 344 | } |
345 | 345 | ||
346 | static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, | 346 | static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, |
@@ -700,7 +700,6 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | |||
700 | /* for pure STA mode without beacons, we can do it */ | 700 | /* for pure STA mode without beacons, we can do it */ |
701 | hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number); | 701 | hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number); |
702 | tx->sdata->sequence_number += 0x10; | 702 | tx->sdata->sequence_number += 0x10; |
703 | tx->sdata->sequence_number &= IEEE80211_SCTL_SEQ; | ||
704 | return TX_CONTINUE; | 703 | return TX_CONTINUE; |
705 | } | 704 | } |
706 | 705 | ||
@@ -844,6 +843,23 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
844 | } | 843 | } |
845 | 844 | ||
846 | static ieee80211_tx_result debug_noinline | 845 | static ieee80211_tx_result debug_noinline |
846 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | ||
847 | { | ||
848 | struct sk_buff *skb = tx->skb; | ||
849 | |||
850 | if (!tx->sta) | ||
851 | return TX_CONTINUE; | ||
852 | |||
853 | tx->sta->tx_packets++; | ||
854 | do { | ||
855 | tx->sta->tx_fragments++; | ||
856 | tx->sta->tx_bytes += skb->len; | ||
857 | } while ((skb = skb->next)); | ||
858 | |||
859 | return TX_CONTINUE; | ||
860 | } | ||
861 | |||
862 | static ieee80211_tx_result debug_noinline | ||
847 | ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | 863 | ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) |
848 | { | 864 | { |
849 | if (!tx->key) | 865 | if (!tx->key) |
@@ -887,23 +903,6 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) | |||
887 | return TX_CONTINUE; | 903 | return TX_CONTINUE; |
888 | } | 904 | } |
889 | 905 | ||
890 | static ieee80211_tx_result debug_noinline | ||
891 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | ||
892 | { | ||
893 | struct sk_buff *skb = tx->skb; | ||
894 | |||
895 | if (!tx->sta) | ||
896 | return TX_CONTINUE; | ||
897 | |||
898 | tx->sta->tx_packets++; | ||
899 | do { | ||
900 | tx->sta->tx_fragments++; | ||
901 | tx->sta->tx_bytes += skb->len; | ||
902 | } while ((skb = skb->next)); | ||
903 | |||
904 | return TX_CONTINUE; | ||
905 | } | ||
906 | |||
907 | /* actual transmit path */ | 906 | /* actual transmit path */ |
908 | 907 | ||
909 | /* | 908 | /* |
@@ -1154,6 +1153,9 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
1154 | next = skb->next; | 1153 | next = skb->next; |
1155 | len = skb->len; | 1154 | len = skb->len; |
1156 | 1155 | ||
1156 | if (next) | ||
1157 | info->flags |= IEEE80211_TX_CTL_MORE_FRAMES; | ||
1158 | |||
1157 | sdata = vif_to_sdata(info->control.vif); | 1159 | sdata = vif_to_sdata(info->control.vif); |
1158 | 1160 | ||
1159 | switch (sdata->vif.type) { | 1161 | switch (sdata->vif.type) { |
@@ -1210,9 +1212,9 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1210 | CALL_TXH(ieee80211_tx_h_sequence) | 1212 | CALL_TXH(ieee80211_tx_h_sequence) |
1211 | CALL_TXH(ieee80211_tx_h_fragment) | 1213 | CALL_TXH(ieee80211_tx_h_fragment) |
1212 | /* handlers after fragment must be aware of tx info fragmentation! */ | 1214 | /* handlers after fragment must be aware of tx info fragmentation! */ |
1215 | CALL_TXH(ieee80211_tx_h_stats) | ||
1213 | CALL_TXH(ieee80211_tx_h_encrypt) | 1216 | CALL_TXH(ieee80211_tx_h_encrypt) |
1214 | CALL_TXH(ieee80211_tx_h_calculate_duration) | 1217 | CALL_TXH(ieee80211_tx_h_calculate_duration) |
1215 | CALL_TXH(ieee80211_tx_h_stats) | ||
1216 | #undef CALL_TXH | 1218 | #undef CALL_TXH |
1217 | 1219 | ||
1218 | txh_done: | 1220 | txh_done: |
@@ -1410,16 +1412,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1410 | 1412 | ||
1411 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | 1413 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; |
1412 | 1414 | ||
1413 | if (ieee80211_vif_is_mesh(&sdata->vif) && | 1415 | if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { |
1414 | ieee80211_is_data(hdr->frame_control)) { | ||
1415 | if (is_multicast_ether_addr(hdr->addr3)) | ||
1416 | memcpy(hdr->addr1, hdr->addr3, ETH_ALEN); | ||
1417 | else | ||
1418 | if (mesh_nexthop_lookup(skb, sdata)) { | ||
1419 | dev_put(sdata->dev); | ||
1420 | return; | ||
1421 | } | ||
1422 | } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { | ||
1423 | int hdrlen; | 1416 | int hdrlen; |
1424 | u16 len_rthdr; | 1417 | u16 len_rthdr; |
1425 | 1418 | ||
@@ -1476,6 +1469,15 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1476 | 1469 | ||
1477 | info->control.vif = &sdata->vif; | 1470 | info->control.vif = &sdata->vif; |
1478 | 1471 | ||
1472 | if (ieee80211_vif_is_mesh(&sdata->vif) && | ||
1473 | ieee80211_is_data(hdr->frame_control) && | ||
1474 | !is_multicast_ether_addr(hdr->addr1)) | ||
1475 | if (mesh_nexthop_lookup(skb, sdata)) { | ||
1476 | /* skb queued: don't free */ | ||
1477 | dev_put(sdata->dev); | ||
1478 | return; | ||
1479 | } | ||
1480 | |||
1479 | ieee80211_select_queue(local, skb); | 1481 | ieee80211_select_queue(local, skb); |
1480 | ieee80211_tx(sdata, skb, false); | 1482 | ieee80211_tx(sdata, skb, false); |
1481 | dev_put(sdata->dev); | 1483 | dev_put(sdata->dev); |
@@ -1617,52 +1619,58 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1617 | break; | 1619 | break; |
1618 | #ifdef CONFIG_MAC80211_MESH | 1620 | #ifdef CONFIG_MAC80211_MESH |
1619 | case NL80211_IFTYPE_MESH_POINT: | 1621 | case NL80211_IFTYPE_MESH_POINT: |
1620 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | ||
1621 | if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { | 1622 | if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { |
1622 | /* Do not send frames with mesh_ttl == 0 */ | 1623 | /* Do not send frames with mesh_ttl == 0 */ |
1623 | sdata->u.mesh.mshstats.dropped_frames_ttl++; | 1624 | sdata->u.mesh.mshstats.dropped_frames_ttl++; |
1624 | ret = NETDEV_TX_OK; | 1625 | ret = NETDEV_TX_OK; |
1625 | goto fail; | 1626 | goto fail; |
1626 | } | 1627 | } |
1627 | memset(&mesh_hdr, 0, sizeof(mesh_hdr)); | ||
1628 | 1628 | ||
1629 | if (compare_ether_addr(dev->dev_addr, | 1629 | if (compare_ether_addr(dev->dev_addr, |
1630 | skb->data + ETH_ALEN) == 0) { | 1630 | skb->data + ETH_ALEN) == 0) { |
1631 | /* RA TA DA SA */ | 1631 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, |
1632 | memset(hdr.addr1, 0, ETH_ALEN); | 1632 | skb->data, skb->data + ETH_ALEN); |
1633 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | 1633 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, |
1634 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1634 | sdata, NULL, NULL, NULL); |
1635 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
1636 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata); | ||
1637 | } else { | 1635 | } else { |
1638 | /* packet from other interface */ | 1636 | /* packet from other interface */ |
1639 | struct mesh_path *mppath; | 1637 | struct mesh_path *mppath; |
1638 | int is_mesh_mcast = 1; | ||
1639 | char *mesh_da; | ||
1640 | 1640 | ||
1641 | memset(hdr.addr1, 0, ETH_ALEN); | 1641 | rcu_read_lock(); |
1642 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
1643 | memcpy(hdr.addr4, dev->dev_addr, ETH_ALEN); | ||
1644 | |||
1645 | if (is_multicast_ether_addr(skb->data)) | 1642 | if (is_multicast_ether_addr(skb->data)) |
1646 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1643 | /* DA TA mSA AE:SA */ |
1644 | mesh_da = skb->data; | ||
1647 | else { | 1645 | else { |
1648 | rcu_read_lock(); | ||
1649 | mppath = mpp_path_lookup(skb->data, sdata); | 1646 | mppath = mpp_path_lookup(skb->data, sdata); |
1650 | if (mppath) | 1647 | if (mppath) { |
1651 | memcpy(hdr.addr3, mppath->mpp, ETH_ALEN); | 1648 | /* RA TA mDA mSA AE:DA SA */ |
1652 | else | 1649 | mesh_da = mppath->mpp; |
1653 | memset(hdr.addr3, 0xff, ETH_ALEN); | 1650 | is_mesh_mcast = 0; |
1654 | rcu_read_unlock(); | 1651 | } else |
1652 | /* DA TA mSA AE:SA */ | ||
1653 | mesh_da = dev->broadcast; | ||
1655 | } | 1654 | } |
1655 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, | ||
1656 | mesh_da, dev->dev_addr); | ||
1657 | rcu_read_unlock(); | ||
1658 | if (is_mesh_mcast) | ||
1659 | meshhdrlen = | ||
1660 | ieee80211_new_mesh_header(&mesh_hdr, | ||
1661 | sdata, | ||
1662 | skb->data + ETH_ALEN, | ||
1663 | NULL, | ||
1664 | NULL); | ||
1665 | else | ||
1666 | meshhdrlen = | ||
1667 | ieee80211_new_mesh_header(&mesh_hdr, | ||
1668 | sdata, | ||
1669 | NULL, | ||
1670 | skb->data, | ||
1671 | skb->data + ETH_ALEN); | ||
1656 | 1672 | ||
1657 | mesh_hdr.flags |= MESH_FLAGS_AE_A5_A6; | ||
1658 | mesh_hdr.ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; | ||
1659 | put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &mesh_hdr.seqnum); | ||
1660 | memcpy(mesh_hdr.eaddr1, skb->data, ETH_ALEN); | ||
1661 | memcpy(mesh_hdr.eaddr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
1662 | sdata->u.mesh.mesh_seqnum++; | ||
1663 | meshhdrlen = 18; | ||
1664 | } | 1673 | } |
1665 | hdrlen = 30; | ||
1666 | break; | 1674 | break; |
1667 | #endif | 1675 | #endif |
1668 | case NL80211_IFTYPE_STATION: | 1676 | case NL80211_IFTYPE_STATION: |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index d74cc77fa57a..3ecaa9179977 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -5,7 +5,8 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o | |||
5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o | 5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o |
6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o | 6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o |
7 | 7 | ||
8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o | 8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o |
9 | cfg80211-y += mlme.o ibss.o sme.o chan.o | ||
9 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | 10 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o |
10 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o | 11 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o |
11 | 12 | ||
diff --git a/net/wireless/chan.c b/net/wireless/chan.c new file mode 100644 index 000000000000..a46ac6c9b365 --- /dev/null +++ b/net/wireless/chan.c | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * This file contains helper code to handle channel | ||
3 | * settings and keeping track of what is possible at | ||
4 | * any point in time. | ||
5 | * | ||
6 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> | ||
7 | */ | ||
8 | |||
9 | #include <net/cfg80211.h> | ||
10 | #include "core.h" | ||
11 | |||
12 | struct ieee80211_channel * | ||
13 | rdev_fixed_channel(struct cfg80211_registered_device *rdev, | ||
14 | struct wireless_dev *for_wdev) | ||
15 | { | ||
16 | struct wireless_dev *wdev; | ||
17 | struct ieee80211_channel *result = NULL; | ||
18 | |||
19 | WARN_ON(!mutex_is_locked(&rdev->devlist_mtx)); | ||
20 | |||
21 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | ||
22 | if (wdev == for_wdev) | ||
23 | continue; | ||
24 | |||
25 | /* | ||
26 | * Lock manually to tell lockdep about allowed | ||
27 | * nesting here if for_wdev->mtx is held already. | ||
28 | * This is ok as it's all under the rdev devlist | ||
29 | * mutex and as such can only be done once at any | ||
30 | * given time. | ||
31 | */ | ||
32 | mutex_lock_nested(&wdev->mtx, SINGLE_DEPTH_NESTING); | ||
33 | if (wdev->current_bss) | ||
34 | result = wdev->current_bss->pub.channel; | ||
35 | wdev_unlock(wdev); | ||
36 | |||
37 | if (result) | ||
38 | break; | ||
39 | } | ||
40 | |||
41 | return result; | ||
42 | } | ||
43 | |||
44 | int rdev_set_freq(struct cfg80211_registered_device *rdev, | ||
45 | struct wireless_dev *for_wdev, | ||
46 | int freq, enum nl80211_channel_type channel_type) | ||
47 | { | ||
48 | struct ieee80211_channel *chan; | ||
49 | struct ieee80211_sta_ht_cap *ht_cap; | ||
50 | int result; | ||
51 | |||
52 | if (rdev_fixed_channel(rdev, for_wdev)) | ||
53 | return -EBUSY; | ||
54 | |||
55 | if (!rdev->ops->set_channel) | ||
56 | return -EOPNOTSUPP; | ||
57 | |||
58 | chan = ieee80211_get_channel(&rdev->wiphy, freq); | ||
59 | |||
60 | /* Primary channel not allowed */ | ||
61 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | ||
62 | return -EINVAL; | ||
63 | |||
64 | if (channel_type == NL80211_CHAN_HT40MINUS && | ||
65 | chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | ||
66 | return -EINVAL; | ||
67 | else if (channel_type == NL80211_CHAN_HT40PLUS && | ||
68 | chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
69 | return -EINVAL; | ||
70 | |||
71 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | ||
72 | |||
73 | if (channel_type != NL80211_CHAN_NO_HT) { | ||
74 | if (!ht_cap->ht_supported) | ||
75 | return -EINVAL; | ||
76 | |||
77 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | ||
78 | ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) | ||
79 | return -EINVAL; | ||
80 | } | ||
81 | |||
82 | result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type); | ||
83 | if (result) | ||
84 | return result; | ||
85 | |||
86 | rdev->channel = chan; | ||
87 | |||
88 | return 0; | ||
89 | } | ||
diff --git a/net/wireless/core.c b/net/wireless/core.c index 1e189306560d..bc99e4ec7463 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -32,6 +32,7 @@ MODULE_DESCRIPTION("wireless configuration support"); | |||
32 | * only read the list, and that can happen quite | 32 | * only read the list, and that can happen quite |
33 | * often because we need to do it for each command */ | 33 | * often because we need to do it for each command */ |
34 | LIST_HEAD(cfg80211_rdev_list); | 34 | LIST_HEAD(cfg80211_rdev_list); |
35 | int cfg80211_rdev_list_generation; | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * This is used to protect the cfg80211_rdev_list | 38 | * This is used to protect the cfg80211_rdev_list |
@@ -411,6 +412,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
411 | rdev->wiphy.dev.class = &ieee80211_class; | 412 | rdev->wiphy.dev.class = &ieee80211_class; |
412 | rdev->wiphy.dev.platform_data = rdev; | 413 | rdev->wiphy.dev.platform_data = rdev; |
413 | 414 | ||
415 | rdev->wiphy.ps_default = CONFIG_CFG80211_DEFAULT_PS_VALUE; | ||
416 | |||
414 | wiphy_net_set(&rdev->wiphy, &init_net); | 417 | wiphy_net_set(&rdev->wiphy, &init_net); |
415 | 418 | ||
416 | rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; | 419 | rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; |
@@ -511,6 +514,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
511 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); | 514 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); |
512 | 515 | ||
513 | list_add(&rdev->list, &cfg80211_rdev_list); | 516 | list_add(&rdev->list, &cfg80211_rdev_list); |
517 | cfg80211_rdev_list_generation++; | ||
514 | 518 | ||
515 | mutex_unlock(&cfg80211_mutex); | 519 | mutex_unlock(&cfg80211_mutex); |
516 | 520 | ||
@@ -593,13 +597,14 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
593 | reg_device_remove(wiphy); | 597 | reg_device_remove(wiphy); |
594 | 598 | ||
595 | list_del(&rdev->list); | 599 | list_del(&rdev->list); |
600 | cfg80211_rdev_list_generation++; | ||
596 | device_del(&rdev->wiphy.dev); | 601 | device_del(&rdev->wiphy.dev); |
597 | debugfs_remove(rdev->wiphy.debugfsdir); | 602 | debugfs_remove(rdev->wiphy.debugfsdir); |
598 | 603 | ||
599 | mutex_unlock(&cfg80211_mutex); | 604 | mutex_unlock(&cfg80211_mutex); |
600 | 605 | ||
606 | flush_work(&rdev->scan_done_wk); | ||
601 | cancel_work_sync(&rdev->conn_work); | 607 | cancel_work_sync(&rdev->conn_work); |
602 | cancel_work_sync(&rdev->scan_done_wk); | ||
603 | kfree(rdev->scan_req); | 608 | kfree(rdev->scan_req); |
604 | flush_work(&rdev->event_work); | 609 | flush_work(&rdev->event_work); |
605 | } | 610 | } |
@@ -653,6 +658,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
653 | spin_lock_init(&wdev->event_lock); | 658 | spin_lock_init(&wdev->event_lock); |
654 | mutex_lock(&rdev->devlist_mtx); | 659 | mutex_lock(&rdev->devlist_mtx); |
655 | list_add(&wdev->list, &rdev->netdev_list); | 660 | list_add(&wdev->list, &rdev->netdev_list); |
661 | rdev->devlist_generation++; | ||
656 | /* can only change netns with wiphy */ | 662 | /* can only change netns with wiphy */ |
657 | dev->features |= NETIF_F_NETNS_LOCAL; | 663 | dev->features |= NETIF_F_NETNS_LOCAL; |
658 | 664 | ||
@@ -670,7 +676,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
670 | wdev->wext.default_key = -1; | 676 | wdev->wext.default_key = -1; |
671 | wdev->wext.default_mgmt_key = -1; | 677 | wdev->wext.default_mgmt_key = -1; |
672 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | 678 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
673 | wdev->wext.ps = CONFIG_CFG80211_DEFAULT_PS_VALUE; | 679 | wdev->wext.ps = wdev->wiphy->ps_default; |
674 | wdev->wext.ps_timeout = 100; | 680 | wdev->wext.ps_timeout = 100; |
675 | if (rdev->ops->set_power_mgmt) | 681 | if (rdev->ops->set_power_mgmt) |
676 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, | 682 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, |
@@ -706,6 +712,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
706 | case NETDEV_UP: | 712 | case NETDEV_UP: |
707 | #ifdef CONFIG_WIRELESS_EXT | 713 | #ifdef CONFIG_WIRELESS_EXT |
708 | cfg80211_lock_rdev(rdev); | 714 | cfg80211_lock_rdev(rdev); |
715 | mutex_lock(&rdev->devlist_mtx); | ||
709 | wdev_lock(wdev); | 716 | wdev_lock(wdev); |
710 | switch (wdev->iftype) { | 717 | switch (wdev->iftype) { |
711 | case NL80211_IFTYPE_ADHOC: | 718 | case NL80211_IFTYPE_ADHOC: |
@@ -718,10 +725,18 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
718 | break; | 725 | break; |
719 | } | 726 | } |
720 | wdev_unlock(wdev); | 727 | wdev_unlock(wdev); |
728 | mutex_unlock(&rdev->devlist_mtx); | ||
721 | cfg80211_unlock_rdev(rdev); | 729 | cfg80211_unlock_rdev(rdev); |
722 | #endif | 730 | #endif |
723 | break; | 731 | break; |
724 | case NETDEV_UNREGISTER: | 732 | case NETDEV_UNREGISTER: |
733 | cfg80211_lock_rdev(rdev); | ||
734 | |||
735 | if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == dev)) { | ||
736 | rdev->scan_req->aborted = true; | ||
737 | ___cfg80211_scan_done(rdev); | ||
738 | } | ||
739 | |||
725 | mutex_lock(&rdev->devlist_mtx); | 740 | mutex_lock(&rdev->devlist_mtx); |
726 | /* | 741 | /* |
727 | * It is possible to get NETDEV_UNREGISTER | 742 | * It is possible to get NETDEV_UNREGISTER |
@@ -733,12 +748,14 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
733 | if (!list_empty(&wdev->list)) { | 748 | if (!list_empty(&wdev->list)) { |
734 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); | 749 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
735 | list_del_init(&wdev->list); | 750 | list_del_init(&wdev->list); |
751 | rdev->devlist_generation++; | ||
736 | mutex_destroy(&wdev->mtx); | 752 | mutex_destroy(&wdev->mtx); |
737 | #ifdef CONFIG_WIRELESS_EXT | 753 | #ifdef CONFIG_WIRELESS_EXT |
738 | kfree(wdev->wext.keys); | 754 | kfree(wdev->wext.keys); |
739 | #endif | 755 | #endif |
740 | } | 756 | } |
741 | mutex_unlock(&rdev->devlist_mtx); | 757 | mutex_unlock(&rdev->devlist_mtx); |
758 | cfg80211_unlock_rdev(rdev); | ||
742 | break; | 759 | break; |
743 | case NETDEV_PRE_UP: | 760 | case NETDEV_PRE_UP: |
744 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) | 761 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 325c17e6198c..c603f5286326 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -49,6 +49,7 @@ struct cfg80211_registered_device { | |||
49 | /* associate netdev list */ | 49 | /* associate netdev list */ |
50 | struct mutex devlist_mtx; | 50 | struct mutex devlist_mtx; |
51 | struct list_head netdev_list; | 51 | struct list_head netdev_list; |
52 | int devlist_generation; | ||
52 | 53 | ||
53 | /* BSSes/scanning */ | 54 | /* BSSes/scanning */ |
54 | spinlock_t bss_lock; | 55 | spinlock_t bss_lock; |
@@ -101,6 +102,7 @@ bool wiphy_idx_valid(int wiphy_idx) | |||
101 | 102 | ||
102 | extern struct mutex cfg80211_mutex; | 103 | extern struct mutex cfg80211_mutex; |
103 | extern struct list_head cfg80211_rdev_list; | 104 | extern struct list_head cfg80211_rdev_list; |
105 | extern int cfg80211_rdev_list_generation; | ||
104 | 106 | ||
105 | #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) | 107 | #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) |
106 | 108 | ||
@@ -335,7 +337,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
335 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 337 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
336 | struct net_device *dev, | 338 | struct net_device *dev, |
337 | struct cfg80211_connect_params *connect, | 339 | struct cfg80211_connect_params *connect, |
338 | struct cfg80211_cached_keys *connkeys); | 340 | struct cfg80211_cached_keys *connkeys, |
341 | const u8 *prev_bssid); | ||
339 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 342 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
340 | struct net_device *dev, | 343 | struct net_device *dev, |
341 | struct cfg80211_connect_params *connect, | 344 | struct cfg80211_connect_params *connect, |
@@ -353,6 +356,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
353 | struct wireless_dev *wdev); | 356 | struct wireless_dev *wdev); |
354 | 357 | ||
355 | void cfg80211_conn_work(struct work_struct *work); | 358 | void cfg80211_conn_work(struct work_struct *work); |
359 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); | ||
356 | 360 | ||
357 | /* internal helpers */ | 361 | /* internal helpers */ |
358 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 362 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
@@ -364,6 +368,14 @@ void cfg80211_sme_scan_done(struct net_device *dev); | |||
364 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | 368 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); |
365 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); | 369 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); |
366 | void __cfg80211_scan_done(struct work_struct *wk); | 370 | void __cfg80211_scan_done(struct work_struct *wk); |
371 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev); | ||
367 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); | 372 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); |
368 | 373 | ||
374 | struct ieee80211_channel * | ||
375 | rdev_fixed_channel(struct cfg80211_registered_device *rdev, | ||
376 | struct wireless_dev *for_wdev); | ||
377 | int rdev_set_freq(struct cfg80211_registered_device *rdev, | ||
378 | struct wireless_dev *for_wdev, | ||
379 | int freq, enum nl80211_channel_type channel_type); | ||
380 | |||
369 | #endif /* __NET_WIRELESS_CORE_H */ | 381 | #endif /* __NET_WIRELESS_CORE_H */ |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 4d7a084b35e2..42840a01be74 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -78,10 +78,15 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
78 | struct cfg80211_cached_keys *connkeys) | 78 | struct cfg80211_cached_keys *connkeys) |
79 | { | 79 | { |
80 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 80 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
81 | struct ieee80211_channel *chan; | ||
81 | int err; | 82 | int err; |
82 | 83 | ||
83 | ASSERT_WDEV_LOCK(wdev); | 84 | ASSERT_WDEV_LOCK(wdev); |
84 | 85 | ||
86 | chan = rdev_fixed_channel(rdev, wdev); | ||
87 | if (chan && chan != params->channel) | ||
88 | return -EBUSY; | ||
89 | |||
85 | if (wdev->ssid_len) | 90 | if (wdev->ssid_len) |
86 | return -EALREADY; | 91 | return -EALREADY; |
87 | 92 | ||
@@ -112,9 +117,11 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
112 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 117 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
113 | int err; | 118 | int err; |
114 | 119 | ||
120 | mutex_lock(&rdev->devlist_mtx); | ||
115 | wdev_lock(wdev); | 121 | wdev_lock(wdev); |
116 | err = __cfg80211_join_ibss(rdev, dev, params, connkeys); | 122 | err = __cfg80211_join_ibss(rdev, dev, params, connkeys); |
117 | wdev_unlock(wdev); | 123 | wdev_unlock(wdev); |
124 | mutex_unlock(&rdev->devlist_mtx); | ||
118 | 125 | ||
119 | return err; | 126 | return err; |
120 | } | 127 | } |
@@ -264,27 +271,32 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | |||
264 | 271 | ||
265 | int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | 272 | int cfg80211_ibss_wext_siwfreq(struct net_device *dev, |
266 | struct iw_request_info *info, | 273 | struct iw_request_info *info, |
267 | struct iw_freq *freq, char *extra) | 274 | struct iw_freq *wextfreq, char *extra) |
268 | { | 275 | { |
269 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 276 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
270 | struct ieee80211_channel *chan; | 277 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
271 | int err; | 278 | struct ieee80211_channel *chan = NULL; |
279 | int err, freq; | ||
272 | 280 | ||
273 | /* call only for ibss! */ | 281 | /* call only for ibss! */ |
274 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) | 282 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) |
275 | return -EINVAL; | 283 | return -EINVAL; |
276 | 284 | ||
277 | if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) | 285 | if (!rdev->ops->join_ibss) |
278 | return -EOPNOTSUPP; | 286 | return -EOPNOTSUPP; |
279 | 287 | ||
280 | chan = cfg80211_wext_freq(wdev->wiphy, freq); | 288 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); |
281 | if (chan && IS_ERR(chan)) | 289 | if (freq < 0) |
282 | return PTR_ERR(chan); | 290 | return freq; |
283 | 291 | ||
284 | if (chan && | 292 | if (freq) { |
285 | (chan->flags & IEEE80211_CHAN_NO_IBSS || | 293 | chan = ieee80211_get_channel(wdev->wiphy, freq); |
286 | chan->flags & IEEE80211_CHAN_DISABLED)) | 294 | if (!chan) |
287 | return -EINVAL; | 295 | return -EINVAL; |
296 | if (chan->flags & IEEE80211_CHAN_NO_IBSS || | ||
297 | chan->flags & IEEE80211_CHAN_DISABLED) | ||
298 | return -EINVAL; | ||
299 | } | ||
288 | 300 | ||
289 | if (wdev->wext.ibss.channel == chan) | 301 | if (wdev->wext.ibss.channel == chan) |
290 | return 0; | 302 | return 0; |
@@ -292,8 +304,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | |||
292 | wdev_lock(wdev); | 304 | wdev_lock(wdev); |
293 | err = 0; | 305 | err = 0; |
294 | if (wdev->ssid_len) | 306 | if (wdev->ssid_len) |
295 | err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), | 307 | err = __cfg80211_leave_ibss(rdev, dev, true); |
296 | dev, true); | ||
297 | wdev_unlock(wdev); | 308 | wdev_unlock(wdev); |
298 | 309 | ||
299 | if (err) | 310 | if (err) |
@@ -307,9 +318,11 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | |||
307 | wdev->wext.ibss.channel_fixed = false; | 318 | wdev->wext.ibss.channel_fixed = false; |
308 | } | 319 | } |
309 | 320 | ||
321 | mutex_lock(&rdev->devlist_mtx); | ||
310 | wdev_lock(wdev); | 322 | wdev_lock(wdev); |
311 | err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); | 323 | err = cfg80211_ibss_wext_join(rdev, wdev); |
312 | wdev_unlock(wdev); | 324 | wdev_unlock(wdev); |
325 | mutex_unlock(&rdev->devlist_mtx); | ||
313 | 326 | ||
314 | return err; | 327 | return err; |
315 | } | 328 | } |
@@ -347,6 +360,7 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, | |||
347 | struct iw_point *data, char *ssid) | 360 | struct iw_point *data, char *ssid) |
348 | { | 361 | { |
349 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 362 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
363 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
350 | size_t len = data->length; | 364 | size_t len = data->length; |
351 | int err; | 365 | int err; |
352 | 366 | ||
@@ -354,14 +368,13 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, | |||
354 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) | 368 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) |
355 | return -EINVAL; | 369 | return -EINVAL; |
356 | 370 | ||
357 | if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) | 371 | if (!rdev->ops->join_ibss) |
358 | return -EOPNOTSUPP; | 372 | return -EOPNOTSUPP; |
359 | 373 | ||
360 | wdev_lock(wdev); | 374 | wdev_lock(wdev); |
361 | err = 0; | 375 | err = 0; |
362 | if (wdev->ssid_len) | 376 | if (wdev->ssid_len) |
363 | err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), | 377 | err = __cfg80211_leave_ibss(rdev, dev, true); |
364 | dev, true); | ||
365 | wdev_unlock(wdev); | 378 | wdev_unlock(wdev); |
366 | 379 | ||
367 | if (err) | 380 | if (err) |
@@ -375,9 +388,11 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, | |||
375 | memcpy(wdev->wext.ibss.ssid, ssid, len); | 388 | memcpy(wdev->wext.ibss.ssid, ssid, len); |
376 | wdev->wext.ibss.ssid_len = len; | 389 | wdev->wext.ibss.ssid_len = len; |
377 | 390 | ||
391 | mutex_lock(&rdev->devlist_mtx); | ||
378 | wdev_lock(wdev); | 392 | wdev_lock(wdev); |
379 | err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); | 393 | err = cfg80211_ibss_wext_join(rdev, wdev); |
380 | wdev_unlock(wdev); | 394 | wdev_unlock(wdev); |
395 | mutex_unlock(&rdev->devlist_mtx); | ||
381 | 396 | ||
382 | return err; | 397 | return err; |
383 | } | 398 | } |
@@ -414,6 +429,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, | |||
414 | struct sockaddr *ap_addr, char *extra) | 429 | struct sockaddr *ap_addr, char *extra) |
415 | { | 430 | { |
416 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 431 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
432 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
417 | u8 *bssid = ap_addr->sa_data; | 433 | u8 *bssid = ap_addr->sa_data; |
418 | int err; | 434 | int err; |
419 | 435 | ||
@@ -421,7 +437,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, | |||
421 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) | 437 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) |
422 | return -EINVAL; | 438 | return -EINVAL; |
423 | 439 | ||
424 | if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) | 440 | if (!rdev->ops->join_ibss) |
425 | return -EOPNOTSUPP; | 441 | return -EOPNOTSUPP; |
426 | 442 | ||
427 | if (ap_addr->sa_family != ARPHRD_ETHER) | 443 | if (ap_addr->sa_family != ARPHRD_ETHER) |
@@ -443,8 +459,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, | |||
443 | wdev_lock(wdev); | 459 | wdev_lock(wdev); |
444 | err = 0; | 460 | err = 0; |
445 | if (wdev->ssid_len) | 461 | if (wdev->ssid_len) |
446 | err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), | 462 | err = __cfg80211_leave_ibss(rdev, dev, true); |
447 | dev, true); | ||
448 | wdev_unlock(wdev); | 463 | wdev_unlock(wdev); |
449 | 464 | ||
450 | if (err) | 465 | if (err) |
@@ -456,9 +471,11 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, | |||
456 | } else | 471 | } else |
457 | wdev->wext.ibss.bssid = NULL; | 472 | wdev->wext.ibss.bssid = NULL; |
458 | 473 | ||
474 | mutex_lock(&rdev->devlist_mtx); | ||
459 | wdev_lock(wdev); | 475 | wdev_lock(wdev); |
460 | err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); | 476 | err = cfg80211_ibss_wext_join(rdev, wdev); |
461 | wdev_unlock(wdev); | 477 | wdev_unlock(wdev); |
478 | mutex_unlock(&rdev->devlist_mtx); | ||
462 | 479 | ||
463 | return err; | 480 | return err; |
464 | } | 481 | } |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 525e8e247b30..da64071ceb84 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -67,6 +67,16 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
67 | 67 | ||
68 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 68 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
69 | 69 | ||
70 | /* | ||
71 | * This is a bit of a hack, we don't notify userspace of | ||
72 | * a (re-)association reply if we tried to send a reassoc | ||
73 | * and got a reject -- we only try again with an assoc | ||
74 | * frame instead of reassoc. | ||
75 | */ | ||
76 | if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && | ||
77 | cfg80211_sme_failed_reassoc(wdev)) | ||
78 | goto out; | ||
79 | |||
70 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); | 80 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); |
71 | 81 | ||
72 | if (status_code == WLAN_STATUS_SUCCESS) { | 82 | if (status_code == WLAN_STATUS_SUCCESS) { |
@@ -97,6 +107,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
97 | cfg80211_put_bss(&bss->pub); | 107 | cfg80211_put_bss(&bss->pub); |
98 | } | 108 | } |
99 | 109 | ||
110 | out: | ||
100 | wdev_unlock(wdev); | 111 | wdev_unlock(wdev); |
101 | } | 112 | } |
102 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | 113 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); |
@@ -149,7 +160,7 @@ static void __cfg80211_send_deauth(struct net_device *dev, | |||
149 | 160 | ||
150 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 161 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
151 | 162 | ||
152 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; | 163 | from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; |
153 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); | 164 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); |
154 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { | 165 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { |
155 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | 166 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, |
@@ -198,7 +209,7 @@ static void __cfg80211_send_disassoc(struct net_device *dev, | |||
198 | return; | 209 | return; |
199 | 210 | ||
200 | if (wdev->current_bss && | 211 | if (wdev->current_bss && |
201 | memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) { | 212 | memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { |
202 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | 213 | for (i = 0; i < MAX_AUTH_BSSES; i++) { |
203 | if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) | 214 | if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) |
204 | continue; | 215 | continue; |
@@ -215,7 +226,7 @@ static void __cfg80211_send_disassoc(struct net_device *dev, | |||
215 | 226 | ||
216 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 227 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
217 | 228 | ||
218 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; | 229 | from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; |
219 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); | 230 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); |
220 | } | 231 | } |
221 | 232 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0cd548267d4a..a8aaadeb6773 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -408,6 +408,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
408 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); | 408 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); |
409 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); | 409 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); |
410 | 410 | ||
411 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, | ||
412 | cfg80211_rdev_list_generation); | ||
413 | |||
411 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | 414 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, |
412 | dev->wiphy.retry_short); | 415 | dev->wiphy.retry_short); |
413 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, | 416 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, |
@@ -701,15 +704,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
701 | 704 | ||
702 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 705 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
703 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 706 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
704 | struct ieee80211_channel *chan; | ||
705 | struct ieee80211_sta_ht_cap *ht_cap; | ||
706 | u32 freq; | 707 | u32 freq; |
707 | 708 | ||
708 | if (!rdev->ops->set_channel) { | ||
709 | result = -EOPNOTSUPP; | ||
710 | goto bad_res; | ||
711 | } | ||
712 | |||
713 | result = -EINVAL; | 709 | result = -EINVAL; |
714 | 710 | ||
715 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 711 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
@@ -723,42 +719,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
723 | } | 719 | } |
724 | 720 | ||
725 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 721 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
726 | chan = ieee80211_get_channel(&rdev->wiphy, freq); | ||
727 | |||
728 | /* Primary channel not allowed */ | ||
729 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | ||
730 | goto bad_res; | ||
731 | |||
732 | if (channel_type == NL80211_CHAN_HT40MINUS && | ||
733 | (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)) | ||
734 | goto bad_res; | ||
735 | else if (channel_type == NL80211_CHAN_HT40PLUS && | ||
736 | (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)) | ||
737 | goto bad_res; | ||
738 | |||
739 | /* | ||
740 | * At this point we know if that if HT40 was requested | ||
741 | * we are allowed to use it and the extension channel | ||
742 | * exists. | ||
743 | */ | ||
744 | |||
745 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | ||
746 | |||
747 | /* no HT capabilities or intolerant */ | ||
748 | if (channel_type != NL80211_CHAN_NO_HT) { | ||
749 | if (!ht_cap->ht_supported) | ||
750 | goto bad_res; | ||
751 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | ||
752 | (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) | ||
753 | goto bad_res; | ||
754 | } | ||
755 | 722 | ||
756 | result = rdev->ops->set_channel(&rdev->wiphy, chan, | 723 | mutex_lock(&rdev->devlist_mtx); |
757 | channel_type); | 724 | result = rdev_set_freq(rdev, NULL, freq, channel_type); |
725 | mutex_unlock(&rdev->devlist_mtx); | ||
758 | if (result) | 726 | if (result) |
759 | goto bad_res; | 727 | goto bad_res; |
760 | |||
761 | rdev->channel = chan; | ||
762 | } | 728 | } |
763 | 729 | ||
764 | changed = 0; | 730 | changed = 0; |
@@ -862,6 +828,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
862 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 828 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
863 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); | 829 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); |
864 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); | 830 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); |
831 | |||
832 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, | ||
833 | rdev->devlist_generation ^ | ||
834 | (cfg80211_rdev_list_generation << 2)); | ||
835 | |||
865 | return genlmsg_end(msg, hdr); | 836 | return genlmsg_end(msg, hdr); |
866 | 837 | ||
867 | nla_put_failure: | 838 | nla_put_failure: |
@@ -875,12 +846,12 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
875 | int if_idx = 0; | 846 | int if_idx = 0; |
876 | int wp_start = cb->args[0]; | 847 | int wp_start = cb->args[0]; |
877 | int if_start = cb->args[1]; | 848 | int if_start = cb->args[1]; |
878 | struct cfg80211_registered_device *dev; | 849 | struct cfg80211_registered_device *rdev; |
879 | struct wireless_dev *wdev; | 850 | struct wireless_dev *wdev; |
880 | 851 | ||
881 | mutex_lock(&cfg80211_mutex); | 852 | mutex_lock(&cfg80211_mutex); |
882 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 853 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
883 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | 854 | if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) |
884 | continue; | 855 | continue; |
885 | if (wp_idx < wp_start) { | 856 | if (wp_idx < wp_start) { |
886 | wp_idx++; | 857 | wp_idx++; |
@@ -888,21 +859,21 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
888 | } | 859 | } |
889 | if_idx = 0; | 860 | if_idx = 0; |
890 | 861 | ||
891 | mutex_lock(&dev->devlist_mtx); | 862 | mutex_lock(&rdev->devlist_mtx); |
892 | list_for_each_entry(wdev, &dev->netdev_list, list) { | 863 | list_for_each_entry(wdev, &rdev->netdev_list, list) { |
893 | if (if_idx < if_start) { | 864 | if (if_idx < if_start) { |
894 | if_idx++; | 865 | if_idx++; |
895 | continue; | 866 | continue; |
896 | } | 867 | } |
897 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, | 868 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, |
898 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 869 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
899 | dev, wdev->netdev) < 0) { | 870 | rdev, wdev->netdev) < 0) { |
900 | mutex_unlock(&dev->devlist_mtx); | 871 | mutex_unlock(&rdev->devlist_mtx); |
901 | goto out; | 872 | goto out; |
902 | } | 873 | } |
903 | if_idx++; | 874 | if_idx++; |
904 | } | 875 | } |
905 | mutex_unlock(&dev->devlist_mtx); | 876 | mutex_unlock(&rdev->devlist_mtx); |
906 | 877 | ||
907 | wp_idx++; | 878 | wp_idx++; |
908 | } | 879 | } |
@@ -1653,6 +1624,8 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
1653 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 1624 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
1654 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 1625 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
1655 | 1626 | ||
1627 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, sinfo->generation); | ||
1628 | |||
1656 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); | 1629 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); |
1657 | if (!sinfoattr) | 1630 | if (!sinfoattr) |
1658 | goto nla_put_failure; | 1631 | goto nla_put_failure; |
@@ -2138,6 +2111,8 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | |||
2138 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); | 2111 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); |
2139 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); | 2112 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); |
2140 | 2113 | ||
2114 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, pinfo->generation); | ||
2115 | |||
2141 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); | 2116 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); |
2142 | if (!pinfoattr) | 2117 | if (!pinfoattr) |
2143 | goto nla_put_failure; | 2118 | goto nla_put_failure; |
@@ -3027,10 +3002,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3027 | goto out; | 3002 | goto out; |
3028 | } | 3003 | } |
3029 | 3004 | ||
3030 | request->channels = (void *)((char *)request + sizeof(*request)); | ||
3031 | request->n_channels = n_channels; | 3005 | request->n_channels = n_channels; |
3032 | if (n_ssids) | 3006 | if (n_ssids) |
3033 | request->ssids = (void *)(request->channels + n_channels); | 3007 | request->ssids = (void *)&request->channels[n_channels]; |
3034 | request->n_ssids = n_ssids; | 3008 | request->n_ssids = n_ssids; |
3035 | if (ie_len) { | 3009 | if (ie_len) { |
3036 | if (request->ssids) | 3010 | if (request->ssids) |
@@ -3127,8 +3101,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
3127 | if (!hdr) | 3101 | if (!hdr) |
3128 | return -1; | 3102 | return -1; |
3129 | 3103 | ||
3130 | NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION, | 3104 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation); |
3131 | rdev->bss_generation); | ||
3132 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); | 3105 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); |
3133 | 3106 | ||
3134 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); | 3107 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); |
@@ -3453,7 +3426,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3453 | struct cfg80211_registered_device *rdev; | 3426 | struct cfg80211_registered_device *rdev; |
3454 | struct net_device *dev; | 3427 | struct net_device *dev; |
3455 | struct cfg80211_crypto_settings crypto; | 3428 | struct cfg80211_crypto_settings crypto; |
3456 | struct ieee80211_channel *chan; | 3429 | struct ieee80211_channel *chan, *fixedchan; |
3457 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 3430 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; |
3458 | int err, ssid_len, ie_len = 0; | 3431 | int err, ssid_len, ie_len = 0; |
3459 | bool use_mfp = false; | 3432 | bool use_mfp = false; |
@@ -3496,6 +3469,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3496 | goto out; | 3469 | goto out; |
3497 | } | 3470 | } |
3498 | 3471 | ||
3472 | mutex_lock(&rdev->devlist_mtx); | ||
3473 | fixedchan = rdev_fixed_channel(rdev, NULL); | ||
3474 | if (fixedchan && chan != fixedchan) { | ||
3475 | err = -EBUSY; | ||
3476 | mutex_unlock(&rdev->devlist_mtx); | ||
3477 | goto out; | ||
3478 | } | ||
3479 | mutex_unlock(&rdev->devlist_mtx); | ||
3480 | |||
3499 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3481 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3500 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3482 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
3501 | 3483 | ||
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 0f61ae613f3b..f256dfffbf46 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -1018,7 +1018,6 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
1018 | map_regdom_flags(reg_rule->flags) | bw_flags; | 1018 | map_regdom_flags(reg_rule->flags) | bw_flags; |
1019 | chan->max_antenna_gain = chan->orig_mag = | 1019 | chan->max_antenna_gain = chan->orig_mag = |
1020 | (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1020 | (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
1021 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); | ||
1022 | chan->max_power = chan->orig_mpwr = | 1021 | chan->max_power = chan->orig_mpwr = |
1023 | (int) MBM_TO_DBM(power_rule->max_eirp); | 1022 | (int) MBM_TO_DBM(power_rule->max_eirp); |
1024 | return; | 1023 | return; |
@@ -1027,7 +1026,6 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
1027 | chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); | 1026 | chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); |
1028 | chan->max_antenna_gain = min(chan->orig_mag, | 1027 | chan->max_antenna_gain = min(chan->orig_mag, |
1029 | (int) MBI_TO_DBI(power_rule->max_antenna_gain)); | 1028 | (int) MBI_TO_DBI(power_rule->max_antenna_gain)); |
1030 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); | ||
1031 | if (chan->orig_mpwr) | 1029 | if (chan->orig_mpwr) |
1032 | chan->max_power = min(chan->orig_mpwr, | 1030 | chan->max_power = min(chan->orig_mpwr, |
1033 | (int) MBM_TO_DBM(power_rule->max_eirp)); | 1031 | (int) MBM_TO_DBM(power_rule->max_eirp)); |
@@ -1329,7 +1327,6 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1329 | 1327 | ||
1330 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | 1328 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; |
1331 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1329 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
1332 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); | ||
1333 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); | 1330 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); |
1334 | } | 1331 | } |
1335 | 1332 | ||
@@ -1427,7 +1424,7 @@ static int ignore_request(struct wiphy *wiphy, | |||
1427 | if (last_wiphy != wiphy) { | 1424 | if (last_wiphy != wiphy) { |
1428 | /* | 1425 | /* |
1429 | * Two cards with two APs claiming different | 1426 | * Two cards with two APs claiming different |
1430 | * different Country IE alpha2s. We could | 1427 | * Country IE alpha2s. We could |
1431 | * intersect them, but that seems unlikely | 1428 | * intersect them, but that seems unlikely |
1432 | * to be correct. Reject second one for now. | 1429 | * to be correct. Reject second one for now. |
1433 | */ | 1430 | */ |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0ccf3a07dc02..fe575a24c95c 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -18,19 +18,14 @@ | |||
18 | 18 | ||
19 | #define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) | 19 | #define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) |
20 | 20 | ||
21 | void __cfg80211_scan_done(struct work_struct *wk) | 21 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) |
22 | { | 22 | { |
23 | struct cfg80211_registered_device *rdev; | ||
24 | struct cfg80211_scan_request *request; | 23 | struct cfg80211_scan_request *request; |
25 | struct net_device *dev; | 24 | struct net_device *dev; |
26 | #ifdef CONFIG_WIRELESS_EXT | 25 | #ifdef CONFIG_WIRELESS_EXT |
27 | union iwreq_data wrqu; | 26 | union iwreq_data wrqu; |
28 | #endif | 27 | #endif |
29 | 28 | ||
30 | rdev = container_of(wk, struct cfg80211_registered_device, | ||
31 | scan_done_wk); | ||
32 | |||
33 | mutex_lock(&rdev->mtx); | ||
34 | request = rdev->scan_req; | 29 | request = rdev->scan_req; |
35 | 30 | ||
36 | dev = request->dev; | 31 | dev = request->dev; |
@@ -43,9 +38,9 @@ void __cfg80211_scan_done(struct work_struct *wk) | |||
43 | cfg80211_sme_scan_done(dev); | 38 | cfg80211_sme_scan_done(dev); |
44 | 39 | ||
45 | if (request->aborted) | 40 | if (request->aborted) |
46 | nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); | 41 | nl80211_send_scan_aborted(rdev, dev); |
47 | else | 42 | else |
48 | nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); | 43 | nl80211_send_scan_done(rdev, dev); |
49 | 44 | ||
50 | #ifdef CONFIG_WIRELESS_EXT | 45 | #ifdef CONFIG_WIRELESS_EXT |
51 | if (!request->aborted) { | 46 | if (!request->aborted) { |
@@ -57,11 +52,22 @@ void __cfg80211_scan_done(struct work_struct *wk) | |||
57 | 52 | ||
58 | dev_put(dev); | 53 | dev_put(dev); |
59 | 54 | ||
60 | cfg80211_unlock_rdev(rdev); | 55 | rdev->scan_req = NULL; |
61 | wiphy_to_dev(request->wiphy)->scan_req = NULL; | ||
62 | kfree(request); | 56 | kfree(request); |
63 | } | 57 | } |
64 | 58 | ||
59 | void __cfg80211_scan_done(struct work_struct *wk) | ||
60 | { | ||
61 | struct cfg80211_registered_device *rdev; | ||
62 | |||
63 | rdev = container_of(wk, struct cfg80211_registered_device, | ||
64 | scan_done_wk); | ||
65 | |||
66 | cfg80211_lock_rdev(rdev); | ||
67 | ___cfg80211_scan_done(rdev); | ||
68 | cfg80211_unlock_rdev(rdev); | ||
69 | } | ||
70 | |||
65 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | 71 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) |
66 | { | 72 | { |
67 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); | 73 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); |
@@ -562,6 +568,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | |||
562 | spin_lock_bh(&dev->bss_lock); | 568 | spin_lock_bh(&dev->bss_lock); |
563 | 569 | ||
564 | list_del(&bss->list); | 570 | list_del(&bss->list); |
571 | dev->bss_generation++; | ||
565 | rb_erase(&bss->rbn, &dev->bss_tree); | 572 | rb_erase(&bss->rbn, &dev->bss_tree); |
566 | 573 | ||
567 | spin_unlock_bh(&dev->bss_lock); | 574 | spin_unlock_bh(&dev->bss_lock); |
@@ -611,8 +618,8 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
611 | 618 | ||
612 | creq->wiphy = wiphy; | 619 | creq->wiphy = wiphy; |
613 | creq->dev = dev; | 620 | creq->dev = dev; |
614 | creq->ssids = (void *)(creq + 1); | 621 | /* SSIDs come after channels */ |
615 | creq->channels = (void *)(creq->ssids + 1); | 622 | creq->ssids = (void *)&creq->channels[n_channels]; |
616 | creq->n_channels = n_channels; | 623 | creq->n_channels = n_channels; |
617 | creq->n_ssids = 1; | 624 | creq->n_ssids = 1; |
618 | 625 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 8a7dcbf90602..8e2ef54ea714 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -27,10 +27,10 @@ struct cfg80211_conn { | |||
27 | CFG80211_CONN_ASSOCIATE_NEXT, | 27 | CFG80211_CONN_ASSOCIATE_NEXT, |
28 | CFG80211_CONN_ASSOCIATING, | 28 | CFG80211_CONN_ASSOCIATING, |
29 | } state; | 29 | } state; |
30 | u8 bssid[ETH_ALEN]; | 30 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
31 | u8 *ie; | 31 | u8 *ie; |
32 | size_t ie_len; | 32 | size_t ie_len; |
33 | bool auto_auth; | 33 | bool auto_auth, prev_bssid_valid; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | 36 | ||
@@ -65,7 +65,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
65 | if (!request) | 65 | if (!request) |
66 | return -ENOMEM; | 66 | return -ENOMEM; |
67 | 67 | ||
68 | request->channels = (void *)((char *)request + sizeof(*request)); | ||
69 | if (wdev->conn->params.channel) | 68 | if (wdev->conn->params.channel) |
70 | request->channels[0] = wdev->conn->params.channel; | 69 | request->channels[0] = wdev->conn->params.channel; |
71 | else { | 70 | else { |
@@ -82,7 +81,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
82 | } | 81 | } |
83 | } | 82 | } |
84 | request->n_channels = n_channels; | 83 | request->n_channels = n_channels; |
85 | request->ssids = (void *)(request->channels + n_channels); | 84 | request->ssids = (void *)&request->channels[n_channels]; |
86 | request->n_ssids = 1; | 85 | request->n_ssids = 1; |
87 | 86 | ||
88 | memcpy(request->ssids[0].ssid, wdev->conn->params.ssid, | 87 | memcpy(request->ssids[0].ssid, wdev->conn->params.ssid, |
@@ -110,6 +109,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
110 | { | 109 | { |
111 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 110 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
112 | struct cfg80211_connect_params *params; | 111 | struct cfg80211_connect_params *params; |
112 | const u8 *prev_bssid = NULL; | ||
113 | int err; | 113 | int err; |
114 | 114 | ||
115 | ASSERT_WDEV_LOCK(wdev); | 115 | ASSERT_WDEV_LOCK(wdev); |
@@ -135,15 +135,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
135 | case CFG80211_CONN_ASSOCIATE_NEXT: | 135 | case CFG80211_CONN_ASSOCIATE_NEXT: |
136 | BUG_ON(!rdev->ops->assoc); | 136 | BUG_ON(!rdev->ops->assoc); |
137 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; | 137 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; |
138 | /* | 138 | if (wdev->conn->prev_bssid_valid) |
139 | * We could, later, implement roaming here and then actually | 139 | prev_bssid = wdev->conn->prev_bssid; |
140 | * set prev_bssid to non-NULL. But then we need to be aware | ||
141 | * that some APs don't like that -- so we'd need to retry | ||
142 | * the association. | ||
143 | */ | ||
144 | err = __cfg80211_mlme_assoc(rdev, wdev->netdev, | 140 | err = __cfg80211_mlme_assoc(rdev, wdev->netdev, |
145 | params->channel, params->bssid, | 141 | params->channel, params->bssid, |
146 | NULL, | 142 | prev_bssid, |
147 | params->ssid, params->ssid_len, | 143 | params->ssid, params->ssid_len, |
148 | params->ie, params->ie_len, | 144 | params->ie, params->ie_len, |
149 | false, ¶ms->crypto); | 145 | false, ¶ms->crypto); |
@@ -256,9 +252,11 @@ void cfg80211_sme_scan_done(struct net_device *dev) | |||
256 | { | 252 | { |
257 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 253 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
258 | 254 | ||
255 | mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); | ||
259 | wdev_lock(wdev); | 256 | wdev_lock(wdev); |
260 | __cfg80211_sme_scan_done(dev); | 257 | __cfg80211_sme_scan_done(dev); |
261 | wdev_unlock(wdev); | 258 | wdev_unlock(wdev); |
259 | mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); | ||
262 | } | 260 | } |
263 | 261 | ||
264 | void cfg80211_sme_rx_auth(struct net_device *dev, | 262 | void cfg80211_sme_rx_auth(struct net_device *dev, |
@@ -314,6 +312,28 @@ void cfg80211_sme_rx_auth(struct net_device *dev, | |||
314 | } | 312 | } |
315 | } | 313 | } |
316 | 314 | ||
315 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev) | ||
316 | { | ||
317 | struct wiphy *wiphy = wdev->wiphy; | ||
318 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
319 | |||
320 | if (WARN_ON(!wdev->conn)) | ||
321 | return false; | ||
322 | |||
323 | if (!wdev->conn->prev_bssid_valid) | ||
324 | return false; | ||
325 | |||
326 | /* | ||
327 | * Some stupid APs don't accept reassoc, so we | ||
328 | * need to fall back to trying regular assoc. | ||
329 | */ | ||
330 | wdev->conn->prev_bssid_valid = false; | ||
331 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | ||
332 | schedule_work(&rdev->conn_work); | ||
333 | |||
334 | return true; | ||
335 | } | ||
336 | |||
317 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 337 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
318 | const u8 *req_ie, size_t req_ie_len, | 338 | const u8 *req_ie, size_t req_ie_len, |
319 | const u8 *resp_ie, size_t resp_ie_len, | 339 | const u8 *resp_ie, size_t resp_ie_len, |
@@ -357,8 +377,11 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
357 | 377 | ||
358 | memset(&wrqu, 0, sizeof(wrqu)); | 378 | memset(&wrqu, 0, sizeof(wrqu)); |
359 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 379 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
360 | if (bssid && status == WLAN_STATUS_SUCCESS) | 380 | if (bssid && status == WLAN_STATUS_SUCCESS) { |
361 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | 381 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); |
382 | memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN); | ||
383 | wdev->wext.prev_bssid_valid = true; | ||
384 | } | ||
362 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); | 385 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); |
363 | } | 386 | } |
364 | #endif | 387 | #endif |
@@ -509,6 +532,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, | |||
509 | memset(&wrqu, 0, sizeof(wrqu)); | 532 | memset(&wrqu, 0, sizeof(wrqu)); |
510 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 533 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
511 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | 534 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); |
535 | memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN); | ||
536 | wdev->wext.prev_bssid_valid = true; | ||
512 | wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); | 537 | wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); |
513 | #endif | 538 | #endif |
514 | } | 539 | } |
@@ -570,10 +595,30 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
570 | wdev->ssid_len = 0; | 595 | wdev->ssid_len = 0; |
571 | 596 | ||
572 | if (wdev->conn) { | 597 | if (wdev->conn) { |
598 | const u8 *bssid; | ||
599 | int ret; | ||
600 | |||
573 | kfree(wdev->conn->ie); | 601 | kfree(wdev->conn->ie); |
574 | wdev->conn->ie = NULL; | 602 | wdev->conn->ie = NULL; |
575 | kfree(wdev->conn); | 603 | kfree(wdev->conn); |
576 | wdev->conn = NULL; | 604 | wdev->conn = NULL; |
605 | |||
606 | /* | ||
607 | * If this disconnect was due to a disassoc, we | ||
608 | * we might still have an auth BSS around. For | ||
609 | * the userspace SME that's currently expected, | ||
610 | * but for the kernel SME (nl80211 CONNECT or | ||
611 | * wireless extensions) we want to clear up all | ||
612 | * state. | ||
613 | */ | ||
614 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | ||
615 | if (!wdev->auth_bsses[i]) | ||
616 | continue; | ||
617 | bssid = wdev->auth_bsses[i]->pub.bssid; | ||
618 | ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, | ||
619 | WLAN_REASON_DEAUTH_LEAVING); | ||
620 | WARN(ret, "deauth failed: %d\n", ret); | ||
621 | } | ||
577 | } | 622 | } |
578 | 623 | ||
579 | nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); | 624 | nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); |
@@ -621,9 +666,11 @@ EXPORT_SYMBOL(cfg80211_disconnected); | |||
621 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 666 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
622 | struct net_device *dev, | 667 | struct net_device *dev, |
623 | struct cfg80211_connect_params *connect, | 668 | struct cfg80211_connect_params *connect, |
624 | struct cfg80211_cached_keys *connkeys) | 669 | struct cfg80211_cached_keys *connkeys, |
670 | const u8 *prev_bssid) | ||
625 | { | 671 | { |
626 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 672 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
673 | struct ieee80211_channel *chan; | ||
627 | int err; | 674 | int err; |
628 | 675 | ||
629 | ASSERT_WDEV_LOCK(wdev); | 676 | ASSERT_WDEV_LOCK(wdev); |
@@ -631,6 +678,10 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
631 | if (wdev->sme_state != CFG80211_SME_IDLE) | 678 | if (wdev->sme_state != CFG80211_SME_IDLE) |
632 | return -EALREADY; | 679 | return -EALREADY; |
633 | 680 | ||
681 | chan = rdev_fixed_channel(rdev, wdev); | ||
682 | if (chan && chan != connect->channel) | ||
683 | return -EBUSY; | ||
684 | |||
634 | if (WARN_ON(wdev->connect_keys)) { | 685 | if (WARN_ON(wdev->connect_keys)) { |
635 | kfree(wdev->connect_keys); | 686 | kfree(wdev->connect_keys); |
636 | wdev->connect_keys = NULL; | 687 | wdev->connect_keys = NULL; |
@@ -638,14 +689,28 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
638 | 689 | ||
639 | if (connkeys && connkeys->def >= 0) { | 690 | if (connkeys && connkeys->def >= 0) { |
640 | int idx; | 691 | int idx; |
692 | u32 cipher; | ||
641 | 693 | ||
642 | idx = connkeys->def; | 694 | idx = connkeys->def; |
695 | cipher = connkeys->params[idx].cipher; | ||
643 | /* If given a WEP key we may need it for shared key auth */ | 696 | /* If given a WEP key we may need it for shared key auth */ |
644 | if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 || | 697 | if (cipher == WLAN_CIPHER_SUITE_WEP40 || |
645 | connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) { | 698 | cipher == WLAN_CIPHER_SUITE_WEP104) { |
646 | connect->key_idx = idx; | 699 | connect->key_idx = idx; |
647 | connect->key = connkeys->params[idx].key; | 700 | connect->key = connkeys->params[idx].key; |
648 | connect->key_len = connkeys->params[idx].key_len; | 701 | connect->key_len = connkeys->params[idx].key_len; |
702 | |||
703 | /* | ||
704 | * If ciphers are not set (e.g. when going through | ||
705 | * iwconfig), we have to set them appropriately here. | ||
706 | */ | ||
707 | if (connect->crypto.cipher_group == 0) | ||
708 | connect->crypto.cipher_group = cipher; | ||
709 | |||
710 | if (connect->crypto.n_ciphers_pairwise == 0) { | ||
711 | connect->crypto.n_ciphers_pairwise = 1; | ||
712 | connect->crypto.ciphers_pairwise[0] = cipher; | ||
713 | } | ||
649 | } | 714 | } |
650 | } | 715 | } |
651 | 716 | ||
@@ -701,6 +766,11 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
701 | wdev->sme_state = CFG80211_SME_CONNECTING; | 766 | wdev->sme_state = CFG80211_SME_CONNECTING; |
702 | wdev->connect_keys = connkeys; | 767 | wdev->connect_keys = connkeys; |
703 | 768 | ||
769 | if (prev_bssid) { | ||
770 | memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN); | ||
771 | wdev->conn->prev_bssid_valid = true; | ||
772 | } | ||
773 | |||
704 | /* we're good if we have both BSSID and channel */ | 774 | /* we're good if we have both BSSID and channel */ |
705 | if (wdev->conn->params.bssid && wdev->conn->params.channel) { | 775 | if (wdev->conn->params.bssid && wdev->conn->params.channel) { |
706 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; | 776 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; |
@@ -751,9 +821,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
751 | { | 821 | { |
752 | int err; | 822 | int err; |
753 | 823 | ||
824 | mutex_lock(&rdev->devlist_mtx); | ||
754 | wdev_lock(dev->ieee80211_ptr); | 825 | wdev_lock(dev->ieee80211_ptr); |
755 | err = __cfg80211_connect(rdev, dev, connect, connkeys); | 826 | err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL); |
756 | wdev_unlock(dev->ieee80211_ptr); | 827 | wdev_unlock(dev->ieee80211_ptr); |
828 | mutex_unlock(&rdev->devlist_mtx); | ||
757 | 829 | ||
758 | return err; | 830 | return err; |
759 | } | 831 | } |
diff --git a/net/wireless/util.c b/net/wireless/util.c index ba387d85dcfd..693275a16a26 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -274,11 +274,11 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | |||
274 | switch (ae) { | 274 | switch (ae) { |
275 | case 0: | 275 | case 0: |
276 | return 6; | 276 | return 6; |
277 | case 1: | 277 | case MESH_FLAGS_AE_A4: |
278 | return 12; | 278 | return 12; |
279 | case 2: | 279 | case MESH_FLAGS_AE_A5_A6: |
280 | return 18; | 280 | return 18; |
281 | case 3: | 281 | case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6): |
282 | return 24; | 282 | return 24; |
283 | default: | 283 | default: |
284 | return 6; | 284 | return 6; |
@@ -333,10 +333,18 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, | |||
333 | } | 333 | } |
334 | break; | 334 | break; |
335 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): | 335 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): |
336 | if (iftype != NL80211_IFTYPE_STATION || | 336 | if ((iftype != NL80211_IFTYPE_STATION && |
337 | iftype != NL80211_IFTYPE_MESH_POINT) || | ||
337 | (is_multicast_ether_addr(dst) && | 338 | (is_multicast_ether_addr(dst) && |
338 | !compare_ether_addr(src, addr))) | 339 | !compare_ether_addr(src, addr))) |
339 | return -1; | 340 | return -1; |
341 | if (iftype == NL80211_IFTYPE_MESH_POINT) { | ||
342 | struct ieee80211s_hdr *meshdr = | ||
343 | (struct ieee80211s_hdr *) (skb->data + hdrlen); | ||
344 | hdrlen += ieee80211_get_mesh_hdrlen(meshdr); | ||
345 | if (meshdr->flags & MESH_FLAGS_AE_A4) | ||
346 | memcpy(src, meshdr->eaddr1, ETH_ALEN); | ||
347 | } | ||
340 | break; | 348 | break; |
341 | case cpu_to_le16(0): | 349 | case cpu_to_le16(0): |
342 | if (iftype != NL80211_IFTYPE_ADHOC) | 350 | if (iftype != NL80211_IFTYPE_ADHOC) |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index e4e90e249bab..c44917492210 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -267,39 +267,26 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); | |||
267 | * @wiphy: the wiphy | 267 | * @wiphy: the wiphy |
268 | * @freq: the wext freq encoding | 268 | * @freq: the wext freq encoding |
269 | * | 269 | * |
270 | * Returns a channel, %NULL for auto, or an ERR_PTR for errors! | 270 | * Returns a frequency, or a negative error code, or 0 for auto. |
271 | */ | 271 | */ |
272 | struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, | 272 | int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq) |
273 | struct iw_freq *freq) | ||
274 | { | 273 | { |
275 | struct ieee80211_channel *chan; | ||
276 | int f; | ||
277 | |||
278 | /* | 274 | /* |
279 | * Parse frequency - return NULL for auto and | 275 | * Parse frequency - return 0 for auto and |
280 | * -EINVAL for impossible things. | 276 | * -EINVAL for impossible things. |
281 | */ | 277 | */ |
282 | if (freq->e == 0) { | 278 | if (freq->e == 0) { |
283 | if (freq->m < 0) | 279 | if (freq->m < 0) |
284 | return NULL; | 280 | return 0; |
285 | f = ieee80211_channel_to_frequency(freq->m); | 281 | return ieee80211_channel_to_frequency(freq->m); |
286 | } else { | 282 | } else { |
287 | int i, div = 1000000; | 283 | int i, div = 1000000; |
288 | for (i = 0; i < freq->e; i++) | 284 | for (i = 0; i < freq->e; i++) |
289 | div /= 10; | 285 | div /= 10; |
290 | if (div <= 0) | 286 | if (div <= 0) |
291 | return ERR_PTR(-EINVAL); | 287 | return -EINVAL; |
292 | f = freq->m / div; | 288 | return freq->m / div; |
293 | } | 289 | } |
294 | |||
295 | /* | ||
296 | * Look up channel struct and return -EINVAL when | ||
297 | * it cannot be found. | ||
298 | */ | ||
299 | chan = ieee80211_get_channel(wiphy, f); | ||
300 | if (!chan) | ||
301 | return ERR_PTR(-EINVAL); | ||
302 | return chan; | ||
303 | } | 290 | } |
304 | 291 | ||
305 | int cfg80211_wext_siwrts(struct net_device *dev, | 292 | int cfg80211_wext_siwrts(struct net_device *dev, |
@@ -761,33 +748,29 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); | |||
761 | 748 | ||
762 | int cfg80211_wext_siwfreq(struct net_device *dev, | 749 | int cfg80211_wext_siwfreq(struct net_device *dev, |
763 | struct iw_request_info *info, | 750 | struct iw_request_info *info, |
764 | struct iw_freq *freq, char *extra) | 751 | struct iw_freq *wextfreq, char *extra) |
765 | { | 752 | { |
766 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 753 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
767 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 754 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
768 | struct ieee80211_channel *chan; | 755 | int freq, err; |
769 | int err; | ||
770 | 756 | ||
771 | switch (wdev->iftype) { | 757 | switch (wdev->iftype) { |
772 | case NL80211_IFTYPE_STATION: | 758 | case NL80211_IFTYPE_STATION: |
773 | return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra); | 759 | return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra); |
774 | case NL80211_IFTYPE_ADHOC: | 760 | case NL80211_IFTYPE_ADHOC: |
775 | return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); | 761 | return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra); |
776 | default: | 762 | default: |
777 | chan = cfg80211_wext_freq(wdev->wiphy, freq); | 763 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); |
778 | if (!chan) | 764 | if (freq < 0) |
765 | return freq; | ||
766 | if (freq == 0) | ||
779 | return -EINVAL; | 767 | return -EINVAL; |
780 | if (IS_ERR(chan)) | 768 | mutex_lock(&rdev->devlist_mtx); |
781 | return PTR_ERR(chan); | 769 | err = rdev_set_freq(rdev, NULL, freq, NL80211_CHAN_NO_HT); |
782 | err = rdev->ops->set_channel(wdev->wiphy, chan, | 770 | mutex_unlock(&rdev->devlist_mtx); |
783 | NL80211_CHAN_NO_HT); | 771 | return err; |
784 | if (err) | ||
785 | return err; | ||
786 | rdev->channel = chan; | ||
787 | return 0; | ||
788 | } | 772 | } |
789 | } | 773 | } |
790 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq); | ||
791 | 774 | ||
792 | int cfg80211_wext_giwfreq(struct net_device *dev, | 775 | int cfg80211_wext_giwfreq(struct net_device *dev, |
793 | struct iw_request_info *info, | 776 | struct iw_request_info *info, |
diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h index 9a3774749589..20b3daef6964 100644 --- a/net/wireless/wext-compat.h +++ b/net/wireless/wext-compat.h | |||
@@ -42,8 +42,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, | |||
42 | struct iw_request_info *info, | 42 | struct iw_request_info *info, |
43 | struct iw_point *data, char *ssid); | 43 | struct iw_point *data, char *ssid); |
44 | 44 | ||
45 | struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, | 45 | int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq); |
46 | struct iw_freq *freq); | ||
47 | 46 | ||
48 | 47 | ||
49 | extern const struct iw_handler_def cfg80211_wext_handler; | 48 | extern const struct iw_handler_def cfg80211_wext_handler; |
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 7bacbd1c2af6..d16cd9ea4d00 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -15,6 +15,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
15 | struct wireless_dev *wdev) | 15 | struct wireless_dev *wdev) |
16 | { | 16 | { |
17 | struct cfg80211_cached_keys *ck = NULL; | 17 | struct cfg80211_cached_keys *ck = NULL; |
18 | const u8 *prev_bssid = NULL; | ||
18 | int err, i; | 19 | int err, i; |
19 | 20 | ||
20 | ASSERT_RDEV_LOCK(rdev); | 21 | ASSERT_RDEV_LOCK(rdev); |
@@ -42,8 +43,12 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
42 | for (i = 0; i < 6; i++) | 43 | for (i = 0; i < 6; i++) |
43 | ck->params[i].key = ck->data[i]; | 44 | ck->params[i].key = ck->data[i]; |
44 | } | 45 | } |
46 | |||
47 | if (wdev->wext.prev_bssid_valid) | ||
48 | prev_bssid = wdev->wext.prev_bssid; | ||
49 | |||
45 | err = __cfg80211_connect(rdev, wdev->netdev, | 50 | err = __cfg80211_connect(rdev, wdev->netdev, |
46 | &wdev->wext.connect, ck); | 51 | &wdev->wext.connect, ck, prev_bssid); |
47 | if (err) | 52 | if (err) |
48 | kfree(ck); | 53 | kfree(ck); |
49 | 54 | ||
@@ -52,25 +57,31 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
52 | 57 | ||
53 | int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | 58 | int cfg80211_mgd_wext_siwfreq(struct net_device *dev, |
54 | struct iw_request_info *info, | 59 | struct iw_request_info *info, |
55 | struct iw_freq *freq, char *extra) | 60 | struct iw_freq *wextfreq, char *extra) |
56 | { | 61 | { |
57 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 62 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
58 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 63 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
59 | struct ieee80211_channel *chan; | 64 | struct ieee80211_channel *chan = NULL; |
60 | int err; | 65 | int err, freq; |
61 | 66 | ||
62 | /* call only for station! */ | 67 | /* call only for station! */ |
63 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 68 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) |
64 | return -EINVAL; | 69 | return -EINVAL; |
65 | 70 | ||
66 | chan = cfg80211_wext_freq(wdev->wiphy, freq); | 71 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); |
67 | if (chan && IS_ERR(chan)) | 72 | if (freq < 0) |
68 | return PTR_ERR(chan); | 73 | return freq; |
69 | 74 | ||
70 | if (chan && (chan->flags & IEEE80211_CHAN_DISABLED)) | 75 | if (freq) { |
71 | return -EINVAL; | 76 | chan = ieee80211_get_channel(wdev->wiphy, freq); |
77 | if (!chan) | ||
78 | return -EINVAL; | ||
79 | if (chan->flags & IEEE80211_CHAN_DISABLED) | ||
80 | return -EINVAL; | ||
81 | } | ||
72 | 82 | ||
73 | cfg80211_lock_rdev(rdev); | 83 | cfg80211_lock_rdev(rdev); |
84 | mutex_lock(&rdev->devlist_mtx); | ||
74 | wdev_lock(wdev); | 85 | wdev_lock(wdev); |
75 | 86 | ||
76 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 87 | if (wdev->sme_state != CFG80211_SME_IDLE) { |
@@ -84,9 +95,8 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
84 | /* if SSID set, we'll try right again, avoid event */ | 95 | /* if SSID set, we'll try right again, avoid event */ |
85 | if (wdev->wext.connect.ssid_len) | 96 | if (wdev->wext.connect.ssid_len) |
86 | event = false; | 97 | event = false; |
87 | err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), | 98 | err = __cfg80211_disconnect(rdev, dev, |
88 | dev, WLAN_REASON_DEAUTH_LEAVING, | 99 | WLAN_REASON_DEAUTH_LEAVING, event); |
89 | event); | ||
90 | if (err) | 100 | if (err) |
91 | goto out; | 101 | goto out; |
92 | } | 102 | } |
@@ -95,17 +105,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
95 | wdev->wext.connect.channel = chan; | 105 | wdev->wext.connect.channel = chan; |
96 | 106 | ||
97 | /* SSID is not set, we just want to switch channel */ | 107 | /* SSID is not set, we just want to switch channel */ |
98 | if (wdev->wext.connect.ssid_len && chan) { | 108 | if (chan && !wdev->wext.connect.ssid_len) { |
99 | err = -EOPNOTSUPP; | 109 | err = rdev_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT); |
100 | if (rdev->ops->set_channel) | ||
101 | err = rdev->ops->set_channel(wdev->wiphy, chan, | ||
102 | NL80211_CHAN_NO_HT); | ||
103 | goto out; | 110 | goto out; |
104 | } | 111 | } |
105 | 112 | ||
106 | err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); | 113 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
107 | out: | 114 | out: |
108 | wdev_unlock(wdev); | 115 | wdev_unlock(wdev); |
116 | mutex_unlock(&rdev->devlist_mtx); | ||
109 | cfg80211_unlock_rdev(rdev); | 117 | cfg80211_unlock_rdev(rdev); |
110 | return err; | 118 | return err; |
111 | } | 119 | } |
@@ -143,6 +151,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
143 | struct iw_point *data, char *ssid) | 151 | struct iw_point *data, char *ssid) |
144 | { | 152 | { |
145 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 153 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
154 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
146 | size_t len = data->length; | 155 | size_t len = data->length; |
147 | int err; | 156 | int err; |
148 | 157 | ||
@@ -157,7 +166,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
157 | if (len > 0 && ssid[len - 1] == '\0') | 166 | if (len > 0 && ssid[len - 1] == '\0') |
158 | len--; | 167 | len--; |
159 | 168 | ||
160 | cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); | 169 | cfg80211_lock_rdev(rdev); |
170 | mutex_lock(&rdev->devlist_mtx); | ||
161 | wdev_lock(wdev); | 171 | wdev_lock(wdev); |
162 | 172 | ||
163 | err = 0; | 173 | err = 0; |
@@ -173,23 +183,24 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
173 | /* if SSID set now, we'll try to connect, avoid event */ | 183 | /* if SSID set now, we'll try to connect, avoid event */ |
174 | if (len) | 184 | if (len) |
175 | event = false; | 185 | event = false; |
176 | err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), | 186 | err = __cfg80211_disconnect(rdev, dev, |
177 | dev, WLAN_REASON_DEAUTH_LEAVING, | 187 | WLAN_REASON_DEAUTH_LEAVING, event); |
178 | event); | ||
179 | if (err) | 188 | if (err) |
180 | goto out; | 189 | goto out; |
181 | } | 190 | } |
182 | 191 | ||
192 | wdev->wext.prev_bssid_valid = false; | ||
183 | wdev->wext.connect.ssid = wdev->wext.ssid; | 193 | wdev->wext.connect.ssid = wdev->wext.ssid; |
184 | memcpy(wdev->wext.ssid, ssid, len); | 194 | memcpy(wdev->wext.ssid, ssid, len); |
185 | wdev->wext.connect.ssid_len = len; | 195 | wdev->wext.connect.ssid_len = len; |
186 | 196 | ||
187 | wdev->wext.connect.crypto.control_port = false; | 197 | wdev->wext.connect.crypto.control_port = false; |
188 | 198 | ||
189 | err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); | 199 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
190 | out: | 200 | out: |
191 | wdev_unlock(wdev); | 201 | wdev_unlock(wdev); |
192 | cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); | 202 | mutex_unlock(&rdev->devlist_mtx); |
203 | cfg80211_unlock_rdev(rdev); | ||
193 | return err; | 204 | return err; |
194 | } | 205 | } |
195 | 206 | ||
@@ -206,7 +217,15 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, | |||
206 | data->flags = 0; | 217 | data->flags = 0; |
207 | 218 | ||
208 | wdev_lock(wdev); | 219 | wdev_lock(wdev); |
209 | if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { | 220 | if (wdev->current_bss) { |
221 | const u8 *ie = ieee80211_bss_get_ie(&wdev->current_bss->pub, | ||
222 | WLAN_EID_SSID); | ||
223 | if (ie) { | ||
224 | data->flags = 1; | ||
225 | data->length = ie[1]; | ||
226 | memcpy(ssid, ie + 2, data->length); | ||
227 | } | ||
228 | } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { | ||
210 | data->flags = 1; | 229 | data->flags = 1; |
211 | data->length = wdev->wext.connect.ssid_len; | 230 | data->length = wdev->wext.connect.ssid_len; |
212 | memcpy(ssid, wdev->wext.connect.ssid, data->length); | 231 | memcpy(ssid, wdev->wext.connect.ssid, data->length); |
@@ -222,6 +241,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
222 | struct sockaddr *ap_addr, char *extra) | 241 | struct sockaddr *ap_addr, char *extra) |
223 | { | 242 | { |
224 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 243 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
244 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
225 | u8 *bssid = ap_addr->sa_data; | 245 | u8 *bssid = ap_addr->sa_data; |
226 | int err; | 246 | int err; |
227 | 247 | ||
@@ -236,7 +256,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
236 | if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) | 256 | if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) |
237 | bssid = NULL; | 257 | bssid = NULL; |
238 | 258 | ||
239 | cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); | 259 | cfg80211_lock_rdev(rdev); |
260 | mutex_lock(&rdev->devlist_mtx); | ||
240 | wdev_lock(wdev); | 261 | wdev_lock(wdev); |
241 | 262 | ||
242 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 263 | if (wdev->sme_state != CFG80211_SME_IDLE) { |
@@ -250,9 +271,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
250 | compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) | 271 | compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) |
251 | goto out; | 272 | goto out; |
252 | 273 | ||
253 | err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), | 274 | err = __cfg80211_disconnect(rdev, dev, |
254 | dev, WLAN_REASON_DEAUTH_LEAVING, | 275 | WLAN_REASON_DEAUTH_LEAVING, false); |
255 | false); | ||
256 | if (err) | 276 | if (err) |
257 | goto out; | 277 | goto out; |
258 | } | 278 | } |
@@ -263,10 +283,11 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
263 | } else | 283 | } else |
264 | wdev->wext.connect.bssid = NULL; | 284 | wdev->wext.connect.bssid = NULL; |
265 | 285 | ||
266 | err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); | 286 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
267 | out: | 287 | out: |
268 | wdev_unlock(wdev); | 288 | wdev_unlock(wdev); |
269 | cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); | 289 | mutex_unlock(&rdev->devlist_mtx); |
290 | cfg80211_unlock_rdev(rdev); | ||
270 | return err; | 291 | return err; |
271 | } | 292 | } |
272 | 293 | ||