summaryrefslogtreecommitdiff
path: root/drivers/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/Kconfig81
-rw-r--r--drivers/net/wireless/adm8211.c62
-rw-r--r--drivers/net/wireless/airo.c26
-rw-r--r--drivers/net/wireless/arlan-main.c8
-rw-r--r--drivers/net/wireless/at76c50x-usb.c33
-rw-r--r--drivers/net/wireless/ath/Kconfig19
-rw-r--r--drivers/net/wireless/ath/ar9170/Kconfig4
-rw-r--r--drivers/net/wireless/ath/ar9170/ar9170.h69
-rw-r--r--drivers/net/wireless/ath/ar9170/led.c11
-rw-r--r--drivers/net/wireless/ath/ar9170/mac.c46
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c768
-rw-r--r--drivers/net/wireless/ath/ar9170/phy.c420
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c2
-rw-r--r--drivers/net/wireless/ath/ath.h48
-rw-r--r--drivers/net/wireless/ath/ath5k/Kconfig3
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h45
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c84
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c473
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h29
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c8
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c39
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.h4
-rw-r--r--drivers/net/wireless/ath/ath5k/led.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c57
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/reg.h12
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c156
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig13
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile6
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c207
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.h25
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h86
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.c340
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.h100
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c218
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h11
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c99
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h56
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c2598
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h284
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c1188
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c1177
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c1387
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c891
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h123
-rw-r--r--drivers/net/wireless/ath/ath9k/initvals.h2239
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c47
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h9
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c316
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c34
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.c65
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.h32
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c616
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h29
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c150
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h202
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c34
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c193
-rw-r--r--drivers/net/wireless/ath/main.c36
-rw-r--r--drivers/net/wireless/ath/regd.c2
-rw-r--r--drivers/net/wireless/ath/regd.h26
-rw-r--r--drivers/net/wireless/ath/regd_common.h8
-rw-r--r--drivers/net/wireless/atmel.c8
-rw-r--r--drivers/net/wireless/b43/Kconfig18
-rw-r--r--drivers/net/wireless/b43/b43.h52
-rw-r--r--drivers/net/wireless/b43/debugfs.c67
-rw-r--r--drivers/net/wireless/b43/debugfs.h3
-rw-r--r--drivers/net/wireless/b43/dma.c52
-rw-r--r--drivers/net/wireless/b43/dma.h3
-rw-r--r--drivers/net/wireless/b43/lo.c2
-rw-r--r--drivers/net/wireless/b43/main.c921
-rw-r--r--drivers/net/wireless/b43/main.h6
-rw-r--r--drivers/net/wireless/b43/phy_a.c48
-rw-r--r--drivers/net/wireless/b43/phy_common.c37
-rw-r--r--drivers/net/wireless/b43/phy_common.h21
-rw-r--r--drivers/net/wireless/b43/phy_g.c66
-rw-r--r--drivers/net/wireless/b43/phy_g.h3
-rw-r--r--drivers/net/wireless/b43/phy_lp.c1804
-rw-r--r--drivers/net/wireless/b43/phy_lp.h58
-rw-r--r--drivers/net/wireless/b43/phy_n.c3
-rw-r--r--drivers/net/wireless/b43/pio.c75
-rw-r--r--drivers/net/wireless/b43/pio.h6
-rw-r--r--drivers/net/wireless/b43/sysfs.c3
-rw-r--r--drivers/net/wireless/b43/tables_lpphy.c2193
-rw-r--r--drivers/net/wireless/b43/tables_lpphy.h13
-rw-r--r--drivers/net/wireless/b43/wa.c4
-rw-r--r--drivers/net/wireless/b43/xmit.c36
-rw-r--r--drivers/net/wireless/b43/xmit.h3
-rw-r--r--drivers/net/wireless/b43legacy/dma.c22
-rw-r--r--drivers/net/wireless/b43legacy/main.c20
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_80211.h10
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_tx.c53
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c3
-rw-r--r--drivers/net/wireless/ipw2x00/Kconfig6
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c228
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.h16
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c1118
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.h16
-rw-r--r--drivers/net/wireless/ipw2x00/libipw.h (renamed from drivers/net/wireless/ipw2x00/ieee80211.h)669
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_geo.c82
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_module.c124
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_rx.c403
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_tx.c78
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_wx.c94
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c96
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c94
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c96
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c149
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c136
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c321
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c333
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.c13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h62
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c972
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h89
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h37
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c1159
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h293
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c514
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h124
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c65
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c40
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c822
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h115
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c245
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c42
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c60
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c255
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c289
-rw-r--r--drivers/net/wireless/iwmc3200wifi/Kconfig1
-rw-r--r--drivers/net/wireless/iwmc3200wifi/Makefile2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c436
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c196
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h7
-rw-r--r--drivers/net/wireless/iwmc3200wifi/debug.h2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/debugfs.c105
-rw-r--r--drivers/net/wireless/iwmc3200wifi/eeprom.c4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/fw.c67
-rw-r--r--drivers/net/wireless/iwmc3200wifi/hal.c16
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h47
-rw-r--r--drivers/net/wireless/iwmc3200wifi/lmac.h19
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c103
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c28
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c205
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.c10
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.h3
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h8
-rw-r--r--drivers/net/wireless/iwmc3200wifi/wext.c723
-rw-r--r--drivers/net/wireless/libertas/assoc.c67
-rw-r--r--drivers/net/wireless/libertas/debugfs.c28
-rw-r--r--drivers/net/wireless/libertas/decl.h5
-rw-r--r--drivers/net/wireless/libertas/dev.h3
-rw-r--r--drivers/net/wireless/libertas/ethtool.c2
-rw-r--r--drivers/net/wireless/libertas/if_cs.c42
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c5
-rw-r--r--drivers/net/wireless/libertas/if_spi.c10
-rw-r--r--drivers/net/wireless/libertas/if_usb.c3
-rw-r--r--drivers/net/wireless/libertas/main.c6
-rw-r--r--drivers/net/wireless/libertas/tx.c6
-rw-r--r--drivers/net/wireless/libertas/wext.c4
-rw-r--r--drivers/net/wireless/libertas_tf/main.c40
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c98
-rw-r--r--drivers/net/wireless/mwl8k.c1559
-rw-r--r--drivers/net/wireless/netwave_cs.c8
-rw-r--r--drivers/net/wireless/orinoco/Kconfig1
-rw-r--r--drivers/net/wireless/orinoco/Makefile2
-rw-r--r--drivers/net/wireless/orinoco/airport.c98
-rw-r--r--drivers/net/wireless/orinoco/cfg.c203
-rw-r--r--drivers/net/wireless/orinoco/cfg.h15
-rw-r--r--drivers/net/wireless/orinoco/fw.c41
-rw-r--r--drivers/net/wireless/orinoco/hermes.c2
-rw-r--r--drivers/net/wireless/orinoco/hermes.h2
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.c50
-rw-r--r--drivers/net/wireless/orinoco/hw.c786
-rw-r--r--drivers/net/wireless/orinoco/hw.h16
-rw-r--r--drivers/net/wireless/orinoco/main.c1169
-rw-r--r--drivers/net/wireless/orinoco/main.h3
-rw-r--r--drivers/net/wireless/orinoco/orinoco.h65
-rw-r--r--drivers/net/wireless/orinoco/orinoco_cs.c96
-rw-r--r--drivers/net/wireless/orinoco/orinoco_nortel.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.h57
-rw-r--r--drivers/net/wireless/orinoco/orinoco_plx.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_tmd.c38
-rw-r--r--drivers/net/wireless/orinoco/scan.c291
-rw-r--r--drivers/net/wireless/orinoco/scan.h21
-rw-r--r--drivers/net/wireless/orinoco/spectrum_cs.c96
-rw-r--r--drivers/net/wireless/orinoco/wext.c1053
-rw-r--r--drivers/net/wireless/p54/Makefile3
-rw-r--r--drivers/net/wireless/p54/eeprom.c753
-rw-r--r--drivers/net/wireless/p54/eeprom.h226
-rw-r--r--drivers/net/wireless/p54/fwio.c716
-rw-r--r--drivers/net/wireless/p54/led.c162
-rw-r--r--drivers/net/wireless/p54/lmac.h558
-rw-r--r--drivers/net/wireless/p54/main.c648
-rw-r--r--drivers/net/wireless/p54/p54.h151
-rw-r--r--drivers/net/wireless/p54/p54common.c2688
-rw-r--r--drivers/net/wireless/p54/p54common.h644
-rw-r--r--drivers/net/wireless/p54/p54pci.c9
-rw-r--r--drivers/net/wireless/p54/p54spi.c54
-rw-r--r--drivers/net/wireless/p54/p54usb.c42
-rw-r--r--drivers/net/wireless/p54/txrx.c869
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.c8
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.h2
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c4
-rw-r--r--drivers/net/wireless/ray_cs.c21
-rw-r--r--drivers/net/wireless/rndis_wlan.c2157
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig16
-rw-r--r--drivers/net/wireless/rt2x00/Makefile1
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c15
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c15
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c28
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c49
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h60
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c35
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00crypto.c14
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c104
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h68
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00link.c168
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c127
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c123
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00reg.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00rfkill.c127
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c27
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c21
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h4
-rw-r--r--drivers/net/wireless/rtl818x/Makefile2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_dev.c16
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187.h1
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c47
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_leds.c14
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_rfkill.c63
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_rfkill.h8
-rw-r--r--drivers/net/wireless/rtl818x/rtl818x.h19
-rw-r--r--drivers/net/wireless/strip.c13
-rw-r--r--drivers/net/wireless/wavelan.c5
-rw-r--r--drivers/net/wireless/wavelan.p.h2
-rw-r--r--drivers/net/wireless/wavelan_cs.c6
-rw-r--r--drivers/net/wireless/wavelan_cs.p.h2
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig51
-rw-r--r--drivers/net/wireless/wl12xx/Makefile18
-rw-r--r--drivers/net/wireless/wl12xx/acx.c689
-rw-r--r--drivers/net/wireless/wl12xx/boot.c295
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c353
-rw-r--r--drivers/net/wireless/wl12xx/init.c200
-rw-r--r--drivers/net/wireless/wl12xx/wl1251.c709
-rw-r--r--drivers/net/wireless/wl12xx/wl1251.h467
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.c918
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.h (renamed from drivers/net/wireless/wl12xx/acx.h)345
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.c530
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.h (renamed from drivers/net/wireless/wl12xx/boot.h)13
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.c412
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.h (renamed from drivers/net/wireless/wl12xx/cmd.h)196
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_debugfs.c (renamed from drivers/net/wireless/wl12xx/debugfs.c)60
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_debugfs.h (renamed from drivers/net/wireless/wl12xx/debugfs.h)16
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.c (renamed from drivers/net/wireless/wl12xx/event.c)57
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.h (renamed from drivers/net/wireless/wl12xx/event.h)12
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.c413
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.h41
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_io.c196
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_io.h64
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c (renamed from drivers/net/wireless/wl12xx/main.c)890
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_netlink.h (renamed from drivers/net/wireless/wl12xx/init.h)22
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.c (renamed from drivers/net/wireless/wl12xx/ps.c)80
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.h (renamed from drivers/net/wireless/wl12xx/ps.h)18
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_reg.h644
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.c (renamed from drivers/net/wireless/wl12xx/rx.c)93
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.h (renamed from drivers/net/wireless/wl12xx/rx.h)24
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_sdio.c205
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.c344
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.h61
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.c (renamed from drivers/net/wireless/wl12xx/tx.c)174
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.h (renamed from drivers/net/wireless/wl12xx/tx.h)21
-rw-r--r--drivers/net/wireless/wl12xx/wl1271.h (renamed from drivers/net/wireless/wl12xx/wl12xx.h)210
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.c961
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.h1221
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_boot.c541
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_boot.h72
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.c813
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.h464
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_debugfs.c518
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_debugfs.h33
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.c125
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.h110
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_init.c397
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_init.h115
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c1394
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.c142
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.h35
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_reg.h (renamed from drivers/net/wireless/wl12xx/reg.h)223
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_rx.c200
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_rx.h121
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_spi.c (renamed from drivers/net/wireless/wl12xx/spi.c)194
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_spi.h (renamed from drivers/net/wireless/wl12xx/spi.h)68
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.c378
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.h130
-rw-r--r--drivers/net/wireless/wl3501_cs.c6
-rw-r--r--drivers/net/wireless/zd1201.c7
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c6
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h6
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c51
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c74
321 files changed, 44929 insertions, 21713 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 5bc00db21b24..ad89d23968df 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -2,10 +2,19 @@
# Wireless LAN device configuration
#
-menu "Wireless LAN"
+menuconfig WLAN
+ bool "Wireless LAN"
depends on !S390
+ ---help---
+ This section contains all the pre 802.11 and 802.11 wireless
+ device drivers. For a complete list of drivers and documentation
+ on them refer to the wireless wiki:
+
+ http://wireless.kernel.org/en/users/Drivers
+
+if WLAN
-config WLAN_PRE80211
+menuconfig WLAN_PRE80211
bool "Wireless LAN (pre-802.11)"
depends on NETDEVICES
---help---
@@ -101,7 +110,7 @@ config PCMCIA_NETWAVE
called netwave_cs. If unsure, say N.
-config WLAN_80211
+menuconfig WLAN_80211
bool "Wireless LAN (IEEE 802.11)"
depends on NETDEVICES
---help---
@@ -266,51 +275,26 @@ config PCMCIA_WL3501
micro support for ethtool.
config PRISM54
- tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus'
+ tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)'
depends on PCI && EXPERIMENTAL && WLAN_80211
select WIRELESS_EXT
select FW_LOADER
---help---
- Enable PCI and Cardbus support for the following chipset based cards:
-
- ISL3880 - Prism GT 802.11 b/g
- ISL3877 - Prism Indigo 802.11 a
- ISL3890 - Prism Duette 802.11 a/b/g
-
- For a complete list of supported cards visit <http://prism54.org>.
- Here is the latest confirmed list of supported cards:
-
- 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 (version 1)
- Allnet ALL0271 PCI Card
- Compex WL54G Cardbus Card
- Corega CG-WLCB54GT Cardbus Card
- D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650
- I-O Data WN-G54/CB Cardbus Card
- Kobishi XG-300 aka Z-Com Cardbus Card
- Netgear WG511 Cardbus Card
- Ovislink WL-5400PCI PCI Card
- Peabird WLG-PCI PCI Card
- Sitecom WL-100i Cardbus Card
- Sitecom WL-110i PCI Card
- SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card
- SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card
- SMC2835W-V2 - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card
- Z-Com XG-900 PCI Card
- Zyxel G-100 Cardbus Card
-
- If you enable this you will need a firmware file as well.
- You will need to copy this to /usr/lib/hotplug/firmware/isl3890.
- You can get this non-GPL'd firmware file from the Prism54 project page:
- <http://prism54.org>
- You will also need the /etc/hotplug/firmware.agent script from
- a current hotplug package.
-
- Note: You need a motherboard with DMA support to use any of these cards
-
- If you want to compile the driver as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/kbuild/modules.txt>.
- The module will be called prism54.
+ This enables support for FullMAC PCI/Cardbus prism54 devices. This
+ driver is now deprecated in favor for the SoftMAC driver, p54pci.
+ p54pci supports FullMAC PCI/Cardbus devices as well. For details on
+ the scheduled removal of this driver on the kernel see the feature
+ removal schedule:
+
+ Documentation/feature-removal-schedule.txt
+
+ For more information refer to the p54 wiki:
+
+ http://wireless.kernel.org/en/users/Drivers/p54
+
+ Note: You need a motherboard with DMA support to use any of these cards
+
+ When built as module you get the module prism54
config USB_ZD1201
tristate "USB ZD1201 based Wireless device support"
@@ -337,7 +321,6 @@ config USB_NET_RNDIS_WLAN
select USB_USBNET
select USB_NET_CDCETHER
select USB_NET_RNDIS_HOST
- select WIRELESS_EXT
---help---
This is a driver for wireless RNDIS devices.
These are USB based adapters found in devices such as:
@@ -428,10 +411,12 @@ config RTL8187
Micronet SP907GK V5
Encore ENUWI-G2
Trendnet TEW-424UB
- ASUS P5B Deluxe
+ ASUS P5B Deluxe/P5K Premium motherboards
Toshiba Satellite Pro series of laptops
Asus Wireless Link
- Linksys WUSB54GC-EU
+ Linksys WUSB54GC-EU v2
+ (v1 = rt73usb; v3 is rt2070-based,
+ use staging/rt3070 or try rt2800usb)
Thanks to Realtek for their support!
@@ -504,4 +489,4 @@ source "drivers/net/wireless/orinoco/Kconfig"
source "drivers/net/wireless/wl12xx/Kconfig"
source "drivers/net/wireless/iwmc3200wifi/Kconfig"
-endmenu
+endif # WLAN
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 2b9e379994a1..b80f514877d8 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -452,7 +452,8 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
rx_status.freq = adm8211_channels[priv->channel - 1].center_freq;
rx_status.band = IEEE80211_BAND_2GHZ;
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(dev, skb);
}
entry = (++priv->cur_rx) % priv->rx_ring_size;
@@ -1327,16 +1328,39 @@ static void adm8211_bss_info_changed(struct ieee80211_hw *dev,
}
}
+static u64 adm8211_prepare_multicast(struct ieee80211_hw *hw,
+ int mc_count, struct dev_addr_list *mclist)
+{
+ unsigned int bit_nr, i;
+ u32 mc_filter[2];
+
+ mc_filter[1] = mc_filter[0] = 0;
+
+ for (i = 0; i < mc_count; i++) {
+ if (!mclist)
+ break;
+ bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+ bit_nr &= 0x3F;
+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+ mclist = mclist->next;
+ }
+
+ return mc_filter[0] | ((u64)(mc_filter[1]) << 32);
+}
+
static void adm8211_configure_filter(struct ieee80211_hw *dev,
unsigned int changed_flags,
unsigned int *total_flags,
- int mc_count, struct dev_mc_list *mclist)
+ u64 multicast)
{
static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
struct adm8211_priv *priv = dev->priv;
- unsigned int bit_nr, new_flags;
+ unsigned int new_flags;
u32 mc_filter[2];
- int i;
+
+ mc_filter[0] = multicast;
+ mc_filter[1] = multicast >> 32;
new_flags = 0;
@@ -1345,23 +1369,13 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
priv->nar |= ADM8211_NAR_PR;
priv->nar &= ~ADM8211_NAR_MM;
mc_filter[1] = mc_filter[0] = ~0;
- } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
+ } else if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) {
new_flags |= FIF_ALLMULTI;
priv->nar &= ~ADM8211_NAR_PR;
priv->nar |= ADM8211_NAR_MM;
mc_filter[1] = mc_filter[0] = ~0;
} else {
priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
- mc_filter[1] = mc_filter[0] = 0;
- for (i = 0; i < mc_count; i++) {
- if (!mclist)
- break;
- bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
-
- bit_nr &= 0x3F;
- mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
- mclist = mclist->next;
- }
}
ADM8211_IDLE_RX();
@@ -1756,6 +1770,7 @@ static const struct ieee80211_ops adm8211_ops = {
.remove_interface = adm8211_remove_interface,
.config = adm8211_config,
.bss_info_changed = adm8211_bss_info_changed,
+ .prepare_multicast = adm8211_prepare_multicast,
.configure_filter = adm8211_configure_filter,
.get_stats = adm8211_get_stats,
.get_tx_stats = adm8211_get_tx_stats,
@@ -1963,14 +1978,6 @@ static void __devexit adm8211_remove(struct pci_dev *pdev)
#ifdef CONFIG_PM
static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct ieee80211_hw *dev = pci_get_drvdata(pdev);
- struct adm8211_priv *priv = dev->priv;
-
- if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
- ieee80211_stop_queues(dev);
- adm8211_stop(dev);
- }
-
pci_save_state(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
@@ -1978,17 +1985,8 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
static int adm8211_resume(struct pci_dev *pdev)
{
- struct ieee80211_hw *dev = pci_get_drvdata(pdev);
- struct adm8211_priv *priv = dev->priv;
-
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
-
- if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
- adm8211_start(dev);
- ieee80211_wake_queues(dev);
- }
-
return 0;
}
#endif /* CONFIG_PM */
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 8ce5e4cee168..7116a1aa20ce 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1920,14 +1920,16 @@ static int airo_open(struct net_device *dev) {
return 0;
}
-static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+static netdev_tx_t mpi_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
int npacks, pending;
unsigned long flags;
struct airo_info *ai = dev->ml_priv;
if (!skb) {
airo_print_err(dev->name, "%s: skb == NULL!",__func__);
- return 0;
+ return NETDEV_TX_OK;
}
npacks = skb_queue_len (&ai->txq);
@@ -1938,7 +1940,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
return NETDEV_TX_BUSY;
}
skb_queue_tail (&ai->txq, skb);
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&ai->aux_lock, flags);
@@ -1951,7 +1953,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
set_bit(FLAG_PENDING_XMIT, &ai->flags);
mpi_send_packet (dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -2119,7 +2121,9 @@ static void airo_end_xmit(struct net_device *dev) {
dev_kfree_skb(skb);
}
-static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+static netdev_tx_t airo_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
s16 len;
int i, j;
struct airo_info *priv = dev->ml_priv;
@@ -2127,7 +2131,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
if ( skb == NULL ) {
airo_print_err(dev->name, "%s: skb == NULL!", __func__);
- return 0;
+ return NETDEV_TX_OK;
}
/* Find a vacant FID */
@@ -2155,7 +2159,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
wake_up_interruptible(&priv->thr_wait);
} else
airo_end_xmit(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void airo_end_xmit11(struct net_device *dev) {
@@ -2184,7 +2188,9 @@ static void airo_end_xmit11(struct net_device *dev) {
dev_kfree_skb(skb);
}
-static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
+static netdev_tx_t airo_start_xmit11(struct sk_buff *skb,
+ struct net_device *dev)
+{
s16 len;
int i, j;
struct airo_info *priv = dev->ml_priv;
@@ -2199,7 +2205,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
if ( skb == NULL ) {
airo_print_err(dev->name, "%s: skb == NULL!", __func__);
- return 0;
+ return NETDEV_TX_OK;
}
/* Find a vacant FID */
@@ -2227,7 +2233,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
wake_up_interruptible(&priv->thr_wait);
} else
airo_end_xmit11(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void airo_read_stats(struct net_device *dev)
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index d84caf198a23..921a082487a1 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -77,7 +77,7 @@ struct arlan_conf_stru arlan_conf[MAX_ARLANS];
static int arlans_found;
static int arlan_open(struct net_device *dev);
-static int arlan_tx(struct sk_buff *skb, struct net_device *dev);
+static netdev_tx_t arlan_tx(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t arlan_interrupt(int irq, void *dev_id);
static int arlan_close(struct net_device *dev);
static struct net_device_stats *
@@ -1022,7 +1022,7 @@ static int arlan_mac_addr(struct net_device *dev, void *p)
ARLAN_DEBUG_ENTRY("arlan_mac_addr");
return -EINVAL;
- if (!netif_running(dev))
+ if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
@@ -1169,7 +1169,7 @@ static void arlan_tx_timeout (struct net_device *dev)
}
-static int arlan_tx(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t arlan_tx(struct sk_buff *skb, struct net_device *dev)
{
short length;
unsigned char *buf;
@@ -1193,7 +1193,7 @@ static int arlan_tx(struct sk_buff *skb, struct net_device *dev)
arlan_process_interrupt(dev);
ARLAN_DEBUG_EXIT("arlan_tx");
- return 0;
+ return NETDEV_TX_OK;
bad_end:
arlan_process_interrupt(dev);
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 4efbdbe6d6bf..8e1a55dec351 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1568,7 +1568,8 @@ static void at76_rx_tasklet(unsigned long param)
at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d",
priv->rx_skb->len, priv->rx_skb->data_len);
- ieee80211_rx_irqsafe(priv->hw, priv->rx_skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(priv->rx_skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(priv->hw, priv->rx_skb);
/* Use a new skb for the next receive */
priv->rx_skb = NULL;
@@ -1772,6 +1773,9 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw)
at76_dbg(DBG_MAC80211, "%s()", __func__);
+ cancel_delayed_work(&priv->dwork_hw_scan);
+ cancel_work_sync(&priv->work_set_promisc);
+
mutex_lock(&priv->mtx);
if (!priv->device_unplugged) {
@@ -1871,8 +1875,8 @@ static void at76_dwork_hw_scan(struct work_struct *work)
/* FIXME: add maximum time for scan to complete */
if (ret != CMD_STATUS_COMPLETE) {
- queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,
- SCAN_POLL_INTERVAL);
+ ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan,
+ SCAN_POLL_INTERVAL);
mutex_unlock(&priv->mtx);
return;
}
@@ -1933,8 +1937,8 @@ static int at76_hw_scan(struct ieee80211_hw *hw,
goto exit;
}
- queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,
- SCAN_POLL_INTERVAL);
+ ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan,
+ SCAN_POLL_INTERVAL);
exit:
mutex_unlock(&priv->mtx);
@@ -1946,9 +1950,8 @@ static int at76_config(struct ieee80211_hw *hw, u32 changed)
{
struct at76_priv *priv = hw->priv;
- at76_dbg(DBG_MAC80211, "%s(): channel %d radio %d",
- __func__, hw->conf.channel->hw_value,
- hw->conf.radio_enabled);
+ at76_dbg(DBG_MAC80211, "%s(): channel %d",
+ __func__, hw->conf.channel->hw_value);
at76_dbg_dump(DBG_MAC80211, priv->bssid, ETH_ALEN, "bssid:");
mutex_lock(&priv->mtx);
@@ -1993,15 +1996,14 @@ static void at76_bss_info_changed(struct ieee80211_hw *hw,
/* must be atomic */
static void at76_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
- unsigned int *total_flags, int mc_count,
- struct dev_addr_list *mc_list)
+ unsigned int *total_flags, u64 multicast)
{
struct at76_priv *priv = hw->priv;
int flags;
at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x "
- "total_flags=0x%08x mc_count=%d",
- __func__, changed_flags, *total_flags, mc_count);
+ "total_flags=0x%08x",
+ __func__, changed_flags, *total_flags);
flags = changed_flags & AT76_SUPPORTED_FILTERS;
*total_flags = AT76_SUPPORTED_FILTERS;
@@ -2023,7 +2025,7 @@ static void at76_configure_filter(struct ieee80211_hw *hw,
} else
return;
- queue_work(hw->workqueue, &priv->work_set_promisc);
+ ieee80211_queue_work(hw, &priv->work_set_promisc);
}
static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -2294,11 +2296,8 @@ static void at76_delete_device(struct at76_priv *priv)
tasklet_kill(&priv->rx_tasklet);
- if (priv->mac80211_registered) {
- cancel_delayed_work(&priv->dwork_hw_scan);
- flush_workqueue(priv->hw->workqueue);
+ if (priv->mac80211_registered)
ieee80211_unregister_hw(priv->hw);
- }
if (priv->tx_urb) {
usb_kill_urb(priv->tx_urb);
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index eb0337c49546..11ded150b932 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -1,9 +1,22 @@
-config ATH_COMMON
+menuconfig ATH_COMMON
tristate "Atheros Wireless Cards"
depends on WLAN_80211
- depends on ATH5K || ATH9K || AR9170_USB
+ depends on CFG80211
+ ---help---
+ This will enable the support for the Atheros wireless drivers.
+ ath5k, ath9k and ar9170 drivers share some common code, this option
+ enables the common ath.ko module which shares common helpers.
+ For more information and documentation on this module you can visit:
+
+ http://wireless.kernel.org/en/users/Drivers/ath
+
+ For information on all Atheros wireless drivers visit:
+
+ http://wireless.kernel.org/en/users/Drivers/Atheros
+
+if ATH_COMMON
source "drivers/net/wireless/ath/ath5k/Kconfig"
source "drivers/net/wireless/ath/ath9k/Kconfig"
source "drivers/net/wireless/ath/ar9170/Kconfig"
-
+endif
diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig
index b99e3263ee6d..05918f1e685a 100644
--- a/drivers/net/wireless/ath/ar9170/Kconfig
+++ b/drivers/net/wireless/ath/ar9170/Kconfig
@@ -1,13 +1,13 @@
config AR9170_USB
tristate "Atheros AR9170 802.11n USB support"
- depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL
+ depends on USB && MAC80211 && WLAN_80211
select FW_LOADER
- select ATH_COMMON
help
This is a driver for the Atheros "otus" 802.11n USB devices.
These devices require additional firmware (2 files).
For now, these files can be downloaded from here:
+
http://wireless.kernel.org/en/users/Drivers/ar9170
If you choose to build a module, it'll be called ar9170usb.
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index bb97981fb248..914e4718a9a8 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -109,13 +109,55 @@ struct ar9170_rxstream_mpdu_merge {
bool has_plcp;
};
+#define AR9170_NUM_MAX_BA_RETRY 5
+#define AR9170_NUM_TID 16
+#define WME_BA_BMP_SIZE 64
+#define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE)
+
+#define WME_AC_BE 2
+#define WME_AC_BK 3
+#define WME_AC_VI 1
+#define WME_AC_VO 0
+
+#define TID_TO_WME_AC(_tid) \
+ ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
+ (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
+ (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
+ WME_AC_VO)
+
+#define BAW_WITHIN(_start, _bawsz, _seqno) \
+ ((((_seqno) - (_start)) & 0xfff) < (_bawsz))
+
+enum ar9170_tid_state {
+ AR9170_TID_STATE_INVALID,
+ AR9170_TID_STATE_SHUTDOWN,
+ AR9170_TID_STATE_PROGRESS,
+ AR9170_TID_STATE_COMPLETE,
+};
+
+struct ar9170_sta_tid {
+ struct list_head list;
+ struct sk_buff_head queue;
+ u8 addr[ETH_ALEN];
+ u16 ssn;
+ u16 tid;
+ enum ar9170_tid_state state;
+ bool active;
+ u8 retry;
+};
+
#define AR9170_QUEUE_TIMEOUT 64
#define AR9170_TX_TIMEOUT 8
+#define AR9170_BA_TIMEOUT 4
#define AR9170_JANITOR_DELAY 128
#define AR9170_TX_INVALID_RATE 0xffffffff
+#define AR9170_NUM_TX_STATUS 128
+#define AR9170_NUM_TX_AGG_MAX 30
+
struct ar9170 {
struct ieee80211_hw *hw;
+ struct ath_common common;
struct mutex mutex;
enum ar9170_device_state state;
unsigned long bad_hw_nagger;
@@ -136,6 +178,7 @@ struct ar9170 {
/* beaconing */
struct sk_buff *beacon;
struct work_struct beacon_work;
+ bool enable_beacon;
/* cryptographic engine */
u64 usedkeys;
@@ -143,10 +186,8 @@ struct ar9170 {
bool disable_offload;
/* filter settings */
- struct work_struct filter_config_work;
- u64 cur_mc_hash, want_mc_hash;
- u32 cur_filter, want_filter;
- unsigned long filter_changed;
+ u64 cur_mc_hash;
+ u32 cur_filter;
unsigned int filter_state;
bool sniffer_enabled;
@@ -181,20 +222,30 @@ struct ar9170 {
/* EEPROM */
struct ar9170_eeprom eeprom;
- struct ath_regulatory regulatory;
/* tx queues - as seen by hw - */
struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
struct delayed_work tx_janitor;
+ /* tx ampdu */
+ struct sk_buff_head tx_status_ampdu;
+ spinlock_t tx_ampdu_list_lock;
+ struct list_head tx_ampdu_list;
+ unsigned int tx_ampdu_pending;
/* rxstream mpdu merge */
struct ar9170_rxstream_mpdu_merge rx_mpdu;
struct sk_buff *rx_failover;
int rx_failover_missing;
+
+ /* (cached) HW A-MPDU settings */
+ u8 global_ampdu_density;
+ u8 global_ampdu_factor;
};
struct ar9170_sta_info {
+ struct ar9170_sta_tid agg[AR9170_NUM_TID];
+ unsigned int ampdu_max_len;
};
#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0)
@@ -209,10 +260,6 @@ struct ar9170_tx_info {
#define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED)
#define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE)
-#define AR9170_FILTER_CHANGED_MODE BIT(0)
-#define AR9170_FILTER_CHANGED_MULTICAST BIT(1)
-#define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2)
-
/* exported interface */
void *ar9170_alloc(size_t priv_size);
int ar9170_register(struct ar9170 *ar, struct device *pdev);
@@ -226,8 +273,8 @@ int ar9170_nag_limiter(struct ar9170 *ar);
int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
int ar9170_init_mac(struct ar9170 *ar);
int ar9170_set_qos(struct ar9170 *ar);
-int ar9170_update_multicast(struct ar9170 *ar);
-int ar9170_update_frame_filter(struct ar9170 *ar);
+int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hast);
+int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter);
int ar9170_set_operating_mode(struct ar9170 *ar);
int ar9170_set_beacon_timers(struct ar9170 *ar);
int ar9170_set_dyn_sifs_ack(struct ar9170 *ar);
diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c
index 63fda6cd2101..86c4e79f6bc8 100644
--- a/drivers/net/wireless/ath/ar9170/led.c
+++ b/drivers/net/wireless/ath/ar9170/led.c
@@ -90,9 +90,12 @@ static void ar9170_update_leds(struct work_struct *work)
ar9170_set_leds_state(ar, led_val);
mutex_unlock(&ar->mutex);
- if (rerun)
- queue_delayed_work(ar->hw->workqueue, &ar->led_work,
- msecs_to_jiffies(blink_delay));
+ if (!rerun)
+ return;
+
+ ieee80211_queue_delayed_work(ar->hw,
+ &ar->led_work,
+ msecs_to_jiffies(blink_delay));
}
static void ar9170_led_brightness_set(struct led_classdev *led,
@@ -110,7 +113,7 @@ static void ar9170_led_brightness_set(struct led_classdev *led,
}
if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled))
- queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10);
+ ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10);
}
static int ar9170_register_led(struct ar9170 *ar, int i, char *name,
diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c
index d9f1f46de183..614e3218a2bc 100644
--- a/drivers/net/wireless/ath/ar9170/mac.c
+++ b/drivers/net/wireless/ath/ar9170/mac.c
@@ -238,39 +238,31 @@ static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac)
return ar9170_regwrite_result();
}
-int ar9170_update_multicast(struct ar9170 *ar)
+int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hash)
{
int err;
ar9170_regwrite_begin(ar);
- ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H,
- ar->want_mc_hash >> 32);
- ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L,
- ar->want_mc_hash);
-
+ ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32);
+ ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash);
ar9170_regwrite_finish();
err = ar9170_regwrite_result();
-
if (err)
return err;
- ar->cur_mc_hash = ar->want_mc_hash;
-
+ ar->cur_mc_hash = mc_hash;
return 0;
}
-int ar9170_update_frame_filter(struct ar9170 *ar)
+int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter)
{
int err;
- err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER,
- ar->want_filter);
-
+ err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, filter);
if (err)
return err;
- ar->cur_filter = ar->want_filter;
-
+ ar->cur_filter = filter;
return 0;
}
@@ -391,24 +383,26 @@ int ar9170_set_beacon_timers(struct ar9170 *ar)
if (ar->vif) {
v |= ar->vif->bss_conf.beacon_int;
- switch (ar->vif->type) {
- case NL80211_IFTYPE_MESH_POINT:
- case NL80211_IFTYPE_ADHOC:
- v |= BIT(25);
- break;
- case NL80211_IFTYPE_AP:
- v |= BIT(24);
- pretbtt = (ar->vif->bss_conf.beacon_int - 6) << 16;
- break;
- default:
+ if (ar->enable_beacon) {
+ switch (ar->vif->type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_ADHOC:
+ v |= BIT(25);
+ break;
+ case NL80211_IFTYPE_AP:
+ v |= BIT(24);
+ pretbtt = (ar->vif->bss_conf.beacon_int - 6) <<
+ 16;
+ break;
+ default:
break;
+ }
}
v |= ar->vif->bss_conf.dtim_period << 16;
}
ar9170_regwrite_begin(ar);
-
ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt);
ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v);
ar9170_regwrite_finish();
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 88c3d8573869..c1f8c69db165 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -49,6 +49,10 @@ static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+static int modparam_ht;
+module_param_named(ht, modparam_ht, bool, S_IRUGO);
+MODULE_PARM_DESC(ht, "enable MPDU aggregation.");
+
#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \
.bitrate = (_bitrate), \
.flags = (_flags), \
@@ -148,12 +152,15 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
.cap = IEEE80211_HT_CAP_MAX_AMSDU | \
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
IEEE80211_HT_CAP_SGI_40 | \
+ IEEE80211_HT_CAP_GRN_FLD | \
IEEE80211_HT_CAP_DSSSCCK40 | \
IEEE80211_HT_CAP_SM_PS, \
.ampdu_factor = 3, \
.ampdu_density = 6, \
.mcs = { \
- .rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \
+ .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \
+ .rx_highest = cpu_to_le16(300), \
+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
}, \
}
@@ -174,8 +181,31 @@ static struct ieee80211_supported_band ar9170_band_5GHz = {
};
static void ar9170_tx(struct ar9170 *ar);
+static bool ar9170_tx_ampdu(struct ar9170 *ar);
-#ifdef AR9170_QUEUE_DEBUG
+static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr)
+{
+ return le16_to_cpu(hdr->seq_ctrl) >> 4;
+}
+
+static inline u16 ar9170_get_seq(struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+ return ar9170_get_seq_h((void *) txc->frame_data);
+}
+
+static inline u16 ar9170_get_tid(struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+ struct ieee80211_hdr *hdr = (void *) txc->frame_data;
+
+ return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
+#define GET_NEXT_SEQ(seq) ((seq + 1) & 0x0fff)
+#define GET_NEXT_SEQ_FROM_SKB(skb) (GET_NEXT_SEQ(ar9170_get_seq(skb)))
+
+#if (defined AR9170_QUEUE_DEBUG) || (defined AR9170_TXAGG_DEBUG)
static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
{
struct ar9170_tx_control *txc = (void *) skb->data;
@@ -183,10 +213,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
struct ieee80211_hdr *hdr = (void *) txc->frame_data;
- printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x "
+ printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d "
"mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
- ieee80211_get_DA(hdr), arinfo->flags,
+ ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr),
le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
jiffies_to_msecs(arinfo->timeout - jiffies));
}
@@ -210,7 +240,9 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar,
"mismatch %d != %d\n", skb_queue_len(queue), i);
printk(KERN_DEBUG "---[ end ]---\n");
}
+#endif /* AR9170_QUEUE_DEBUG || AR9170_TXAGG_DEBUG */
+#ifdef AR9170_QUEUE_DEBUG
static void ar9170_dump_txqueue(struct ar9170 *ar,
struct sk_buff_head *queue)
{
@@ -220,7 +252,9 @@ static void ar9170_dump_txqueue(struct ar9170 *ar,
__ar9170_dump_txqueue(ar, queue);
spin_unlock_irqrestore(&queue->lock, flags);
}
+#endif /* AR9170_QUEUE_DEBUG */
+#ifdef AR9170_QUEUE_STOP_DEBUG
static void __ar9170_dump_txstats(struct ar9170 *ar)
{
int i;
@@ -229,20 +263,27 @@ static void __ar9170_dump_txstats(struct ar9170 *ar)
wiphy_name(ar->hw->wiphy));
for (i = 0; i < __AR9170_NUM_TXQ; i++)
- printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n",
- wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit,
- ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i]));
+ printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d "
+ " stopped:%d\n", wiphy_name(ar->hw->wiphy), i,
+ ar->tx_stats[i].limit, ar->tx_stats[i].len,
+ skb_queue_len(&ar->tx_status[i]),
+ ieee80211_queue_stopped(ar->hw, i));
}
+#endif /* AR9170_QUEUE_STOP_DEBUG */
-static void ar9170_dump_txstats(struct ar9170 *ar)
+#ifdef AR9170_TXAGG_DEBUG
+static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar)
{
unsigned long flags;
- spin_lock_irqsave(&ar->tx_stats_lock, flags);
- __ar9170_dump_txstats(ar);
- spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
+ spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags);
+ printk(KERN_DEBUG "%s: A-MPDU tx_status queue => \n",
+ wiphy_name(ar->hw->wiphy));
+ __ar9170_dump_txqueue(ar, &ar->tx_status_ampdu);
+ spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags);
}
-#endif /* AR9170_QUEUE_DEBUG */
+
+#endif /* AR9170_TXAGG_DEBUG */
/* caller must guarantee exclusive access for _bin_ queue. */
static void ar9170_recycle_expired(struct ar9170 *ar,
@@ -315,6 +356,70 @@ static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
ieee80211_tx_status_irqsafe(ar->hw, skb);
}
+static void ar9170_tx_fake_ampdu_status(struct ar9170 *ar)
+{
+ struct sk_buff_head success;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned long queue_bitmap = 0;
+
+ skb_queue_head_init(&success);
+
+ while (skb_queue_len(&ar->tx_status_ampdu) > AR9170_NUM_TX_STATUS)
+ __skb_queue_tail(&success, skb_dequeue(&ar->tx_status_ampdu));
+
+ ar9170_recycle_expired(ar, &ar->tx_status_ampdu, &success);
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: collected %d A-MPDU frames.\n",
+ wiphy_name(ar->hw->wiphy), skb_queue_len(&success));
+ __ar9170_dump_txqueue(ar, &success);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ while ((skb = __skb_dequeue(&success))) {
+ struct ieee80211_tx_info *txinfo;
+
+ queue_bitmap |= BIT(skb_get_queue_mapping(skb));
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ ieee80211_tx_info_clear_status(txinfo);
+
+ txinfo->flags |= IEEE80211_TX_STAT_ACK;
+ txinfo->status.rates[0].count = 1;
+
+ skb_pull(skb, sizeof(struct ar9170_tx_control));
+ ieee80211_tx_status_irqsafe(ar->hw, skb);
+ }
+
+ for_each_bit(i, &queue_bitmap, BITS_PER_BYTE) {
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: wake queue %d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
+ ieee80211_wake_queue(ar->hw, i);
+ }
+
+ if (queue_bitmap)
+ ar9170_tx(ar);
+}
+
+static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
+ struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
+
+ arinfo->timeout = jiffies +
+ msecs_to_jiffies(AR9170_BA_TIMEOUT);
+
+ skb_queue_tail(&ar->tx_status_ampdu, skb);
+ ar9170_tx_fake_ampdu_status(ar);
+ ar->tx_ampdu_pending--;
+
+ if (!list_empty(&ar->tx_ampdu_list) && !ar->tx_ampdu_pending)
+ ar9170_tx_ampdu(ar);
+}
+
void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -336,7 +441,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) {
- dev_kfree_skb_any(skb);
+ ar9170_tx_ampdu_callback(ar, skb);
} else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) {
arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT);
@@ -420,6 +525,38 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
return NULL;
}
+static void ar9170_handle_block_ack(struct ar9170 *ar, u16 count, u16 r)
+{
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *txinfo;
+
+ while (count) {
+ skb = ar9170_get_queued_skb(ar, NULL, &ar->tx_status_ampdu, r);
+ if (!skb)
+ break;
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ ieee80211_tx_info_clear_status(txinfo);
+
+ /* FIXME: maybe more ? */
+ txinfo->status.rates[0].count = 1;
+
+ skb_pull(skb, sizeof(struct ar9170_tx_control));
+ ieee80211_tx_status_irqsafe(ar->hw, skb);
+ count--;
+ }
+
+#ifdef AR9170_TXAGG_DEBUG
+ if (count) {
+ printk(KERN_DEBUG "%s: got %d more failed mpdus, but no more "
+ "suitable frames left in tx_status queue.\n",
+ wiphy_name(ar->hw->wiphy), count);
+
+ ar9170_dump_tx_status_ampdu(ar);
+ }
+#endif /* AR9170_TXAGG_DEBUG */
+}
+
/*
* This worker tries to keeps an maintain tx_status queues.
* So we can guarantee that incoming tx_status reports are
@@ -456,10 +593,14 @@ static void ar9170_tx_janitor(struct work_struct *work)
resched = true;
}
- if (resched)
- queue_delayed_work(ar->hw->workqueue,
- &ar->tx_janitor,
- msecs_to_jiffies(AR9170_JANITOR_DELAY));
+ ar9170_tx_fake_ampdu_status(ar);
+
+ if (!resched)
+ return;
+
+ ieee80211_queue_delayed_work(ar->hw,
+ &ar->tx_janitor,
+ msecs_to_jiffies(AR9170_JANITOR_DELAY));
}
void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
@@ -509,7 +650,7 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
* pre-TBTT event
*/
if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP)
- queue_work(ar->hw->workqueue, &ar->beacon_work);
+ ieee80211_queue_work(ar->hw, &ar->beacon_work);
break;
case 0xc2:
@@ -528,8 +669,15 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
break;
case 0xc4:
+ /* BlockACK bitmap */
+ break;
+
case 0xc5:
/* BlockACK events */
+ ar9170_handle_block_ack(ar,
+ le16_to_cpu(cmd->ba_fail_cnt.failed),
+ le16_to_cpu(cmd->ba_fail_cnt.rate));
+ ar9170_tx_fake_ampdu_status(ar);
break;
case 0xc6:
@@ -917,8 +1065,10 @@ static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
ar9170_rx_phy_status(ar, phy, &status);
skb = ar9170_rx_copy_data(buf, mpdu_len);
- if (likely(skb))
- ieee80211_rx_irqsafe(ar->hw, skb, &status);
+ if (likely(skb)) {
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(ar->hw, skb);
+ }
}
void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
@@ -1082,8 +1232,6 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
mutex_lock(&ar->mutex);
- ar->filter_changed = 0;
-
/* reinitialize queues statistics */
memset(&ar->tx_stats, 0, sizeof(ar->tx_stats));
for (i = 0; i < __AR9170_NUM_TXQ; i++)
@@ -1096,6 +1244,10 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */
AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */
+ /* set sane AMPDU defaults */
+ ar->global_ampdu_density = 6;
+ ar->global_ampdu_factor = 3;
+
ar->bad_hw_nagger = jiffies;
err = ar->open(ar);
@@ -1138,11 +1290,12 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
if (IS_STARTED(ar))
ar->state = AR9170_IDLE;
- flush_workqueue(ar->hw->workqueue);
-
cancel_delayed_work_sync(&ar->tx_janitor);
- cancel_work_sync(&ar->filter_config_work);
+#ifdef CONFIG_AR9170_LEDS
+ cancel_delayed_work_sync(&ar->led_work);
+#endif
cancel_work_sync(&ar->beacon_work);
+
mutex_lock(&ar->mutex);
if (IS_ACCEPTING_CMD(ar)) {
@@ -1157,9 +1310,40 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
skb_queue_purge(&ar->tx_pending[i]);
skb_queue_purge(&ar->tx_status[i]);
}
+ skb_queue_purge(&ar->tx_status_ampdu);
+
mutex_unlock(&ar->mutex);
}
+static void ar9170_tx_indicate_immba(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+
+ txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_IMM_AMPDU);
+}
+
+static void ar9170_tx_copy_phy(struct ar9170 *ar, struct sk_buff *dst,
+ struct sk_buff *src)
+{
+ struct ar9170_tx_control *dst_txc, *src_txc;
+ struct ieee80211_tx_info *dst_info, *src_info;
+ struct ar9170_tx_info *dst_arinfo, *src_arinfo;
+
+ src_txc = (void *) src->data;
+ src_info = IEEE80211_SKB_CB(src);
+ src_arinfo = (void *) src_info->rate_driver_data;
+
+ dst_txc = (void *) dst->data;
+ dst_info = IEEE80211_SKB_CB(dst);
+ dst_arinfo = (void *) dst_info->rate_driver_data;
+
+ dst_txc->phy_control = src_txc->phy_control;
+
+ /* same MCS for the whole aggregate */
+ memcpy(dst_info->driver_rates, src_info->driver_rates,
+ sizeof(dst_info->driver_rates));
+}
+
static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
@@ -1228,6 +1412,7 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK;
+
goto out;
}
@@ -1358,6 +1543,159 @@ static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb)
txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT);
}
+static bool ar9170_tx_ampdu(struct ar9170 *ar)
+{
+ struct sk_buff_head agg;
+ struct ar9170_sta_tid *tid_info = NULL, *tmp;
+ struct sk_buff *skb, *first = NULL;
+ unsigned long flags, f2;
+ unsigned int i = 0;
+ u16 seq, queue, tmpssn;
+ bool run = false;
+
+ skb_queue_head_init(&agg);
+
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ if (list_empty(&ar->tx_ampdu_list)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: aggregation list is empty.\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ goto out_unlock;
+ }
+
+ list_for_each_entry_safe(tid_info, tmp, &ar->tx_ampdu_list, list) {
+ if (tid_info->state != AR9170_TID_STATE_COMPLETE) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: dangling aggregation entry!\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ continue;
+ }
+
+ if (++i > 64) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: enough frames aggregated.\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ break;
+ }
+
+ queue = TID_TO_WME_AC(tid_info->tid);
+
+ if (skb_queue_len(&ar->tx_pending[queue]) >=
+ AR9170_NUM_TX_AGG_MAX) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: queue %d full.\n",
+ wiphy_name(ar->hw->wiphy), queue);
+#endif /* AR9170_TXAGG_DEBUG */
+ continue;
+ }
+
+ list_del_init(&tid_info->list);
+
+ spin_lock_irqsave(&tid_info->queue.lock, f2);
+ tmpssn = seq = tid_info->ssn;
+ first = skb_peek(&tid_info->queue);
+
+ if (likely(first))
+ tmpssn = ar9170_get_seq(first);
+
+ if (unlikely(tmpssn != seq)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: ssn mismatch [%d != %d]\n.",
+ wiphy_name(ar->hw->wiphy), seq, tmpssn);
+#endif /* AR9170_TXAGG_DEBUG */
+ tid_info->ssn = tmpssn;
+ }
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: generate A-MPDU for tid:%d ssn:%d with "
+ "%d queued frames.\n", wiphy_name(ar->hw->wiphy),
+ tid_info->tid, tid_info->ssn,
+ skb_queue_len(&tid_info->queue));
+ __ar9170_dump_txqueue(ar, &tid_info->queue);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ while ((skb = skb_peek(&tid_info->queue))) {
+ if (unlikely(ar9170_get_seq(skb) != seq))
+ break;
+
+ __skb_unlink(skb, &tid_info->queue);
+ tid_info->ssn = seq = GET_NEXT_SEQ(seq);
+
+ if (unlikely(skb_get_queue_mapping(skb) != queue)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: tid:%d(q:%d) queue:%d "
+ "!match.\n", wiphy_name(ar->hw->wiphy),
+ tid_info->tid,
+ TID_TO_WME_AC(tid_info->tid),
+ skb_get_queue_mapping(skb));
+#endif /* AR9170_TXAGG_DEBUG */
+ dev_kfree_skb_any(skb);
+ continue;
+ }
+
+ if (unlikely(first == skb)) {
+ ar9170_tx_prepare_phy(ar, skb);
+ __skb_queue_tail(&agg, skb);
+ first = skb;
+ } else {
+ ar9170_tx_copy_phy(ar, skb, first);
+ __skb_queue_tail(&agg, skb);
+ }
+
+ if (unlikely(skb_queue_len(&agg) ==
+ AR9170_NUM_TX_AGG_MAX))
+ break;
+ }
+
+ if (skb_queue_empty(&tid_info->queue))
+ tid_info->active = false;
+ else
+ list_add_tail(&tid_info->list,
+ &ar->tx_ampdu_list);
+
+ spin_unlock_irqrestore(&tid_info->queue.lock, f2);
+
+ if (unlikely(skb_queue_empty(&agg))) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: queued empty list!\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ continue;
+ }
+
+ /*
+ * tell the FW/HW that this is the last frame,
+ * that way it will wait for the immediate block ack.
+ */
+ if (likely(skb_peek_tail(&agg)))
+ ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
+ wiphy_name(ar->hw->wiphy));
+ __ar9170_dump_txqueue(ar, &agg);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+
+ spin_lock_irqsave(&ar->tx_pending[queue].lock, flags);
+ skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]);
+ spin_unlock_irqrestore(&ar->tx_pending[queue].lock, flags);
+ run = true;
+
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ }
+
+out_unlock:
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ __skb_queue_purge(&agg);
+
+ return run;
+}
+
static void ar9170_tx(struct ar9170 *ar)
{
struct sk_buff *skb;
@@ -1382,11 +1720,17 @@ static void ar9170_tx(struct ar9170 *ar)
printk(KERN_DEBUG "%s: queue %d full\n",
wiphy_name(ar->hw->wiphy), i);
- __ar9170_dump_txstats(ar);
- printk(KERN_DEBUG "stuck frames: ===> \n");
+ printk(KERN_DEBUG "%s: stuck frames: ===> \n",
+ wiphy_name(ar->hw->wiphy));
ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
ar9170_dump_txqueue(ar, &ar->tx_status[i]);
#endif /* AR9170_QUEUE_DEBUG */
+
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: stop queue %d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_stop_queue(ar->hw, i);
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
continue;
@@ -1401,8 +1745,6 @@ static void ar9170_tx(struct ar9170 *ar)
"remaining slots:%d, needed:%d\n",
wiphy_name(ar->hw->wiphy), i, remaining_space,
frames);
-
- ar9170_dump_txstats(ar);
#endif /* AR9170_QUEUE_DEBUG */
frames = remaining_space;
}
@@ -1430,6 +1772,9 @@ static void ar9170_tx(struct ar9170 *ar)
arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT);
+ if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+ ar->tx_ampdu_pending++;
+
#ifdef AR9170_QUEUE_DEBUG
printk(KERN_DEBUG "%s: send frame q:%d =>\n",
wiphy_name(ar->hw->wiphy), i);
@@ -1438,6 +1783,9 @@ static void ar9170_tx(struct ar9170 *ar)
err = ar->tx(ar, skb);
if (unlikely(err)) {
+ if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+ ar->tx_ampdu_pending--;
+
frames_failed++;
dev_kfree_skb_any(skb);
} else {
@@ -1459,22 +1807,113 @@ static void ar9170_tx(struct ar9170 *ar)
if (unlikely(frames_failed)) {
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: frames failed =>\n",
+ printk(KERN_DEBUG "%s: frames failed %d =>\n",
wiphy_name(ar->hw->wiphy), frames_failed);
#endif /* AR9170_QUEUE_DEBUG */
spin_lock_irqsave(&ar->tx_stats_lock, flags);
ar->tx_stats[i].len -= frames_failed;
ar->tx_stats[i].count -= frames_failed;
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: wake queue %d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_wake_queue(ar->hw, i);
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
}
}
- if (schedule_garbagecollector)
- queue_delayed_work(ar->hw->workqueue,
- &ar->tx_janitor,
- msecs_to_jiffies(AR9170_JANITOR_DELAY));
+ if (!schedule_garbagecollector)
+ return;
+
+ ieee80211_queue_delayed_work(ar->hw,
+ &ar->tx_janitor,
+ msecs_to_jiffies(AR9170_JANITOR_DELAY));
+}
+
+static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *txinfo;
+ struct ar9170_sta_info *sta_info;
+ struct ar9170_sta_tid *agg;
+ struct sk_buff *iter;
+ unsigned long flags, f2;
+ unsigned int max;
+ u16 tid, seq, qseq;
+ bool run = false, queue = false;
+
+ tid = ar9170_get_tid(skb);
+ seq = ar9170_get_seq(skb);
+ txinfo = IEEE80211_SKB_CB(skb);
+ sta_info = (void *) txinfo->control.sta->drv_priv;
+ agg = &sta_info->agg[tid];
+ max = sta_info->ampdu_max_len;
+
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+
+ if (unlikely(agg->state != AR9170_TID_STATE_COMPLETE)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: BlockACK session not fully initialized "
+ "for ESS:%pM tid:%d state:%d.\n",
+ wiphy_name(ar->hw->wiphy), agg->addr, agg->tid,
+ agg->state);
+#endif /* AR9170_TXAGG_DEBUG */
+ goto err_unlock;
+ }
+
+ if (!agg->active) {
+ agg->active = true;
+ agg->ssn = seq;
+ queue = true;
+ }
+
+ /* check if seq is within the BA window */
+ if (unlikely(!BAW_WITHIN(agg->ssn, max, seq))) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: frame with tid:%d seq:%d does not "
+ "fit into BA window (%d - %d)\n",
+ wiphy_name(ar->hw->wiphy), tid, seq, agg->ssn,
+ (agg->ssn + max) & 0xfff);
+#endif /* AR9170_TXAGG_DEBUG */
+ goto err_unlock;
+ }
+
+ spin_lock_irqsave(&agg->queue.lock, f2);
+
+ skb_queue_reverse_walk(&agg->queue, iter) {
+ qseq = ar9170_get_seq(iter);
+
+ if (GET_NEXT_SEQ(qseq) == seq) {
+ __skb_queue_after(&agg->queue, iter, skb);
+ goto queued;
+ }
+ }
+
+ __skb_queue_head(&agg->queue, skb);
+
+queued:
+ spin_unlock_irqrestore(&agg->queue.lock, f2);
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: new aggregate %p queued.\n",
+ wiphy_name(ar->hw->wiphy), skb);
+ __ar9170_dump_txqueue(ar, &agg->queue);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ if (skb_queue_len(&agg->queue) >= AR9170_NUM_TX_AGG_MAX)
+ run = true;
+
+ if (queue)
+ list_add_tail(&agg->list, &ar->tx_ampdu_list);
+
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ return run;
+
+err_unlock:
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ dev_kfree_skb_irq(skb);
+ return false;
}
int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
@@ -1490,8 +1929,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
info = IEEE80211_SKB_CB(skb);
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
- /* drop frame, we do not allow TX A-MPDU aggregation yet. */
- goto err_free;
+ bool run = ar9170_tx_ampdu_queue(ar, skb);
+
+ if (run || !ar->tx_ampdu_pending)
+ ar9170_tx_ampdu(ar);
} else {
unsigned int queue = skb_get_queue_mapping(skb);
@@ -1529,8 +1970,7 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw,
}
ar->cur_filter = 0;
- ar->want_filter = AR9170_MAC_REG_FTF_DEFAULTS;
- err = ar9170_update_frame_filter(ar);
+ err = ar9170_update_frame_filter(ar, AR9170_MAC_REG_FTF_DEFAULTS);
if (err)
goto unlock;
@@ -1548,8 +1988,7 @@ static void ar9170_op_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&ar->mutex);
ar->vif = NULL;
- ar->want_filter = 0;
- ar9170_update_frame_filter(ar);
+ ar9170_update_frame_filter(ar, 0);
ar9170_set_beacon_timers(ar);
dev_kfree_skb(ar->beacon);
ar->beacon = NULL;
@@ -1592,12 +2031,6 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
goto out;
}
- if (changed & BSS_CHANGED_BEACON_INT) {
- err = ar9170_set_beacon_timers(ar);
- if (err)
- goto out;
- }
-
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
/* adjust slot time for 5 GHz */
@@ -1621,48 +2054,37 @@ out:
return err;
}
-static void ar9170_set_filters(struct work_struct *work)
+static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
+ struct dev_addr_list *mclist)
{
- struct ar9170 *ar = container_of(work, struct ar9170,
- filter_config_work);
- int err;
-
- if (unlikely(!IS_STARTED(ar)))
- return ;
-
- mutex_lock(&ar->mutex);
- if (test_and_clear_bit(AR9170_FILTER_CHANGED_MODE,
- &ar->filter_changed)) {
- err = ar9170_set_operating_mode(ar);
- if (err)
- goto unlock;
- }
+ u64 mchash;
+ int i;
- if (test_and_clear_bit(AR9170_FILTER_CHANGED_MULTICAST,
- &ar->filter_changed)) {
- err = ar9170_update_multicast(ar);
- if (err)
- goto unlock;
- }
+ /* always get broadcast frames */
+ mchash = 1ULL << (0xff >> 2);
- if (test_and_clear_bit(AR9170_FILTER_CHANGED_FRAMEFILTER,
- &ar->filter_changed)) {
- err = ar9170_update_frame_filter(ar);
- if (err)
- goto unlock;
+ for (i = 0; i < mc_count; i++) {
+ if (WARN_ON(!mclist))
+ break;
+ mchash |= 1ULL << (mclist->dmi_addr[5] >> 2);
+ mclist = mclist->next;
}
-unlock:
- mutex_unlock(&ar->mutex);
+ return mchash;
}
static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *new_flags,
- int mc_count, struct dev_mc_list *mclist)
+ u64 multicast)
{
struct ar9170 *ar = hw->priv;
+ if (unlikely(!IS_ACCEPTING_CMD(ar)))
+ return ;
+
+ mutex_lock(&ar->mutex);
+
/* mask supported flags */
*new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC |
FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL;
@@ -1672,26 +2094,11 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
* then checking the error flags, later.
*/
- if (changed_flags & FIF_ALLMULTI) {
- if (*new_flags & FIF_ALLMULTI) {
- ar->want_mc_hash = ~0ULL;
- } else {
- u64 mchash;
- int i;
-
- /* always get broadcast frames */
- mchash = 1ULL << (0xff >> 2);
+ if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI)
+ multicast = ~0ULL;
- for (i = 0; i < mc_count; i++) {
- if (WARN_ON(!mclist))
- break;
- mchash |= 1ULL << (mclist->dmi_addr[5] >> 2);
- mclist = mclist->next;
- }
- ar->want_mc_hash = mchash;
- }
- set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed);
- }
+ if (multicast != ar->cur_mc_hash)
+ ar9170_update_multicast(ar, multicast);
if (changed_flags & FIF_CONTROL) {
u32 filter = AR9170_MAC_REG_FTF_PSPOLL |
@@ -1702,24 +2109,22 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
AR9170_MAC_REG_FTF_CFE_ACK;
if (*new_flags & FIF_CONTROL)
- ar->want_filter = ar->cur_filter | filter;
+ filter |= ar->cur_filter;
else
- ar->want_filter = ar->cur_filter & ~filter;
+ filter &= (~ar->cur_filter);
- set_bit(AR9170_FILTER_CHANGED_FRAMEFILTER,
- &ar->filter_changed);
+ ar9170_update_frame_filter(ar, filter);
}
if (changed_flags & FIF_PROMISC_IN_BSS) {
ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0;
- set_bit(AR9170_FILTER_CHANGED_MODE,
- &ar->filter_changed);
+ ar9170_set_operating_mode(ar);
}
- if (likely(IS_STARTED(ar)))
- queue_work(ar->hw->workqueue, &ar->filter_config_work);
+ mutex_unlock(&ar->mutex);
}
+
static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -1737,11 +2142,17 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
goto out;
}
- if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) {
+ if (changed & BSS_CHANGED_BEACON_ENABLED)
+ ar->enable_beacon = bss_conf->enable_beacon;
+
+ if (changed & BSS_CHANGED_BEACON) {
err = ar9170_update_beacon(ar);
if (err)
goto out;
+ }
+ if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON |
+ BSS_CHANGED_BEACON_INT)) {
err = ar9170_set_beacon_timers(ar);
if (err)
goto out;
@@ -1754,12 +2165,6 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
#endif /* CONFIG_AR9170_LEDS */
}
- if (changed & BSS_CHANGED_BEACON_INT) {
- err = ar9170_set_beacon_timers(ar);
- if (err)
- goto out;
- }
-
if (changed & BSS_CHANGED_HT) {
/* TODO */
err = 0;
@@ -1929,6 +2334,50 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta)
{
+ struct ar9170 *ar = hw->priv;
+ struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
+ unsigned int i;
+
+ switch (cmd) {
+ case STA_NOTIFY_ADD:
+ memset(sta_info, 0, sizeof(*sta_info));
+
+ if (!sta->ht_cap.ht_supported)
+ break;
+
+ if (sta->ht_cap.ampdu_density > ar->global_ampdu_density)
+ ar->global_ampdu_density = sta->ht_cap.ampdu_density;
+
+ if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor)
+ ar->global_ampdu_factor = sta->ht_cap.ampdu_factor;
+
+ for (i = 0; i < AR9170_NUM_TID; i++) {
+ sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
+ sta_info->agg[i].active = false;
+ sta_info->agg[i].ssn = 0;
+ sta_info->agg[i].retry = 0;
+ sta_info->agg[i].tid = i;
+ INIT_LIST_HEAD(&sta_info->agg[i].list);
+ skb_queue_head_init(&sta_info->agg[i].queue);
+ }
+
+ sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
+ break;
+
+ case STA_NOTIFY_REMOVE:
+ if (!sta->ht_cap.ht_supported)
+ break;
+
+ for (i = 0; i < AR9170_NUM_TID; i++) {
+ sta_info->agg[i].state = AR9170_TID_STATE_INVALID;
+ skb_queue_purge(&sta_info->agg[i].queue);
+ }
+
+ break;
+
+ default:
+ break;
+ }
}
static int ar9170_get_stats(struct ieee80211_hw *hw,
@@ -1984,18 +2433,65 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
+ struct ar9170 *ar = hw->priv;
+ struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
+ struct ar9170_sta_tid *tid_info = &sta_info->agg[tid];
+ unsigned long flags;
+
+ if (!modparam_ht)
+ return -EOPNOTSUPP;
+
switch (action) {
+ case IEEE80211_AMPDU_TX_START:
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ if (tid_info->state != AR9170_TID_STATE_SHUTDOWN ||
+ !list_empty(&tid_info->list)) {
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_INFO "%s: A-MPDU [ESS:[%pM] tid:[%d]] "
+ "is in a very bad state!\n",
+ wiphy_name(hw->wiphy), sta->addr, tid);
+#endif /* AR9170_TXAGG_DEBUG */
+ return -EBUSY;
+ }
+
+ *ssn = tid_info->ssn;
+ tid_info->state = AR9170_TID_STATE_PROGRESS;
+ tid_info->active = false;
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+ break;
+
+ case IEEE80211_AMPDU_TX_STOP:
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ tid_info->state = AR9170_TID_STATE_SHUTDOWN;
+ list_del_init(&tid_info->list);
+ tid_info->active = false;
+ skb_queue_purge(&tid_info->queue);
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+ break;
+
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_INFO "%s: A-MPDU for %pM [tid:%d] Operational.\n",
+ wiphy_name(hw->wiphy), sta->addr, tid);
+#endif /* AR9170_TXAGG_DEBUG */
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ sta_info->agg[tid].state = AR9170_TID_STATE_COMPLETE;
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ break;
+
case IEEE80211_AMPDU_RX_START:
case IEEE80211_AMPDU_RX_STOP:
- /*
- * Something goes wrong -- RX locks up
- * after a while of receiving aggregated
- * frames -- not enabling for now.
- */
- return -EOPNOTSUPP;
+ /* Handled by firmware */
+ break;
+
default:
return -EOPNOTSUPP;
}
+
+ return 0;
}
static const struct ieee80211_ops ar9170_ops = {
@@ -2005,6 +2501,7 @@ static const struct ieee80211_ops ar9170_ops = {
.add_interface = ar9170_op_add_interface,
.remove_interface = ar9170_op_remove_interface,
.config = ar9170_op_config,
+ .prepare_multicast = ar9170_op_prepare_multicast,
.configure_filter = ar9170_op_configure_filter,
.conf_tx = ar9170_conf_tx,
.bss_info_changed = ar9170_op_bss_info_changed,
@@ -2044,14 +2541,16 @@ void *ar9170_alloc(size_t priv_size)
mutex_init(&ar->mutex);
spin_lock_init(&ar->cmdlock);
spin_lock_init(&ar->tx_stats_lock);
+ spin_lock_init(&ar->tx_ampdu_list_lock);
+ skb_queue_head_init(&ar->tx_status_ampdu);
for (i = 0; i < __AR9170_NUM_TXQ; i++) {
skb_queue_head_init(&ar->tx_status[i]);
skb_queue_head_init(&ar->tx_pending[i]);
}
ar9170_rx_reset_rx_mpdu(ar);
- INIT_WORK(&ar->filter_config_work, ar9170_set_filters);
INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor);
+ INIT_LIST_HEAD(&ar->tx_ampdu_list);
/* all hw supports 2.4 GHz, so set channel to 1 by default */
ar->channel = &ar9170_2ghz_chantable[0];
@@ -2065,6 +2564,13 @@ void *ar9170_alloc(size_t priv_size)
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
+ if (modparam_ht) {
+ ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+ } else {
+ ar9170_band_2GHz.ht_cap.ht_supported = false;
+ ar9170_band_5GHz.ht_cap.ht_supported = false;
+ }
+
ar->hw->queues = __AR9170_NUM_TXQ;
ar->hw->extra_tx_headroom = 8;
ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
@@ -2086,10 +2592,11 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
{
#define RW 8 /* number of words to read at once */
#define RB (sizeof(u32) * RW)
- DECLARE_MAC_BUF(mbuf);
+ struct ath_regulatory *regulatory = &ar->common.regulatory;
u8 *eeprom = (void *)&ar->eeprom;
u8 *addr = ar->eeprom.mac_address;
__le32 offsets[RW];
+ unsigned int rx_streams, tx_streams, tx_params = 0;
int i, j, err, bands = 0;
BUILD_BUG_ON(sizeof(ar->eeprom) & 3);
@@ -2126,6 +2633,20 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz;
bands++;
}
+
+ rx_streams = hweight8(ar->eeprom.rx_mask);
+ tx_streams = hweight8(ar->eeprom.tx_mask);
+
+ if (rx_streams != tx_streams)
+ tx_params = IEEE80211_HT_MCS_TX_RX_DIFF;
+
+ if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS)
+ tx_params = (tx_streams - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+
+ ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params;
+ ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params;
+
/*
* I measured this, a bandswitch takes roughly
* 135 ms and a frequency switch about 80.
@@ -2138,8 +2659,8 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
else
ar->hw->channel_change_time = 80 * 1000;
- ar->regulatory.current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);
- ar->regulatory.current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]);
+ regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);
+ regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]);
/* second part of wiphy init */
SET_IEEE80211_PERM_ADDR(ar->hw, addr);
@@ -2153,11 +2674,12 @@ static int ar9170_reg_notifier(struct wiphy *wiphy,
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ar9170 *ar = hw->priv;
- return ath_reg_notifier_apply(wiphy, request, &ar->regulatory);
+ return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
}
int ar9170_register(struct ar9170 *ar, struct device *pdev)
{
+ struct ath_regulatory *regulatory = &ar->common.regulatory;
int err;
/* try to read EEPROM, init MAC addr */
@@ -2165,7 +2687,7 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev)
if (err)
goto err_out;
- err = ath_regd_init(&ar->regulatory, ar->hw->wiphy,
+ err = ath_regd_init(regulatory, ar->hw->wiphy,
ar9170_reg_notifier);
if (err)
goto err_out;
@@ -2174,8 +2696,8 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev)
if (err)
goto err_out;
- if (!ath_is_world_regd(&ar->regulatory))
- regulatory_hint(ar->hw->wiphy, ar->regulatory.alpha2);
+ if (!ath_is_world_regd(regulatory))
+ regulatory_hint(ar->hw->wiphy, regulatory->alpha2);
err = ar9170_init_leds(ar);
if (err)
diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c
index df86f70cd817..b3e5cf3735b0 100644
--- a/drivers/net/wireless/ath/ar9170/phy.c
+++ b/drivers/net/wireless/ath/ar9170/phy.c
@@ -396,6 +396,136 @@ static struct ar9170_phy_init ar5416_phy_init[] = {
{ 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, }
};
+/*
+ * look up a certain register in ar5416_phy_init[] and return the init. value
+ * for the band and bandwidth given. Return 0 if register address not found.
+ */
+static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz)
+{
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) {
+ if (ar5416_phy_init[i].reg != reg)
+ continue;
+
+ if (is_2ghz) {
+ if (is_40mhz)
+ return ar5416_phy_init[i]._2ghz_40;
+ else
+ return ar5416_phy_init[i]._2ghz_20;
+ } else {
+ if (is_40mhz)
+ return ar5416_phy_init[i]._5ghz_40;
+ else
+ return ar5416_phy_init[i]._5ghz_20;
+ }
+ }
+ return 0;
+}
+
+/*
+ * initialize some phy regs from eeprom values in modal_header[]
+ * acc. to band and bandwith
+ */
+static int ar9170_init_phy_from_eeprom(struct ar9170 *ar,
+ bool is_2ghz, bool is_40mhz)
+{
+ static const u8 xpd2pd[16] = {
+ 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2,
+ 0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2
+ };
+ u32 defval, newval;
+ /* pointer to the modal_header acc. to band */
+ struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz];
+
+ ar9170_regwrite_begin(ar);
+
+ /* ant common control (index 0) */
+ newval = le32_to_cpu(m->antCtrlCommon);
+ ar9170_regwrite(0x1c5964, newval);
+
+ /* ant control chain 0 (index 1) */
+ newval = le32_to_cpu(m->antCtrlChain[0]);
+ ar9170_regwrite(0x1c5960, newval);
+
+ /* ant control chain 2 (index 2) */
+ newval = le32_to_cpu(m->antCtrlChain[1]);
+ ar9170_regwrite(0x1c7960, newval);
+
+ /* SwSettle (index 3) */
+ if (!is_40mhz) {
+ defval = ar9170_get_default_phy_reg_val(0x1c5844,
+ is_2ghz, is_40mhz);
+ newval = (defval & ~0x3f80) |
+ ((m->switchSettling & 0x7f) << 7);
+ ar9170_regwrite(0x1c5844, newval);
+ }
+
+ /* adcDesired, pdaDesired (index 4) */
+ defval = ar9170_get_default_phy_reg_val(0x1c5850, is_2ghz, is_40mhz);
+ newval = (defval & ~0xffff) | ((u8)m->pgaDesiredSize << 8) |
+ ((u8)m->adcDesiredSize);
+ ar9170_regwrite(0x1c5850, newval);
+
+ /* TxEndToXpaOff, TxFrameToXpaOn (index 5) */
+ defval = ar9170_get_default_phy_reg_val(0x1c5834, is_2ghz, is_40mhz);
+ newval = (m->txEndToXpaOff << 24) | (m->txEndToXpaOff << 16) |
+ (m->txFrameToXpaOn << 8) | m->txFrameToXpaOn;
+ ar9170_regwrite(0x1c5834, newval);
+
+ /* TxEndToRxOn (index 6) */
+ defval = ar9170_get_default_phy_reg_val(0x1c5828, is_2ghz, is_40mhz);
+ newval = (defval & ~0xff0000) | (m->txEndToRxOn << 16);
+ ar9170_regwrite(0x1c5828, newval);
+
+ /* thresh62 (index 7) */
+ defval = ar9170_get_default_phy_reg_val(0x1c8864, is_2ghz, is_40mhz);
+ newval = (defval & ~0x7f000) | (m->thresh62 << 12);
+ ar9170_regwrite(0x1c8864, newval);
+
+ /* tx/rx attenuation chain 0 (index 8) */
+ defval = ar9170_get_default_phy_reg_val(0x1c5848, is_2ghz, is_40mhz);
+ newval = (defval & ~0x3f000) | ((m->txRxAttenCh[0] & 0x3f) << 12);
+ ar9170_regwrite(0x1c5848, newval);
+
+ /* tx/rx attenuation chain 2 (index 9) */
+ defval = ar9170_get_default_phy_reg_val(0x1c7848, is_2ghz, is_40mhz);
+ newval = (defval & ~0x3f000) | ((m->txRxAttenCh[1] & 0x3f) << 12);
+ ar9170_regwrite(0x1c7848, newval);
+
+ /* tx/rx margin chain 0 (index 10) */
+ defval = ar9170_get_default_phy_reg_val(0x1c620c, is_2ghz, is_40mhz);
+ newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[0] & 0x3f) << 18);
+ /* bsw margin chain 0 for 5GHz only */
+ if (!is_2ghz)
+ newval = (newval & ~0x3c00) | ((m->bswMargin[0] & 0xf) << 10);
+ ar9170_regwrite(0x1c620c, newval);
+
+ /* tx/rx margin chain 2 (index 11) */
+ defval = ar9170_get_default_phy_reg_val(0x1c820c, is_2ghz, is_40mhz);
+ newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[1] & 0x3f) << 18);
+ ar9170_regwrite(0x1c820c, newval);
+
+ /* iqCall, iqCallq chain 0 (index 12) */
+ defval = ar9170_get_default_phy_reg_val(0x1c5920, is_2ghz, is_40mhz);
+ newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[0] & 0x3f) << 5) |
+ ((u8)m->iqCalQCh[0] & 0x1f);
+ ar9170_regwrite(0x1c5920, newval);
+
+ /* iqCall, iqCallq chain 2 (index 13) */
+ defval = ar9170_get_default_phy_reg_val(0x1c7920, is_2ghz, is_40mhz);
+ newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[1] & 0x3f) << 5) |
+ ((u8)m->iqCalQCh[1] & 0x1f);
+ ar9170_regwrite(0x1c7920, newval);
+
+ /* xpd gain mask (index 14) */
+ defval = ar9170_get_default_phy_reg_val(0x1c6258, is_2ghz, is_40mhz);
+ newval = (defval & ~0xf0000) | (xpd2pd[m->xpdGain & 0xf] << 16);
+ ar9170_regwrite(0x1c6258, newval);
+ ar9170_regwrite_finish();
+
+ return ar9170_regwrite_result();
+}
+
int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
{
int i, err;
@@ -426,7 +556,9 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
if (err)
return err;
- /* XXX: use EEPROM data here! */
+ err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz);
+ if (err)
+ return err;
err = ar9170_init_power_cal(ar);
if (err)
@@ -987,6 +1119,282 @@ static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2)
#undef SHIFT
}
+static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ if (x <= x_array[i + 1])
+ break;
+
+ return ar9170_interpolate_u8(x,
+ x_array[i],
+ y_array[i],
+ x_array[i + 1],
+ y_array[i + 1]);
+}
+
+static int ar9170_set_freq_cal_data(struct ar9170 *ar,
+ struct ieee80211_channel *channel)
+{
+ u8 *cal_freq_pier;
+ u8 vpds[2][AR5416_PD_GAIN_ICEPTS];
+ u8 pwrs[2][AR5416_PD_GAIN_ICEPTS];
+ int chain, idx, i;
+ u8 f;
+
+ switch (channel->band) {
+ case IEEE80211_BAND_2GHZ:
+ f = channel->center_freq - 2300;
+ cal_freq_pier = ar->eeprom.cal_freq_pier_2G;
+ i = AR5416_NUM_2G_CAL_PIERS - 1;
+ break;
+
+ case IEEE80211_BAND_5GHZ:
+ f = (channel->center_freq - 4800) / 5;
+ cal_freq_pier = ar->eeprom.cal_freq_pier_5G;
+ i = AR5416_NUM_5G_CAL_PIERS - 1;
+ break;
+
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ for (; i >= 0; i--) {
+ if (cal_freq_pier[i] != 0xff)
+ break;
+ }
+ if (i < 0)
+ return -EINVAL;
+
+ idx = ar9170_find_freq_idx(i, cal_freq_pier, f);
+
+ ar9170_regwrite_begin(ar);
+
+ for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) {
+ for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) {
+ struct ar9170_calibration_data_per_freq *cal_pier_data;
+ int j;
+
+ switch (channel->band) {
+ case IEEE80211_BAND_2GHZ:
+ cal_pier_data = &ar->eeprom.
+ cal_pier_data_2G[chain][idx];
+ break;
+
+ case IEEE80211_BAND_5GHZ:
+ cal_pier_data = &ar->eeprom.
+ cal_pier_data_5G[chain][idx];
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ for (j = 0; j < 2; j++) {
+ vpds[j][i] = ar9170_interpolate_u8(f,
+ cal_freq_pier[idx],
+ cal_pier_data->vpd_pdg[j][i],
+ cal_freq_pier[idx + 1],
+ cal_pier_data[1].vpd_pdg[j][i]);
+
+ pwrs[j][i] = ar9170_interpolate_u8(f,
+ cal_freq_pier[idx],
+ cal_pier_data->pwr_pdg[j][i],
+ cal_freq_pier[idx + 1],
+ cal_pier_data[1].pwr_pdg[j][i]) / 2;
+ }
+ }
+
+ for (i = 0; i < 76; i++) {
+ u32 phy_data;
+ u8 tmp;
+
+ if (i < 25) {
+ tmp = ar9170_interpolate_val(i, &pwrs[0][0],
+ &vpds[0][0]);
+ } else {
+ tmp = ar9170_interpolate_val(i - 12,
+ &pwrs[1][0],
+ &vpds[1][0]);
+ }
+
+ phy_data |= tmp << ((i & 3) << 3);
+ if ((i & 3) == 3) {
+ ar9170_regwrite(0x1c6280 + chain * 0x1000 +
+ (i & ~3), phy_data);
+ phy_data = 0;
+ }
+ }
+
+ for (i = 19; i < 32; i++)
+ ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2),
+ 0x0);
+ }
+
+ ar9170_regwrite_finish();
+ return ar9170_regwrite_result();
+}
+
+static u8 ar9170_get_max_edge_power(struct ar9170 *ar,
+ struct ar9170_calctl_edges edges[],
+ u32 freq)
+{
+/* TODO: move somewhere else */
+#define AR5416_MAX_RATE_POWER 63
+
+ int i;
+ u8 rc = AR5416_MAX_RATE_POWER;
+ u8 f;
+ if (freq < 3000)
+ f = freq - 2300;
+ else
+ f = (freq - 4800) / 5;
+
+ for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) {
+ if (edges[i].channel == 0xff)
+ break;
+ if (f == edges[i].channel) {
+ /* exact freq match */
+ rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS;
+ break;
+ }
+ if (i > 0 && f < edges[i].channel) {
+ if (f > edges[i-1].channel &&
+ edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
+ /* lower channel has the inband flag set */
+ rc = edges[i-1].power_flags &
+ ~AR9170_CALCTL_EDGE_FLAGS;
+ }
+ break;
+ }
+ }
+
+ if (i == AR5416_NUM_BAND_EDGES) {
+ if (f > edges[i-1].channel &&
+ edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
+ /* lower channel has the inband flag set */
+ rc = edges[i-1].power_flags &
+ ~AR9170_CALCTL_EDGE_FLAGS;
+ }
+ }
+ return rc;
+}
+
+/* calculate the conformance test limits and apply them to ar->power*
+ * (derived from otus hal/hpmain.c, line 3706 ff.)
+ */
+static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
+{
+ u8 ctl_grp; /* CTL group */
+ u8 ctl_idx; /* CTL index */
+ int i, j;
+ struct ctl_modes {
+ u8 ctl_mode;
+ u8 max_power;
+ u8 *pwr_cal_data;
+ int pwr_cal_len;
+ } *modes;
+
+ /* order is relevant in the mode_list_*: we fall back to the
+ * lower indices if any mode is missed in the EEPROM.
+ */
+ struct ctl_modes mode_list_2ghz[] = {
+ { CTL_11B, 0, ar->power_2G_cck, 4 },
+ { CTL_11G, 0, ar->power_2G_ofdm, 4 },
+ { CTL_2GHT20, 0, ar->power_2G_ht20, 8 },
+ { CTL_2GHT40, 0, ar->power_2G_ht40, 8 },
+ };
+ struct ctl_modes mode_list_5ghz[] = {
+ { CTL_11A, 0, ar->power_5G_leg, 4 },
+ { CTL_5GHT20, 0, ar->power_5G_ht20, 8 },
+ { CTL_5GHT40, 0, ar->power_5G_ht40, 8 },
+ };
+ int nr_modes;
+
+#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n])
+
+ /* TODO: investigate the differences between OTUS'
+ * hpreg.c::zfHpGetRegulatoryDomain() and
+ * ath/regd.c::ath_regd_get_band_ctl() -
+ * e.g. for FCC3_WORLD the OTUS procedure
+ * always returns CTL_FCC, while the one in ath/ delivers
+ * CTL_ETSI for 2GHz and CTL_FCC for 5GHz.
+ */
+ ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory,
+ ar->hw->conf.channel->band);
+
+ /* ctl group not found - either invalid band (NO_CTL) or ww roaming */
+ if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL)
+ ctl_grp = CTL_FCC;
+
+ if (ctl_grp != CTL_FCC)
+ /* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */
+ return;
+
+ if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
+ modes = mode_list_2ghz;
+ nr_modes = ARRAY_SIZE(mode_list_2ghz);
+ } else {
+ modes = mode_list_5ghz;
+ nr_modes = ARRAY_SIZE(mode_list_5ghz);
+ }
+
+ for (i = 0; i < nr_modes; i++) {
+ u8 c = ctl_grp | modes[i].ctl_mode;
+ for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++)
+ if (c == ar->eeprom.ctl_index[ctl_idx])
+ break;
+ if (ctl_idx < AR5416_NUM_CTLS) {
+ int f_off = 0;
+
+ /* adjust freq for 40MHz */
+ if (modes[i].ctl_mode == CTL_2GHT40 ||
+ modes[i].ctl_mode == CTL_5GHT40) {
+ if (bw == AR9170_BW_40_BELOW)
+ f_off = -10;
+ else
+ f_off = 10;
+ }
+
+ modes[i].max_power =
+ ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1),
+ freq+f_off);
+
+ /* TODO: check if the regulatory max. power is
+ * controlled by cfg80211 for DFS
+ * (hpmain applies it to max_power itself for DFS freq)
+ */
+
+ } else {
+ /* Workaround in otus driver, hpmain.c, line 3906:
+ * if no data for 5GHT20 are found, take the
+ * legacy 5G value.
+ * We extend this here to fallback from any other *HT or
+ * 11G, too.
+ */
+ int k = i;
+
+ modes[i].max_power = AR5416_MAX_RATE_POWER;
+ while (k-- > 0) {
+ if (modes[k].max_power !=
+ AR5416_MAX_RATE_POWER) {
+ modes[i].max_power = modes[k].max_power;
+ break;
+ }
+ }
+ }
+
+ /* apply max power to pwr_cal_data (ar->power_*) */
+ for (j = 0; j < modes[i].pwr_cal_len; j++) {
+ modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j],
+ modes[i].max_power);
+ }
+ }
+#undef EDGES
+}
+
static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
{
struct ar9170_calibration_target_power_legacy *ctpl;
@@ -1089,6 +1497,12 @@ static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
ctph[idx + 1].power[n]);
}
+
+ /* calc. conformance test limits and apply to ar->power*[] */
+ ar9170_calc_ctl(ar, freq, bw);
+
+ /* TODO: (heavy clip) regulatory domain power level fine-tuning. */
+
/* set ACK/CTS TX power */
ar9170_regwrite_begin(ar);
@@ -1207,6 +1621,10 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
if (err)
return err;
+ err = ar9170_set_freq_cal_data(ar, channel);
+ if (err)
+ return err;
+
err = ar9170_set_power_cal(ar, channel->center_freq, bw);
if (err)
return err;
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index 007eb85fc67e..e0138ac8bf50 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -783,7 +783,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
aru->req_one_stage_fw = ar9170_requires_one_stage(id);
usb_set_intfdata(intf, aru);
- SET_IEEE80211_DEV(ar->hw, &udev->dev);
+ SET_IEEE80211_DEV(ar->hw, &intf->dev);
init_usb_anchor(&aru->rx_submitted);
init_usb_anchor(&aru->tx_pending);
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
new file mode 100644
index 000000000000..a63e90cbf9e5
--- /dev/null
+++ b/drivers/net/wireless/ath/ath.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ATH_H
+#define ATH_H
+
+#include <linux/skbuff.h>
+
+struct reg_dmn_pair_mapping {
+ u16 regDmnEnum;
+ u16 reg_5ghz_ctl;
+ u16 reg_2ghz_ctl;
+};
+
+struct ath_regulatory {
+ char alpha2[2];
+ u16 country_code;
+ u16 max_power_level;
+ u32 tp_scale;
+ u16 current_rd;
+ u16 current_rd_ext;
+ int16_t power_limit;
+ struct reg_dmn_pair_mapping *regpair;
+};
+
+struct ath_common {
+ u16 cachelsz;
+ struct ath_regulatory regulatory;
+};
+
+struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
+ u32 len,
+ gfp_t gfp_mask);
+
+#endif /* ATH_H */
diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig
index daf0c83527d8..06d006675d7d 100644
--- a/drivers/net/wireless/ath/ath5k/Kconfig
+++ b/drivers/net/wireless/ath/ath5k/Kconfig
@@ -1,7 +1,6 @@
config ATH5K
tristate "Atheros 5xxx wireless cards support"
- depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
- select ATH_COMMON
+ depends on PCI && MAC80211 && WLAN_80211
select MAC80211_LEDS
select LEDS_CLASS
select NEW_LEDS
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 6358233bac99..6cd5efcec417 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -27,8 +27,6 @@
#include <linux/types.h>
#include <net/mac80211.h>
-#include "../regd.h"
-
/* RX/TX descriptor hw structs
* TODO: Driver part should only see sw structs */
#include "desc.h"
@@ -308,6 +306,7 @@ struct ath5k_srev_name {
#define AR5K_SREV_AR5311B 0x30 /* Spirit */
#define AR5K_SREV_AR5211 0x40 /* Oahu */
#define AR5K_SREV_AR5212 0x50 /* Venice */
+#define AR5K_SREV_AR5212_V4 0x54 /* ??? */
#define AR5K_SREV_AR5213 0x55 /* ??? */
#define AR5K_SREV_AR5213A 0x59 /* Hainan */
#define AR5K_SREV_AR2413 0x78 /* Griffin lite */
@@ -713,8 +712,8 @@ struct ath5k_gain {
* Used internaly for reset_tx_queue).
* Also see struct struct ieee80211_channel.
*/
-#define IS_CHAN_XR(_c) ((_c.hw_value & CHANNEL_XR) != 0)
-#define IS_CHAN_B(_c) ((_c.hw_value & CHANNEL_B) != 0)
+#define IS_CHAN_XR(_c) ((_c->hw_value & CHANNEL_XR) != 0)
+#define IS_CHAN_B(_c) ((_c->hw_value & CHANNEL_B) != 0)
/*
* The following structure is used to map 2GHz channels to
@@ -919,6 +918,12 @@ enum ath5k_int {
AR5K_INT_NOCARD = 0xffffffff
};
+/* Software interrupts used for calibration */
+enum ath5k_software_interrupt {
+ AR5K_SWI_FULL_CALIBRATION = 0x01,
+ AR5K_SWI_SHORT_CALIBRATION = 0x02,
+};
+
/*
* Power management
*/
@@ -1029,14 +1034,16 @@ struct ath5k_hw {
enum ath5k_int ah_imr;
enum nl80211_iftype ah_op_mode;
- enum ath5k_power_mode ah_power_mode;
- struct ieee80211_channel ah_current_channel;
+ struct ieee80211_channel *ah_current_channel;
bool ah_turbo;
bool ah_calibration;
- bool ah_running;
bool ah_single_chip;
+ bool ah_aes_support;
bool ah_combined_mic;
+ enum ath5k_version ah_version;
+ enum ath5k_radio ah_radio;
+ u32 ah_phy;
u32 ah_mac_srev;
u16 ah_mac_version;
u16 ah_mac_revision;
@@ -1044,13 +1051,6 @@ struct ath5k_hw {
u16 ah_radio_5ghz_revision;
u16 ah_radio_2ghz_revision;
- enum ath5k_version ah_version;
- enum ath5k_radio ah_radio;
- u32 ah_phy;
-
- bool ah_5ghz;
- bool ah_2ghz;
-
#define ah_modes ah_capabilities.cap_mode
#define ah_ee_version ah_capabilities.cap_eeprom.ee_version
@@ -1058,7 +1058,6 @@ struct ath5k_hw {
u32 ah_aifs;
u32 ah_cw_min;
u32 ah_cw_max;
- bool ah_software_retry;
u32 ah_limit_tx_retries;
/* Antenna Control */
@@ -1066,6 +1065,7 @@ struct ath5k_hw {
u8 ah_ant_mode;
u8 ah_tx_ant;
u8 ah_def_ant;
+ bool ah_software_retry;
u8 ah_sta_id[ETH_ALEN];
@@ -1075,10 +1075,8 @@ struct ath5k_hw {
u8 ah_bssid[ETH_ALEN];
u8 ah_bssid_mask[ETH_ALEN];
- u32 ah_gpio[AR5K_MAX_GPIO];
int ah_gpio_npins;
- struct ath_regulatory ah_regulatory;
struct ath5k_capabilities ah_capabilities;
struct ath5k_txq_info ah_txq[AR5K_NUM_TX_QUEUES];
@@ -1130,6 +1128,15 @@ struct ath5k_hw {
/* noise floor from last periodic calibration */
s32 ah_noise_floor;
+ /* Calibration timestamp */
+ unsigned long ah_cal_tstamp;
+
+ /* Calibration interval (secs) */
+ u8 ah_cal_intval;
+
+ /* Software interrupt mask */
+ u8 ah_swi_mask;
+
/*
* Function pointers
*/
@@ -1153,7 +1160,7 @@ struct ath5k_hw {
*/
/* Attach/Detach Functions */
-extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version);
+extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc);
extern void ath5k_hw_detach(struct ath5k_hw *ah);
/* LED functions */
@@ -1164,6 +1171,7 @@ extern void ath5k_unregister_leds(struct ath5k_softc *sc);
/* Reset Functions */
extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
+extern int ath5k_hw_on_hold(struct ath5k_hw *ah);
extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel);
/* Power management functions */
extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration);
@@ -1282,6 +1290,7 @@ extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *chann
/* PHY calibration */
extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
+extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah);
/* Spur mitigation */
bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
struct ieee80211_channel *channel);
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index c41ef58393e7..71a1bd254517 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -95,17 +95,17 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
* ath5k_hw_attach - Check if hw is supported and init the needed structs
*
* @sc: The &struct ath5k_softc we got from the driver's attach function
- * @mac_version: The mac version id (check out ath5k.h) based on pci id
*
* Check if the device is supported, perform a POST and initialize the needed
* structs. Returns -ENOMEM if we don't have memory for the needed structs,
* -ENODEV if the device is not supported or prints an error msg if something
* else went wrong.
*/
-struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
+struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc)
{
struct ath5k_hw *ah;
struct pci_dev *pdev = sc->pdev;
+ struct ath5k_eeprom_info *ee;
int ret;
u32 srev;
@@ -135,9 +135,15 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
ah->ah_software_retry = false;
/*
- * Set the mac version based on the pci id
+ * Find the mac version
*/
- ah->ah_version = mac_version;
+ srev = ath5k_hw_reg_read(ah, AR5K_SREV);
+ if (srev < AR5K_SREV_AR5311)
+ ah->ah_version = AR5K_AR5210;
+ else if (srev < AR5K_SREV_AR5212)
+ ah->ah_version = AR5K_AR5211;
+ else
+ ah->ah_version = AR5K_AR5212;
/*Fill the ath5k_hw struct with the needed functions*/
ret = ath5k_hw_init_desc_functions(ah);
@@ -145,12 +151,11 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
goto err_free;
/* Bring device out of sleep and reset it's units */
- ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true);
+ ret = ath5k_hw_nic_wakeup(ah, 0, true);
if (ret)
goto err_free;
/* Get MAC, PHY and RADIO revisions */
- srev = ath5k_hw_reg_read(ah, AR5K_SREV);
ah->ah_mac_srev = srev;
ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
@@ -253,28 +258,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
}
/*
- * Write PCI-E power save settings
- */
- if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
- ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
- ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
- /* Shut off RX when elecidle is asserted */
- ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
- ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
- /* TODO: EEPROM work */
- ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
- /* Shut off PLL and CLKREQ active in L1 */
- ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
- /* Preserce other settings */
- ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
- ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
- ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
- /* Reset SERDES to load new settings */
- ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
- mdelay(1);
- }
-
- /*
* POST
*/
ret = ath5k_hw_post(ah);
@@ -283,7 +266,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
/* Enable pci core retry fix on Hainan (5213A) and later chips */
if (srev >= AR5K_SREV_AR5213A)
- ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG);
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_RETRY_FIX);
/*
* Get card capabilities, calibration values etc
@@ -295,6 +278,40 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
goto err_free;
}
+ /*
+ * Write PCI-E power save settings
+ */
+ if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+
+ ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
+ ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
+
+ /* Shut off RX when elecidle is asserted */
+ ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
+ ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
+
+ /* If serdes programing is enabled, increase PCI-E
+ * tx power for systems with long trace from host
+ * to minicard connector. */
+ if (ee->ee_serdes)
+ ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
+ else
+ ath5k_hw_reg_write(ah, 0xf6800579, AR5K_PCIE_SERDES);
+
+ /* Shut off PLL and CLKREQ active in L1 */
+ ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
+
+ /* Preserve other settings */
+ ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
+ ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
+ ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
+
+ /* Reset SERDES to load new settings */
+ ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
+ mdelay(1);
+ }
+
/* Get misc capabilities */
ret = ath5k_hw_set_capabilities(ah);
if (ret) {
@@ -303,6 +320,12 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
goto err_free;
}
+ /* Crypto settings */
+ ee = &ah->ah_capabilities.cap_eeprom;
+ ah->ah_aes_support = srev >= AR5K_SREV_AR5212_V4 &&
+ (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
+ !AR5K_EEPROM_AES_DIS(ee->ee_misc5));
+
if (srev >= AR5K_SREV_AR2414) {
ah->ah_combined_mic = true;
AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE,
@@ -319,6 +342,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
ath5k_hw_rfgain_opt_init(ah);
+ /* turn on HW LEDs */
+ ath5k_hw_set_ledstate(ah, AR5K_LED_INIT);
+
return ah;
err_free:
kfree(ah);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 029c1bc7468f..9c6ab5378f6e 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -59,7 +59,7 @@
#include "reg.h"
#include "debug.h"
-static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
+static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
@@ -84,24 +84,24 @@ MODULE_VERSION("0.6.0 (EXPERIMENTAL)");
/* Known PCI ids */
static const struct pci_device_id ath5k_pci_id_table[] = {
- { PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */
- { PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */
- { PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 - this is on AHB bus !*/
- { PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */
- { PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */
- { PCI_VDEVICE(3COM_2, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */
- { PCI_VDEVICE(3COM, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */
- { PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */
- { PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */
- { PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */
- { PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* PCI-E cards */
- { PCI_VDEVICE(ATHEROS, 0x001d), .driver_data = AR5K_AR5212 }, /* 2417 Nala */
+ { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */
+ { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */
+ { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/
+ { PCI_VDEVICE(ATHEROS, 0x0012) }, /* 5211 */
+ { PCI_VDEVICE(ATHEROS, 0x0013) }, /* 5212 */
+ { PCI_VDEVICE(3COM_2, 0x0013) }, /* 3com 5212 */
+ { PCI_VDEVICE(3COM, 0x0013) }, /* 3com 3CRDAG675 5212 */
+ { PCI_VDEVICE(ATHEROS, 0x1014) }, /* IBM minipci 5212 */
+ { PCI_VDEVICE(ATHEROS, 0x0014) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0015) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0016) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0017) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0018) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0019) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x001a) }, /* 2413 Griffin-lite */
+ { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
+ { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
+ { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
{ 0 }
};
MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
@@ -218,6 +218,8 @@ static struct pci_driver ath5k_pci_driver = {
* Prototypes - MAC 802.11 stack related functions
*/
static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
+static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ath5k_txq *txq);
static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
static int ath5k_reset_wake(struct ath5k_softc *sc);
static int ath5k_start(struct ieee80211_hw *hw);
@@ -227,10 +229,12 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
static void ath5k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
+static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
+ int mc_count, struct dev_addr_list *mc_list);
static void ath5k_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *new_flags,
- int mc_count, struct dev_mc_list *mclist);
+ u64 multicast);
static int ath5k_set_key(struct ieee80211_hw *hw,
enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
@@ -248,6 +252,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changes);
+static void ath5k_sw_scan_start(struct ieee80211_hw *hw);
+static void ath5k_sw_scan_complete(struct ieee80211_hw *hw);
static const struct ieee80211_ops ath5k_hw_ops = {
.tx = ath5k_tx,
@@ -256,6 +262,7 @@ static const struct ieee80211_ops ath5k_hw_ops = {
.add_interface = ath5k_add_interface,
.remove_interface = ath5k_remove_interface,
.config = ath5k_config,
+ .prepare_multicast = ath5k_prepare_multicast,
.configure_filter = ath5k_configure_filter,
.set_key = ath5k_set_key,
.get_stats = ath5k_get_stats,
@@ -265,6 +272,8 @@ static const struct ieee80211_ops ath5k_hw_ops = {
.set_tsf = ath5k_set_tsf,
.reset_tsf = ath5k_reset_tsf,
.bss_info_changed = ath5k_bss_info_changed,
+ .sw_scan_start = ath5k_sw_scan_start,
+ .sw_scan_complete = ath5k_sw_scan_complete,
};
/*
@@ -297,7 +306,8 @@ static void ath5k_desc_free(struct ath5k_softc *sc,
static int ath5k_rxbuf_setup(struct ath5k_softc *sc,
struct ath5k_buf *bf);
static int ath5k_txbuf_setup(struct ath5k_softc *sc,
- struct ath5k_buf *bf);
+ struct ath5k_buf *bf,
+ struct ath5k_txq *txq);
static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
struct ath5k_buf *bf)
{
@@ -369,7 +379,7 @@ static int ath5k_stop_hw(struct ath5k_softc *sc);
static irqreturn_t ath5k_intr(int irq, void *dev_id);
static void ath5k_tasklet_reset(unsigned long data);
-static void ath5k_calibrate(unsigned long data);
+static void ath5k_tasklet_calibrate(unsigned long data);
/*
* Module init/exit functions
@@ -464,7 +474,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
* DMA to work so force a reasonable value here if it
* comes up zero.
*/
- csz = L1_CACHE_BYTES / sizeof(u32);
+ csz = L1_CACHE_BYTES >> 2;
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
}
/*
@@ -512,6 +522,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
/* Initialize driver private data */
SET_IEEE80211_DEV(hw, &pdev->dev);
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
@@ -536,7 +547,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
__set_bit(ATH_STAT_INVALID, sc->status);
sc->iobase = mem; /* So we can unmap it on detach */
- sc->cachelsz = csz * sizeof(u32); /* convert to bytes */
+ sc->common.cachelsz = csz << 2; /* convert to bytes */
sc->opmode = NL80211_IFTYPE_STATION;
sc->bintval = 1000;
mutex_init(&sc->lock);
@@ -555,7 +566,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
}
/* Initialize device */
- sc->ah = ath5k_hw_attach(sc, id->driver_data);
+ sc->ah = ath5k_hw_attach(sc);
if (IS_ERR(sc->ah)) {
ret = PTR_ERR(sc->ah);
goto err_irq;
@@ -666,7 +677,6 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
ath5k_led_off(sc);
- free_irq(pdev->irq, sc);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
@@ -694,18 +704,8 @@ ath5k_pci_resume(struct pci_dev *pdev)
*/
pci_write_config_byte(pdev, 0x41, 0);
- err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
- if (err) {
- ATH5K_ERR(sc, "request_irq failed\n");
- goto err_no_irq;
- }
-
ath5k_led_enable(sc);
return 0;
-
-err_no_irq:
- pci_disable_device(pdev);
- return err;
}
#endif /* CONFIG_PM */
@@ -718,9 +718,9 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath5k_softc *sc = hw->priv;
- struct ath_regulatory *reg = &sc->ah->ah_regulatory;
+ struct ath_regulatory *regulatory = &sc->common.regulatory;
- return ath_reg_notifier_apply(wiphy, request, reg);
+ return ath_reg_notifier_apply(wiphy, request, regulatory);
}
static int
@@ -728,6 +728,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
+ struct ath_regulatory *regulatory = &sc->common.regulatory;
u8 mac[ETH_ALEN] = {};
int ret;
@@ -785,19 +786,25 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
goto err_desc;
}
sc->bhalq = ret;
+ sc->cabq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0);
+ if (IS_ERR(sc->cabq)) {
+ ATH5K_ERR(sc, "can't setup cab queue\n");
+ ret = PTR_ERR(sc->cabq);
+ goto err_bhal;
+ }
sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
if (IS_ERR(sc->txq)) {
ATH5K_ERR(sc, "can't setup xmit queue\n");
ret = PTR_ERR(sc->txq);
- goto err_bhal;
+ goto err_queues;
}
tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
+ tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc);
tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc);
- setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
ret = ath5k_eeprom_read_mac(ah, mac);
if (ret) {
@@ -811,9 +818,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
memset(sc->bssidmask, 0xff, ETH_ALEN);
ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
- ah->ah_regulatory.current_rd =
- ah->ah_capabilities.cap_eeprom.ee_regdomain;
- ret = ath_regd_init(&ah->ah_regulatory, hw->wiphy, ath5k_reg_notifier);
+ regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain;
+ ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier);
if (ret) {
ATH5K_ERR(sc, "can't initialize regulatory system\n");
goto err_queues;
@@ -825,8 +831,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
goto err_queues;
}
- if (!ath_is_world_regd(&sc->ah->ah_regulatory))
- regulatory_hint(hw->wiphy, sc->ah->ah_regulatory.alpha2);
+ if (!ath_is_world_regd(regulatory))
+ regulatory_hint(hw->wiphy, regulatory->alpha2);
ath5k_init_leds(sc);
@@ -1068,10 +1074,9 @@ ath5k_setup_bands(struct ieee80211_hw *hw)
}
/*
- * Set/change channels. If the channel is really being changed,
- * it's done by reseting the chip. To accomplish this we must
- * first cleanup any pending DMA, then restart stuff after a la
- * ath5k_init.
+ * Set/change channels. We always reset the chip.
+ * To accomplish this we must first cleanup any pending DMA,
+ * then restart stuff after a la ath5k_init.
*
* Called with sc->lock.
*/
@@ -1081,19 +1086,13 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n",
sc->curchan->center_freq, chan->center_freq);
- if (chan->center_freq != sc->curchan->center_freq ||
- chan->hw_value != sc->curchan->hw_value) {
-
- /*
- * To switch channels clear any pending DMA operations;
- * wait long enough for the RX fifo to drain, reset the
- * hardware at the new frequency, and then re-enable
- * the relevant bits of the h/w.
- */
- return ath5k_reset(sc, chan);
- }
-
- return 0;
+ /*
+ * To switch channels clear any pending DMA operations;
+ * wait long enough for the RX fifo to drain, reset the
+ * hardware at the new frequency, and then re-enable
+ * the relevant bits of the h/w.
+ */
+ return ath5k_reset(sc, chan);
}
static void
@@ -1114,6 +1113,8 @@ ath5k_mode_setup(struct ath5k_softc *sc)
struct ath5k_hw *ah = sc->ah;
u32 rfilt;
+ ah->ah_op_mode = sc->opmode;
+
/* configure rx filter */
rfilt = sc->filter_flags;
ath5k_hw_set_rx_filter(ah, rfilt);
@@ -1153,27 +1154,20 @@ static
struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr)
{
struct sk_buff *skb;
- unsigned int off;
/*
* Allocate buffer with headroom_needed space for the
* fake physical layer header at the start.
*/
- skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1);
+ skb = ath_rxbuf_alloc(&sc->common,
+ sc->rxbufsize + sc->common.cachelsz - 1,
+ GFP_ATOMIC);
if (!skb) {
ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
- sc->rxbufsize + sc->cachelsz - 1);
+ sc->rxbufsize + sc->common.cachelsz - 1);
return NULL;
}
- /*
- * Cache-line-align. This is important (for the
- * 5210 at least) as not doing so causes bogus data
- * in rx'd frames.
- */
- off = ((unsigned long)skb->data) % sc->cachelsz;
- if (off != 0)
- skb_reserve(skb, sc->cachelsz - off);
*skb_addr = pci_map_single(sc->pdev,
skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE);
@@ -1228,10 +1222,10 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
}
static int
-ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
+ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
+ struct ath5k_txq *txq)
{
struct ath5k_hw *ah = sc->ah;
- struct ath5k_txq *txq = sc->txq;
struct ath5k_desc *ds = bf->desc;
struct sk_buff *skb = bf->skb;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1615,10 +1609,10 @@ ath5k_rx_start(struct ath5k_softc *sc)
struct ath5k_buf *bf;
int ret;
- sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz);
+ sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz);
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
- sc->cachelsz, sc->rxbufsize);
+ sc->common.cachelsz, sc->rxbufsize);
spin_lock_bh(&sc->rxbuflock);
sc->rxlink = NULL;
@@ -1747,7 +1741,7 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
static void
ath5k_tasklet_rx(unsigned long data)
{
- struct ieee80211_rx_status rxs = {};
+ struct ieee80211_rx_status *rxs;
struct ath5k_rx_status rs = {};
struct sk_buff *skb, *next_skb;
dma_addr_t next_skb_addr;
@@ -1757,6 +1751,7 @@ ath5k_tasklet_rx(unsigned long data)
int ret;
int hdrlen;
int padsize;
+ int rx_flag;
spin_lock(&sc->rxbuflock);
if (list_empty(&sc->rxbuf)) {
@@ -1764,7 +1759,7 @@ ath5k_tasklet_rx(unsigned long data)
goto unlock;
}
do {
- rxs.flag = 0;
+ rx_flag = 0;
bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
BUG_ON(bf->skb == NULL);
@@ -1808,7 +1803,7 @@ ath5k_tasklet_rx(unsigned long data)
goto accept;
}
if (rs.rs_status & AR5K_RXERR_MIC) {
- rxs.flag |= RX_FLAG_MMIC_ERROR;
+ rx_flag |= RX_FLAG_MMIC_ERROR;
goto accept;
}
@@ -1846,6 +1841,7 @@ accept:
memmove(skb->data + padsize, skb->data, hdrlen);
skb_pull(skb, padsize);
}
+ rxs = IEEE80211_SKB_RXCB(skb);
/*
* always extend the mac timestamp, since this information is
@@ -1867,41 +1863,41 @@ accept:
* impossible to comply to that. This affects IBSS merge only
* right now, so it's not too bad...
*/
- rxs.mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp);
- rxs.flag |= RX_FLAG_TSFT;
+ rxs->mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp);
+ rxs->flag = rx_flag | RX_FLAG_TSFT;
- rxs.freq = sc->curchan->center_freq;
- rxs.band = sc->curband->band;
+ rxs->freq = sc->curchan->center_freq;
+ rxs->band = sc->curband->band;
- rxs.noise = sc->ah->ah_noise_floor;
- rxs.signal = rxs.noise + rs.rs_rssi;
+ rxs->noise = sc->ah->ah_noise_floor;
+ rxs->signal = rxs->noise + rs.rs_rssi;
/* An rssi of 35 indicates you should be able use
* 54 Mbps reliably. A more elaborate scheme can be used
* here but it requires a map of SNR/throughput for each
* possible mode used */
- rxs.qual = rs.rs_rssi * 100 / 35;
+ rxs->qual = rs.rs_rssi * 100 / 35;
/* rssi can be more than 35 though, anything above that
* should be considered at 100% */
- if (rxs.qual > 100)
- rxs.qual = 100;
+ if (rxs->qual > 100)
+ rxs->qual = 100;
- rxs.antenna = rs.rs_antenna;
- rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
- rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
+ rxs->antenna = rs.rs_antenna;
+ rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
+ rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
- if (rxs.rate_idx >= 0 && rs.rs_rate ==
- sc->curband->bitrates[rxs.rate_idx].hw_value_short)
- rxs.flag |= RX_FLAG_SHORTPRE;
+ if (rxs->rate_idx >= 0 && rs.rs_rate ==
+ sc->curband->bitrates[rxs->rate_idx].hw_value_short)
+ rxs->flag |= RX_FLAG_SHORTPRE;
ath5k_debug_dump_skb(sc, skb, "RX ", 0);
/* check beacons in IBSS mode */
if (sc->opmode == NL80211_IFTYPE_ADHOC)
- ath5k_check_ibss_tsf(sc, skb, &rxs);
+ ath5k_check_ibss_tsf(sc, skb, rxs);
- __ieee80211_rx(sc->hw, skb, &rxs);
+ ieee80211_rx(sc->hw, skb);
bf->skb = next_skb;
bf->skbaddr = next_skb_addr;
@@ -1994,9 +1990,12 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
static void
ath5k_tasklet_tx(unsigned long data)
{
+ int i;
struct ath5k_softc *sc = (void *)data;
- ath5k_tx_processq(sc, sc->txq);
+ for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
+ if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
+ ath5k_tx_processq(sc, &sc->txqs[i]);
}
@@ -2078,13 +2077,6 @@ err_unmap:
return ret;
}
-static void ath5k_beacon_disable(struct ath5k_softc *sc)
-{
- sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
- ath5k_hw_set_imr(sc->ah, sc->imask);
- ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
-}
-
/*
* Transmit a beacon frame at SWBA. Dynamic updates to the
* frame contents are done as needed and the slot time is
@@ -2098,6 +2090,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
{
struct ath5k_buf *bf = sc->bbuf;
struct ath5k_hw *ah = sc->ah;
+ struct sk_buff *skb;
ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
@@ -2151,6 +2144,12 @@ ath5k_beacon_send(struct ath5k_softc *sc)
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
+ skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+ while (skb) {
+ ath5k_tx_queue(sc->hw, skb, sc->cabq);
+ skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+ }
+
sc->bsent++;
}
@@ -2271,13 +2270,11 @@ ath5k_beacon_config(struct ath5k_softc *sc)
struct ath5k_hw *ah = sc->ah;
unsigned long flags;
- ath5k_hw_set_imr(ah, 0);
+ spin_lock_irqsave(&sc->block, flags);
sc->bmisscount = 0;
sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
- if (sc->opmode == NL80211_IFTYPE_ADHOC ||
- sc->opmode == NL80211_IFTYPE_MESH_POINT ||
- sc->opmode == NL80211_IFTYPE_AP) {
+ if (sc->enable_beacon) {
/*
* In IBSS mode we use a self-linked tx descriptor and let the
* hardware send the beacons automatically. We have to load it
@@ -2290,16 +2287,17 @@ ath5k_beacon_config(struct ath5k_softc *sc)
sc->imask |= AR5K_INT_SWBA;
if (sc->opmode == NL80211_IFTYPE_ADHOC) {
- if (ath5k_hw_hasveol(ah)) {
- spin_lock_irqsave(&sc->block, flags);
+ if (ath5k_hw_hasveol(ah))
ath5k_beacon_send(sc);
- spin_unlock_irqrestore(&sc->block, flags);
- }
} else
ath5k_beacon_update_timers(sc, -1);
+ } else {
+ ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
}
ath5k_hw_set_imr(ah, sc->imask);
+ mmiowb();
+ spin_unlock_irqrestore(&sc->block, flags);
}
static void ath5k_tasklet_beacon(unsigned long data)
@@ -2363,7 +2361,7 @@ ath5k_init(struct ath5k_softc *sc)
sc->curband = &sc->sbands[sc->curchan->band];
sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
- AR5K_INT_FATAL | AR5K_INT_GLOBAL;
+ AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI;
ret = ath5k_reset(sc, NULL);
if (ret)
goto done;
@@ -2380,8 +2378,8 @@ ath5k_init(struct ath5k_softc *sc)
/* Set ack to be sent at low bit-rates */
ath5k_hw_set_ack_bitrate_high(ah, false);
- mod_timer(&sc->calib_tim, round_jiffies(jiffies +
- msecs_to_jiffies(ath5k_calinterval * 1000)));
+ /* Set PHY calibration inteval */
+ ah->ah_cal_intval = ath5k_calinterval;
ret = 0;
done:
@@ -2445,37 +2443,39 @@ ath5k_stop_hw(struct ath5k_softc *sc)
ret = ath5k_stop_locked(sc);
if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) {
/*
- * Set the chip in full sleep mode. Note that we are
- * careful to do this only when bringing the interface
- * completely to a stop. When the chip is in this state
- * it must be carefully woken up or references to
- * registers in the PCI clock domain may freeze the bus
- * (and system). This varies by chip and is mostly an
- * issue with newer parts that go to sleep more quickly.
- */
- if (sc->ah->ah_mac_srev >= 0x78) {
- /*
- * XXX
- * don't put newer MAC revisions > 7.8 to sleep because
- * of the above mentioned problems
- */
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, "
- "not putting device to sleep\n");
- } else {
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
- "putting device to full sleep\n");
- ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0);
- }
+ * Don't set the card in full sleep mode!
+ *
+ * a) When the device is in this state it must be carefully
+ * woken up or references to registers in the PCI clock
+ * domain may freeze the bus (and system). This varies
+ * by chip and is mostly an issue with newer parts
+ * (madwifi sources mentioned srev >= 0x78) that go to
+ * sleep more quickly.
+ *
+ * b) On older chips full sleep results a weird behaviour
+ * during wakeup. I tested various cards with srev < 0x78
+ * and they don't wake up after module reload, a second
+ * module reload is needed to bring the card up again.
+ *
+ * Until we figure out what's going on don't enable
+ * full chip reset on any chip (this is what Legacy HAL
+ * and Sam's HAL do anyway). Instead Perform a full reset
+ * on the device (same as initial state after attach) and
+ * leave it idle (keep MAC/BB on warm reset) */
+ ret = ath5k_hw_on_hold(sc->ah);
+
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+ "putting device to sleep\n");
}
ath5k_txbuf_free(sc, sc->bbuf);
mmiowb();
mutex_unlock(&sc->lock);
- del_timer_sync(&sc->calib_tim);
tasklet_kill(&sc->rxtq);
tasklet_kill(&sc->txtq);
tasklet_kill(&sc->restq);
+ tasklet_kill(&sc->calib);
tasklet_kill(&sc->beacontq);
ath5k_rfkill_hw_stop(sc->ah);
@@ -2531,6 +2531,9 @@ ath5k_intr(int irq, void *dev_id)
if (status & AR5K_INT_BMISS) {
/* TODO */
}
+ if (status & AR5K_INT_SWI) {
+ tasklet_schedule(&sc->calib);
+ }
if (status & AR5K_INT_MIB) {
/*
* These stats are also used for ANI i think
@@ -2547,6 +2550,8 @@ ath5k_intr(int irq, void *dev_id)
if (unlikely(!counter))
ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
+ ath5k_hw_calibration_poll(ah);
+
return IRQ_HANDLED;
}
@@ -2563,11 +2568,19 @@ ath5k_tasklet_reset(unsigned long data)
* for temperature/environment changes.
*/
static void
-ath5k_calibrate(unsigned long data)
+ath5k_tasklet_calibrate(unsigned long data)
{
struct ath5k_softc *sc = (void *)data;
struct ath5k_hw *ah = sc->ah;
+ /* Only full calibration for now */
+ if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION)
+ return;
+
+ /* Stop queues so that calibration
+ * doesn't interfere with tx */
+ ieee80211_stop_queues(sc->hw);
+
ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
ieee80211_frequency_to_channel(sc->curchan->center_freq),
sc->curchan->hw_value);
@@ -2585,8 +2598,11 @@ ath5k_calibrate(unsigned long data)
ieee80211_frequency_to_channel(
sc->curchan->center_freq));
- mod_timer(&sc->calib_tim, round_jiffies(jiffies +
- msecs_to_jiffies(ath5k_calinterval * 1000)));
+ ah->ah_swi_mask = 0;
+
+ /* Wake queues */
+ ieee80211_wake_queues(sc->hw);
+
}
@@ -2598,6 +2614,14 @@ static int
ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath5k_softc *sc = hw->priv;
+
+ return ath5k_tx_queue(hw, skb, sc->txq);
+}
+
+static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ath5k_txq *txq)
+{
+ struct ath5k_softc *sc = hw->priv;
struct ath5k_buf *bf;
unsigned long flags;
int hdrlen;
@@ -2641,7 +2665,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
bf->skb = skb;
- if (ath5k_txbuf_setup(sc, bf)) {
+ if (ath5k_txbuf_setup(sc, bf, txq)) {
bf->skb = NULL;
spin_lock_irqsave(&sc->txbuflock, flags);
list_add_tail(&bf->list, &sc->txbuf);
@@ -2676,7 +2700,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
sc->curchan = chan;
sc->curband = &sc->sbands[chan->band];
}
- ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
+ ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL);
if (ret) {
ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
goto err;
@@ -2757,6 +2781,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
}
ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
+ ath5k_mode_setup(sc);
ret = 0;
end:
@@ -2776,7 +2801,6 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
goto end;
ath5k_hw_set_lladdr(sc->ah, mac);
- ath5k_beacon_disable(sc);
sc->vif = NULL;
end:
mutex_unlock(&sc->lock);
@@ -2795,9 +2819,11 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&sc->lock);
- ret = ath5k_chan_set(sc, conf->channel);
- if (ret < 0)
- goto unlock;
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ ret = ath5k_chan_set(sc, conf->channel);
+ if (ret < 0)
+ goto unlock;
+ }
if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
(sc->power_level != conf->power_level)) {
@@ -2831,6 +2857,37 @@ unlock:
return ret;
}
+static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
+ int mc_count, struct dev_addr_list *mclist)
+{
+ u32 mfilt[2], val;
+ int i;
+ u8 pos;
+
+ mfilt[0] = 0;
+ mfilt[1] = 1;
+
+ for (i = 0; i < mc_count; i++) {
+ if (!mclist)
+ break;
+ /* calculate XOR of eight 6-bit values */
+ val = get_unaligned_le32(mclist->dmi_addr + 0);
+ pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+ val = get_unaligned_le32(mclist->dmi_addr + 3);
+ pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+ pos &= 0x3f;
+ mfilt[pos / 32] |= (1 << (pos % 32));
+ /* XXX: we might be able to just do this instead,
+ * but not sure, needs testing, if we do use this we'd
+ * neet to inform below to not reset the mcast */
+ /* ath5k_hw_set_mcast_filterindex(ah,
+ * mclist->dmi_addr[5]); */
+ mclist = mclist->next;
+ }
+
+ return ((u64)(mfilt[1]) << 32) | mfilt[0];
+}
+
#define SUPPORTED_FIF_FLAGS \
FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \
FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
@@ -2856,16 +2913,16 @@ unlock:
static void ath5k_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *new_flags,
- int mc_count, struct dev_mc_list *mclist)
+ u64 multicast)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
- u32 mfilt[2], val, rfilt;
- u8 pos;
- int i;
+ u32 mfilt[2], rfilt;
- mfilt[0] = 0;
- mfilt[1] = 0;
+ mutex_lock(&sc->lock);
+
+ mfilt[0] = multicast;
+ mfilt[1] = multicast >> 32;
/* Only deal with supported flags */
changed_flags &= SUPPORTED_FIF_FLAGS;
@@ -2891,24 +2948,6 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
if (*new_flags & FIF_ALLMULTI) {
mfilt[0] = ~0;
mfilt[1] = ~0;
- } else {
- for (i = 0; i < mc_count; i++) {
- if (!mclist)
- break;
- /* calculate XOR of eight 6-bit values */
- val = get_unaligned_le32(mclist->dmi_addr + 0);
- pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
- val = get_unaligned_le32(mclist->dmi_addr + 3);
- pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
- pos &= 0x3f;
- mfilt[pos / 32] |= (1 << (pos % 32));
- /* XXX: we might be able to just do this instead,
- * but not sure, needs testing, if we do use this we'd
- * neet to inform below to not reset the mcast */
- /* ath5k_hw_set_mcast_filterindex(ah,
- * mclist->dmi_addr[5]); */
- mclist = mclist->next;
- }
}
/* This is the best we can do */
@@ -2932,22 +2971,25 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
/* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
- if (sc->opmode == NL80211_IFTYPE_MONITOR)
- rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
- AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
- if (sc->opmode != NL80211_IFTYPE_STATION)
- rfilt |= AR5K_RX_FILTER_PROBEREQ;
- if (sc->opmode != NL80211_IFTYPE_AP &&
- sc->opmode != NL80211_IFTYPE_MESH_POINT &&
- test_bit(ATH_STAT_PROMISC, sc->status))
- rfilt |= AR5K_RX_FILTER_PROM;
- if ((sc->opmode == NL80211_IFTYPE_STATION && sc->assoc) ||
- sc->opmode == NL80211_IFTYPE_ADHOC ||
- sc->opmode == NL80211_IFTYPE_AP)
- rfilt |= AR5K_RX_FILTER_BEACON;
- if (sc->opmode == NL80211_IFTYPE_MESH_POINT)
- rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
- AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
+ switch (sc->opmode) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_MONITOR:
+ rfilt |= AR5K_RX_FILTER_CONTROL |
+ AR5K_RX_FILTER_BEACON |
+ AR5K_RX_FILTER_PROBEREQ |
+ AR5K_RX_FILTER_PROM;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_ADHOC:
+ rfilt |= AR5K_RX_FILTER_PROBEREQ |
+ AR5K_RX_FILTER_BEACON;
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (sc->assoc)
+ rfilt |= AR5K_RX_FILTER_BEACON;
+ default:
+ break;
+ }
/* Set filters */
ath5k_hw_set_rx_filter(ah, rfilt);
@@ -2957,6 +2999,8 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
/* Set the cached hw filter flags, this will alter actually
* be set in HW */
sc->filter_flags = rfilt;
+
+ mutex_unlock(&sc->lock);
}
static int
@@ -2978,6 +3022,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
case ALG_TKIP:
break;
case ALG_CCMP:
+ if (sc->ah->ah_aes_support)
+ break;
+
return -EOPNOTSUPP;
default:
WARN_ON(1);
@@ -3108,25 +3155,6 @@ out:
return ret;
}
-/*
- * Update the beacon and reconfigure the beacon queues.
- */
-static void
-ath5k_beacon_reconfig(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- int ret;
- unsigned long flags;
- struct ath5k_softc *sc = hw->priv;
-
- spin_lock_irqsave(&sc->block, flags);
- ret = ath5k_beacon_update(hw, vif);
- spin_unlock_irqrestore(&sc->block, flags);
- if (ret == 0) {
- ath5k_beacon_config(sc);
- mmiowb();
- }
-}
-
static void
set_beacon_filter(struct ieee80211_hw *hw, bool enable)
{
@@ -3149,6 +3177,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
+ unsigned long flags;
mutex_lock(&sc->lock);
if (WARN_ON(sc->vif != vif))
@@ -3170,15 +3199,37 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
sc->assoc = bss_conf->assoc;
if (sc->opmode == NL80211_IFTYPE_STATION)
set_beacon_filter(hw, sc->assoc);
+ ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
+ AR5K_LED_ASSOC : AR5K_LED_INIT);
}
- if (changes & BSS_CHANGED_BEACON &&
- (vif->type == NL80211_IFTYPE_ADHOC ||
- vif->type == NL80211_IFTYPE_MESH_POINT ||
- vif->type == NL80211_IFTYPE_AP)) {
- ath5k_beacon_reconfig(hw, vif);
+ if (changes & BSS_CHANGED_BEACON) {
+ spin_lock_irqsave(&sc->block, flags);
+ ath5k_beacon_update(hw, vif);
+ spin_unlock_irqrestore(&sc->block, flags);
}
+ if (changes & BSS_CHANGED_BEACON_ENABLED)
+ sc->enable_beacon = bss_conf->enable_beacon;
+
+ if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED |
+ BSS_CHANGED_BEACON_INT))
+ ath5k_beacon_config(sc);
+
unlock:
mutex_unlock(&sc->lock);
}
+
+static void ath5k_sw_scan_start(struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+ if (!sc->assoc)
+ ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN);
+}
+
+static void ath5k_sw_scan_complete(struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+ ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
+ AR5K_LED_ASSOC : AR5K_LED_INIT);
+}
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index f9b7f2f819b7..a28c42f32c9d 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -51,6 +51,9 @@
#include "ath5k.h"
#include "debug.h"
+#include "../regd.h"
+#include "../ath.h"
+
#define ATH_RXBUF 40 /* number of RX buffers */
#define ATH_TXBUF 200 /* number of TX buffers */
#define ATH_BCBUF 1 /* number of beacon buffers */
@@ -112,10 +115,10 @@ struct ath5k_rfkill {
* associated with an instance of a device */
struct ath5k_softc {
struct pci_dev *pdev; /* for dma mapping */
+ struct ath_common common;
void __iomem *iobase; /* address of the device */
struct mutex lock; /* dev-level lock */
- /* FIXME: how many does it really need? */
- struct ieee80211_tx_queue_stats tx_stats[16];
+ struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES];
struct ieee80211_low_level_stats ll_stats;
struct ieee80211_hw *hw; /* IEEE 802.11 common */
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
@@ -135,7 +138,6 @@ struct ath5k_softc {
struct ath5k_desc *desc; /* TX/RX descriptors */
dma_addr_t desc_daddr; /* DMA (physical) address */
size_t desc_len; /* size of TX/RX descriptors */
- u16 cachelsz; /* cache line size */
DECLARE_BITMAP(status, 5);
#define ATH_STAT_INVALID 0 /* disable hardware accesses */
@@ -171,14 +173,15 @@ struct ath5k_softc {
struct list_head txbuf; /* transmit buffer */
spinlock_t txbuflock;
unsigned int txbuf_len; /* buf count in txbuf list */
- struct ath5k_txq txqs[2]; /* beacon and tx */
-
- struct ath5k_txq *txq; /* beacon and tx*/
+ struct ath5k_txq txqs[AR5K_NUM_TX_QUEUES]; /* tx queues */
+ struct ath5k_txq *txq; /* main tx queue */
struct tasklet_struct txtq; /* tx intr tasklet */
struct ath5k_led tx_led; /* tx led */
struct ath5k_rfkill rf_kill;
+ struct tasklet_struct calib; /* calibration tasklet */
+
spinlock_t block; /* protects beacon */
struct tasklet_struct beacontq; /* beacon intr tasklet */
struct ath5k_buf *bbuf; /* beacon buffer */
@@ -187,10 +190,11 @@ struct ath5k_softc {
bintval, /* beacon interval in TU */
bsent;
unsigned int nexttbtt; /* next beacon time in TU */
+ struct ath5k_txq *cabq; /* content after beacon */
- struct timer_list calib_tim; /* calibration timer */
int power_level; /* Requested tx power in dbm */
bool assoc; /* assocate state */
+ bool enable_beacon; /* true if beacons are on */
};
#define ath5k_hw_hasbssidmask(_ah) \
@@ -198,4 +202,15 @@ struct ath5k_softc {
#define ath5k_hw_hasveol(_ah) \
(ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0)
+static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah)
+{
+ return &ah->ah_sc->common;
+}
+
+static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah)
+{
+ return &(ath5k_hw_common(ah)->regulatory);
+
+}
+
#endif
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 4904a07e4b59..747508c15d34 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -380,13 +380,15 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
ath5k_global_debugfs);
- sc->debug.debugfs_debug = debugfs_create_file("debug", S_IWUSR | S_IRUGO,
+ sc->debug.debugfs_debug = debugfs_create_file("debug",
+ S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_debug);
- sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUGO,
+ sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_registers);
- sc->debug.debugfs_beacon = debugfs_create_file("beacon", S_IWUSR | S_IRUGO,
+ sc->debug.debugfs_beacon = debugfs_create_file("beacon",
+ S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_beacon);
sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR,
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index c56b494d417a..644962adda97 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)
ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL);
ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? true : false;
+ /* Check if PCIE_OFFSET points to PCIE_SERDES_SECTION
+ * and enable serdes programming if needed.
+ *
+ * XXX: Serdes values seem to be fixed so
+ * no need to read them here, we write them
+ * during ath5k_hw_attach */
+ AR5K_EEPROM_READ(AR5K_EEPROM_PCIE_OFFSET, val);
+ ee->ee_serdes = (val == AR5K_EEPROM_PCIE_SERDES_SECTION) ?
+ true : false;
+
return 0;
}
@@ -404,27 +414,11 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
break;
}
-done:
- /* return new offset */
- *offset = o;
-
- return 0;
-}
-
-/*
- * Read turbo mode information on newer EEPROM versions
- */
-static int
-ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
- u32 *offset, unsigned int mode)
-{
- struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
- u32 o = *offset;
- u16 val;
- int ret;
-
+ /*
+ * Read turbo mode information on newer EEPROM versions
+ */
if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
- return 0;
+ goto done;
switch (mode){
case AR5K_EEPROM_MODE_11A:
@@ -458,6 +452,7 @@ ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
break;
}
+done:
/* return new offset */
*offset = o;
@@ -494,10 +489,6 @@ ath5k_eeprom_init_modes(struct ath5k_hw *ah)
ret = ath5k_eeprom_read_modes(ah, &offset, mode);
if (ret)
return ret;
-
- ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode);
- if (ret)
- return ret;
}
/* override for older eeprom versions for better performance */
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 @@
/*
* Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
*/
+#define AR5K_EEPROM_PCIE_OFFSET 0x02 /* Contains offset to PCI-E infos */
+#define AR5K_EEPROM_PCIE_SERDES_SECTION 0x40 /* PCIE_OFFSET points here when
+ * SERDES infos are present */
#define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */
#define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */
#define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */
@@ -391,6 +394,7 @@ struct ath5k_eeprom_info {
u8 ee_rfkill_pin;
bool ee_rfkill_pol;
bool ee_is_hb63;
+ bool ee_serdes;
u16 ee_misc0;
u16 ee_misc1;
u16 ee_misc2;
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index 876725f08b6c..b767c3b67b24 100644
--- a/drivers/net/wireless/ath/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -69,6 +69,8 @@ static const struct pci_device_id ath5k_led_devices[] = {
{ ATH_SDEVICE(PCI_VENDOR_ID_AZWAVE, 0x1026), ATH_LED(3, 0) },
/* IBM ThinkPad AR5BXB6 (legovini@spiro.fisica.unipd.it) */
{ ATH_SDEVICE(PCI_VENDOR_ID_IBM, 0x058a), ATH_LED(1, 0) },
+ /* HP Compaq C700 (nitrousnrg@gmail.com) */
+ { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 1) },
/* IBM-specific AR5212 (all others) */
{ PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) },
{ }
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index a876ca8d69ef..1a039f2bd732 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,
AR5K_RF_XPD_GAIN, true);
} else {
- /* TODO: Set high and low gain bits */
- ath5k_hw_rfb_op(ah, rf_regs,
- ee->ee_x_gain[ee_mode],
+ u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode];
+ if (ee->ee_pd_gains[ee_mode] > 1) {
+ ath5k_hw_rfb_op(ah, rf_regs,
+ pdg_curve_to_idx[0],
AR5K_RF_PD_GAIN_LO, true);
- ath5k_hw_rfb_op(ah, rf_regs,
- ee->ee_x_gain[ee_mode],
+ ath5k_hw_rfb_op(ah, rf_regs,
+ pdg_curve_to_idx[1],
AR5K_RF_PD_GAIN_HI, true);
+ } else {
+ ath5k_hw_rfb_op(ah, rf_regs,
+ pdg_curve_to_idx[0],
+ AR5K_RF_PD_GAIN_LO, true);
+ ath5k_hw_rfb_op(ah, rf_regs,
+ pdg_curve_to_idx[0],
+ AR5K_RF_PD_GAIN_HI, true);
+ }
/* Lower synth voltage on Rev 2 */
ath5k_hw_rfb_op(ah, rf_regs, 2,
@@ -1085,8 +1094,7 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
AR5K_PHY_CCKTXCTL_WORLD);
}
- ah->ah_current_channel.center_freq = channel->center_freq;
- ah->ah_current_channel.hw_value = channel->hw_value;
+ ah->ah_current_channel = channel;
ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false;
return 0;
@@ -1096,6 +1104,29 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
PHY calibration
\*****************/
+void
+ath5k_hw_calibration_poll(struct ath5k_hw *ah)
+{
+ /* Calibration interval in jiffies */
+ unsigned long cal_intval;
+
+ cal_intval = msecs_to_jiffies(ah->ah_cal_intval * 1000);
+
+ /* Initialize timestamp if needed */
+ if (!ah->ah_cal_tstamp)
+ ah->ah_cal_tstamp = jiffies;
+
+ /* For now we always do full calibration
+ * Mark software interrupt mask and fire software
+ * interrupt (bit gets auto-cleared) */
+ if (time_is_before_eq_jiffies(ah->ah_cal_tstamp + cal_intval)) {
+ ah->ah_cal_tstamp = jiffies;
+ ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION;
+ AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI);
+ }
+
+}
+
/**
* ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
*
@@ -1731,7 +1762,7 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable)
void
ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
{
- struct ieee80211_channel *channel = &ah->ah_current_channel;
+ struct ieee80211_channel *channel = ah->ah_current_channel;
bool use_def_for_tx, update_def_on_tx, use_def_for_rts, fast_div;
bool use_def_for_sg;
u8 def_ant, tx_ant, ee_mode;
@@ -1897,8 +1928,9 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR,
s16 min_pwrL, min_pwrR;
s16 pwr_i;
- if (WARN_ON(stepL[0] == stepL[1] || stepR[0] == stepR[1]))
- return 0;
+ /* Some vendors write the same pcdac value twice !!! */
+ if (stepL[0] == stepL[1] || stepR[0] == stepR[1])
+ return max(pwrL[0], pwrR[0]);
if (pwrL[0] == pwrL[1])
min_pwrL = pwrL[0];
@@ -2166,6 +2198,7 @@ static void
ath5k_get_max_ctl_power(struct ath5k_hw *ah,
struct ieee80211_channel *channel)
{
+ struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
struct ath5k_edge_power *rep = ee->ee_ctl_pwr;
u8 *ctl_val = ee->ee_ctl;
@@ -2176,7 +2209,7 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah,
u8 ctl_idx = 0xFF;
u32 target = channel->center_freq;
- ctl_mode = ath_regd_get_band_ctl(&ah->ah_regulatory, channel->band);
+ ctl_mode = ath_regd_get_band_ctl(regulatory, channel->band);
switch (channel->hw_value & CHANNEL_MODES) {
case CHANNEL_A:
@@ -3011,7 +3044,7 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
{
/*Just a try M.F.*/
- struct ieee80211_channel *channel = &ah->ah_current_channel;
+ struct ieee80211_channel *channel = ah->ah_current_channel;
u8 ee_mode;
ATH5K_TRACE(ah->ah_sc);
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index 73407b3f53ef..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)
}
if (tq->tqi_ready_time &&
- (tq->tqi_type != AR5K_TX_QUEUE_ID_CAB))
+ (tq->tqi_type != AR5K_TX_QUEUE_CAB))
ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
AR5K_QCU_RDYTIMECFG_INTVAL) |
AR5K_QCU_RDYTIMECFG_ENABLE,
@@ -411,7 +411,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
AR5K_QCU_MISC_FRSHED_BCN_SENT_GT |
AR5K_QCU_MISC_CBREXP_DIS |
- AR5K_QCU_MISC_RDY_VEOL_POLICY |
AR5K_QCU_MISC_CBREXP_BCN_DIS);
ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h
index 6809b54a2ad7..debad07d9900 100644
--- a/drivers/net/wireless/ath/ath5k/reg.h
+++ b/drivers/net/wireless/ath/ath5k/reg.h
@@ -339,9 +339,9 @@
#define AR5K_SISR2 0x008c /* Register Address [5211+] */
#define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */
#define AR5K_SISR2_QCU_TXURN_S 0
-#define AR5K_SISR2_MCABT 0x00100000 /* Master Cycle Abort */
-#define AR5K_SISR2_SSERR 0x00200000 /* Signaled System Error */
-#define AR5K_SISR2_DPERR 0x00400000 /* Bus parity error */
+#define AR5K_SISR2_MCABT 0x00010000 /* Master Cycle Abort */
+#define AR5K_SISR2_SSERR 0x00020000 /* Signaled System Error */
+#define AR5K_SISR2_DPERR 0x00040000 /* Bus parity error */
#define AR5K_SISR2_TIM 0x01000000 /* [5212+] */
#define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */
#define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */
@@ -430,9 +430,9 @@
#define AR5K_SIMR2 0x00ac /* Register Address [5211+] */
#define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */
#define AR5K_SIMR2_QCU_TXURN_S 0
-#define AR5K_SIMR2_MCABT 0x00100000 /* Master Cycle Abort */
-#define AR5K_SIMR2_SSERR 0x00200000 /* Signaled System Error */
-#define AR5K_SIMR2_DPERR 0x00400000 /* Bus parity error */
+#define AR5K_SIMR2_MCABT 0x00010000 /* Master Cycle Abort */
+#define AR5K_SIMR2_SSERR 0x00020000 /* Signaled System Error */
+#define AR5K_SIMR2_DPERR 0x00040000 /* Bus parity error */
#define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */
#define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */
#define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index bd0a97a38d34..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,
if (!set_chip)
goto commit;
- /* Preserve sleep duration */
data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
+
+ /* If card is down we 'll get 0xffff... so we
+ * need to clean this up before we write the register
+ */
if (data & 0xffc00000)
data = 0;
else
- data = data & 0xfffcffff;
+ /* Preserve sleep duration etc */
+ data = data & ~AR5K_SLEEP_CTL_SLE;
- ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
+ ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
+ AR5K_SLEEP_CTL);
udelay(15);
- for (i = 50; i > 0; i--) {
+ for (i = 200; i > 0; i--) {
/* Check if the chip did wake up */
if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
AR5K_PCICFG_SPWR_DN) == 0)
break;
/* Wait a bit and retry */
- udelay(200);
- ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
+ udelay(50);
+ ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
+ AR5K_SLEEP_CTL);
}
/* Fail if the chip didn't wake up */
- if (i <= 0)
+ if (i == 0)
return -EIO;
break;
@@ -290,13 +296,70 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
}
commit:
- ah->ah_power_mode = mode;
ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
return 0;
}
/*
+ * Put device on hold
+ *
+ * Put MAC and Baseband on warm reset and
+ * keep that state (don't clean sleep control
+ * register). After this MAC and Baseband are
+ * disabled and a full reset is needed to come
+ * back. This way we save as much power as possible
+ * without puting the card on full sleep.
+ */
+int ath5k_hw_on_hold(struct ath5k_hw *ah)
+{
+ struct pci_dev *pdev = ah->ah_sc->pdev;
+ u32 bus_flags;
+ int ret;
+
+ /* Make sure device is awake */
+ ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
+ return ret;
+ }
+
+ /*
+ * Put chipset on warm reset...
+ *
+ * Note: puting PCI core on warm reset on PCI-E cards
+ * results card to hang and always return 0xffff... so
+ * we ingore that flag for PCI-E cards. On PCI cards
+ * this flag gets cleared after 64 PCI clocks.
+ */
+ bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
+
+ if (ah->ah_version == AR5K_AR5210) {
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+ AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
+ AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
+ mdelay(2);
+ } else {
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+ AR5K_RESET_CTL_BASEBAND | bus_flags);
+ }
+
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc, "failed to put device on warm reset\n");
+ return -EIO;
+ }
+
+ /* ...wakeup again!*/
+ ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc, "failed to put device on hold\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
* Bring up MAC + PHY Chips and program PLL
* TODO: Half/Quarter rate support
*/
@@ -319,6 +382,50 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
return ret;
}
+ /*
+ * Put chipset on warm reset...
+ *
+ * Note: puting PCI core on warm reset on PCI-E cards
+ * results card to hang and always return 0xffff... so
+ * we ingore that flag for PCI-E cards. On PCI cards
+ * this flag gets cleared after 64 PCI clocks.
+ */
+ bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
+
+ if (ah->ah_version == AR5K_AR5210) {
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+ AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
+ AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
+ mdelay(2);
+ } else {
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+ AR5K_RESET_CTL_BASEBAND | bus_flags);
+ }
+
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
+ return -EIO;
+ }
+
+ /* ...wakeup again!...*/
+ ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
+ return ret;
+ }
+
+ /* ...clear reset control register and pull device out of
+ * warm reset */
+ if (ath5k_hw_nic_reset(ah, 0)) {
+ ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
+ return -EIO;
+ }
+
+ /* On initialization skip PLL programming since we don't have
+ * a channel / mode set yet */
+ if (initial)
+ return 0;
+
if (ah->ah_version != AR5K_AR5210) {
/*
* Get channel mode flags
@@ -384,39 +491,6 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
AR5K_PHY_TURBO);
}
- /* reseting PCI on PCI-E cards results card to hang
- * and always return 0xffff... so we ingore that flag
- * for PCI-E cards */
- bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
-
- /* Reset chipset */
- if (ah->ah_version == AR5K_AR5210) {
- ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
- AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
- AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
- mdelay(2);
- } else {
- ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
- AR5K_RESET_CTL_BASEBAND | bus_flags);
- }
- if (ret) {
- ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
- return -EIO;
- }
-
- /* ...wakeup again!*/
- ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
- if (ret) {
- ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
- return ret;
- }
-
- /* ...final warm reset */
- if (ath5k_hw_nic_reset(ah, 0)) {
- ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
- return -EIO;
- }
-
if (ah->ah_version != AR5K_AR5210) {
/* ...update PLL if needed */
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 2d79610bce12..ef5f59c4dd80 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -1,13 +1,18 @@
config ATH9K
tristate "Atheros 802.11n wireless cards support"
depends on PCI && MAC80211 && WLAN_80211
- select ATH_COMMON
select MAC80211_LEDS
select LEDS_CLASS
select NEW_LEDS
---help---
This module adds support for wireless adapters based on
- Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets.
+ Atheros IEEE 802.11n AR5008, AR9001 and AR9002 family
+ of chipsets. For a specific list of supported external
+ cards, laptops that already ship with these cards and
+ APs that come with these cards refer to to ath9k wiki
+ products page:
+
+ http://wireless.kernel.org/en/users/Drivers/ath9k/products
If you choose to build a module, it'll be called ath9k.
@@ -18,6 +23,6 @@ config ATH9K_DEBUG
Say Y, if you need ath9k to display debug messages.
Pass the debug mask as a module parameter:
- modprobe ath9k debug=0x00002000
+ modprobe ath9k debug=0x00000200
- Look in ath9k/core.h for possible debug masks
+ Look in ath9k/debug.h for possible debug masks
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 783bc39eb2ff..ff2c9a26c10c 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -1,5 +1,8 @@
ath9k-y += hw.o \
eeprom.o \
+ eeprom_def.o \
+ eeprom_4k.o \
+ eeprom_9287.o \
mac.o \
calib.o \
ani.o \
@@ -9,7 +12,8 @@ ath9k-y += hw.o \
recv.o \
xmit.o \
virtual.o \
- rc.o
+ rc.o \
+ btcoex.o
ath9k-$(CONFIG_PCI) += pci.o
ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 0e65c51ba176..2ad7d0280f7a 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -119,17 +119,15 @@ static int ath_ahb_probe(struct platform_device *pdev)
sc->bus_ops = &ath_ahb_bus_ops;
sc->irq = irq;
- ret = ath_attach(AR5416_AR9100_DEVID, sc);
- if (ret != 0) {
- dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
- ret = -ENODEV;
+ ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize device\n");
goto err_free_hw;
}
ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
if (ret) {
- dev_err(&pdev->dev, "request_irq failed, err=%d\n", ret);
- ret = -EIO;
+ dev_err(&pdev->dev, "request_irq failed\n");
goto err_detach;
}
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index aad259b4c197..a7cbb07988cf 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)
return;
aniState = ah->curani;
-
aniState->listenTime = 0;
- if (ah->has_hw_phycounters) {
- if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
- aniState->ofdmPhyErrBase = 0;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "OFDM Trigger is too high for hw counters\n");
- } else {
- aniState->ofdmPhyErrBase =
- AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
- }
- if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
- aniState->cckPhyErrBase = 0;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "CCK Trigger is too high for hw counters\n");
- } else {
- aniState->cckPhyErrBase =
- AR_PHY_COUNTMAX - aniState->cckTrigHigh;
- }
+
+ if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
+ aniState->ofdmPhyErrBase = 0;
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Writing ofdmbase=%u cckbase=%u\n",
- aniState->ofdmPhyErrBase,
- aniState->cckPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
- REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
-
- ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
+ "OFDM Trigger is too high for hw counters\n");
+ } else {
+ aniState->ofdmPhyErrBase =
+ AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
+ }
+ if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
+ aniState->cckPhyErrBase = 0;
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "CCK Trigger is too high for hw counters\n");
+ } else {
+ aniState->cckPhyErrBase =
+ AR_PHY_COUNTMAX - aniState->cckTrigHigh;
}
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Writing ofdmbase=%u cckbase=%u\n",
+ aniState->ofdmPhyErrBase,
+ aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+ ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
+
aniState->ofdmPhyErrCount = 0;
aniState->cckPhyErrCount = 0;
}
@@ -530,32 +529,26 @@ void ath9k_ani_reset(struct ath_hw *ah)
if (aniState->firstepLevel != 0)
ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel);
- if (ah->has_hw_phycounters) {
- ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
- ~ATH9K_RX_FILTER_PHYERR);
- ath9k_ani_restart(ah);
- REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
- REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
- } else {
- ath9k_ani_restart(ah);
- ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
- ATH9K_RX_FILTER_PHYERR);
- }
+ ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
+ ~ATH9K_RX_FILTER_PHYERR);
+ ath9k_ani_restart(ah);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
}
void ath9k_hw_ani_monitor(struct ath_hw *ah,
- const struct ath9k_node_stats *stats,
struct ath9k_channel *chan)
{
struct ar5416AniState *aniState;
int32_t listenTime;
+ u32 phyCnt1, phyCnt2;
+ u32 ofdmPhyErrCnt, cckPhyErrCnt;
if (!DO_ANI(ah))
return;
aniState = ah->curani;
- ah->stats.ast_nodestats = *stats;
listenTime = ath9k_hw_ani_get_listen_time(ah);
if (listenTime < 0) {
@@ -566,50 +559,45 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
aniState->listenTime += listenTime;
- if (ah->has_hw_phycounters) {
- u32 phyCnt1, phyCnt2;
- u32 ofdmPhyErrCnt, cckPhyErrCnt;
+ ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
- ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
-
- phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
- phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
-
- if (phyCnt1 < aniState->ofdmPhyErrBase ||
- phyCnt2 < aniState->cckPhyErrBase) {
- if (phyCnt1 < aniState->ofdmPhyErrBase) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "phyCnt1 0x%x, resetting "
- "counter value to 0x%x\n",
- phyCnt1, aniState->ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_1,
- aniState->ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_MASK_1,
- AR_PHY_ERR_OFDM_TIMING);
- }
- if (phyCnt2 < aniState->cckPhyErrBase) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "phyCnt2 0x%x, resetting "
- "counter value to 0x%x\n",
- phyCnt2, aniState->cckPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_2,
- aniState->cckPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_MASK_2,
- AR_PHY_ERR_CCK_TIMING);
- }
- return;
+ phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+ phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+
+ if (phyCnt1 < aniState->ofdmPhyErrBase ||
+ phyCnt2 < aniState->cckPhyErrBase) {
+ if (phyCnt1 < aniState->ofdmPhyErrBase) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "phyCnt1 0x%x, resetting "
+ "counter value to 0x%x\n",
+ phyCnt1, aniState->ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_1,
+ aniState->ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_1,
+ AR_PHY_ERR_OFDM_TIMING);
+ }
+ if (phyCnt2 < aniState->cckPhyErrBase) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "phyCnt2 0x%x, resetting "
+ "counter value to 0x%x\n",
+ phyCnt2, aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_2,
+ aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_2,
+ AR_PHY_ERR_CCK_TIMING);
}
+ return;
+ }
- ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
- ah->stats.ast_ani_ofdmerrs +=
- ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
- aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+ ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+ ah->stats.ast_ani_ofdmerrs +=
+ ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+ aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
- cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
- ah->stats.ast_ani_cckerrs +=
- cckPhyErrCnt - aniState->cckPhyErrCount;
- aniState->cckPhyErrCount = cckPhyErrCnt;
- }
+ cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+ ah->stats.ast_ani_cckerrs +=
+ cckPhyErrCnt - aniState->cckPhyErrCount;
+ aniState->cckPhyErrCount = cckPhyErrCnt;
if (aniState->listenTime > 5 * ah->aniperiod) {
if (aniState->ofdmPhyErrCount <= aniState->listenTime *
@@ -632,11 +620,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
}
}
-bool ath9k_hw_phycounters(struct ath_hw *ah)
-{
- return ah->has_hw_phycounters ? true : false;
-}
-
void ath9k_enable_mib_counters(struct ath_hw *ah)
{
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
@@ -708,8 +691,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
* any of the MIB counters overflow/trigger so don't assume we're
* here because a PHY error counter triggered.
*/
-void ath9k_hw_procmibevent(struct ath_hw *ah,
- const struct ath9k_node_stats *stats)
+void ath9k_hw_procmibevent(struct ath_hw *ah)
{
u32 phyCnt1, phyCnt2;
@@ -721,7 +703,6 @@ void ath9k_hw_procmibevent(struct ath_hw *ah,
/* Clear the mib counters and save them in the stats */
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
- ah->stats.ast_nodestats = *stats;
if (!DO_ANI(ah))
return;
@@ -777,13 +758,11 @@ void ath9k_hw_ani_setup(struct ath_hw *ah)
}
}
-void ath9k_hw_ani_attach(struct ath_hw *ah)
+void ath9k_hw_ani_init(struct ath_hw *ah)
{
int i;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n");
-
- ah->has_hw_phycounters = 1;
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Initialize ANI\n");
memset(ah->ani, 0, sizeof(ah->ani));
for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
@@ -799,36 +778,32 @@ void ath9k_hw_ani_attach(struct ath_hw *ah)
ATH9K_ANI_CCK_WEAK_SIG_THR;
ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
- if (ah->has_hw_phycounters) {
- ah->ani[i].ofdmPhyErrBase =
- AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
- ah->ani[i].cckPhyErrBase =
- AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
- }
- }
- if (ah->has_hw_phycounters) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Setting OfdmErrBase = 0x%08x\n",
- ah->ani[0].ofdmPhyErrBase);
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
- ah->ani[0].cckPhyErrBase);
-
- REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
- ath9k_enable_mib_counters(ah);
+ ah->ani[i].ofdmPhyErrBase =
+ AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
+ ah->ani[i].cckPhyErrBase =
+ AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
}
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Setting OfdmErrBase = 0x%08x\n",
+ ah->ani[0].ofdmPhyErrBase);
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
+ ah->ani[0].cckPhyErrBase);
+
+ REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
+ ath9k_enable_mib_counters(ah);
+
ah->aniperiod = ATH9K_ANI_PERIOD;
if (ah->config.enable_ani)
ah->proc_phyerr |= HAL_PROCESS_ANI;
}
-void ath9k_hw_ani_detach(struct ath_hw *ah)
+void ath9k_hw_ani_disable(struct ath_hw *ah)
{
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n");
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling ANI\n");
- if (ah->has_hw_phycounters) {
- ath9k_hw_disable_mib_counters(ah);
- REG_WRITE(ah, AR_PHY_ERR_1, 0);
- REG_WRITE(ah, AR_PHY_ERR_2, 0);
- }
+ ath9k_hw_disable_mib_counters(ah);
+ REG_WRITE(ah, AR_PHY_ERR_1, 0);
+ REG_WRITE(ah, AR_PHY_ERR_2, 0);
}
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h
index 08b4e7ed5ff0..4e1ab94a5153 100644
--- a/drivers/net/wireless/ath/ath9k/ani.h
+++ b/drivers/net/wireless/ath/ath9k/ani.h
@@ -18,15 +18,10 @@
#define ANI_H
#define HAL_PROCESS_ANI 0x00000001
-#define ATH9K_RSSI_EP_MULTIPLIER (1<<7)
#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI))
-#define HAL_EP_RND(x, mul) \
- ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
-#define BEACON_RSSI(ahp) \
- HAL_EP_RND(ahp->stats.ast_nodestats.ns_avgbrssi, \
- ATH9K_RSSI_EP_MULTIPLIER)
+#define BEACON_RSSI(ahp) (ahp->stats.avgbrssi)
#define ATH9K_ANI_OFDM_TRIG_HIGH 500
#define ATH9K_ANI_OFDM_TRIG_LOW 200
@@ -65,13 +60,6 @@ struct ath9k_mib_stats {
u32 beacons;
};
-struct ath9k_node_stats {
- u32 ns_avgbrssi;
- u32 ns_avgrssi;
- u32 ns_avgtxrssi;
- u32 ns_avgtxrate;
-};
-
struct ar5416AniState {
struct ath9k_channel *c;
u8 noiseImmunityLevel;
@@ -115,24 +103,21 @@ struct ar5416Stats {
u32 ast_ani_reset;
u32 ast_ani_lzero;
u32 ast_ani_lneg;
+ u32 avgbrssi;
struct ath9k_mib_stats ast_mibstats;
- struct ath9k_node_stats ast_nodestats;
};
#define ah_mibStats stats.ast_mibstats
void ath9k_ani_reset(struct ath_hw *ah);
void ath9k_hw_ani_monitor(struct ath_hw *ah,
- const struct ath9k_node_stats *stats,
struct ath9k_channel *chan);
-bool ath9k_hw_phycounters(struct ath_hw *ah);
void ath9k_enable_mib_counters(struct ath_hw *ah);
void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt,
u32 *rxf_pcnt, u32 *txf_pcnt);
-void ath9k_hw_procmibevent(struct ath_hw *ah,
- const struct ath9k_node_stats *stats);
+void ath9k_hw_procmibevent(struct ath_hw *ah);
void ath9k_hw_ani_setup(struct ath_hw *ah);
-void ath9k_hw_ani_attach(struct ath_hw *ah);
-void ath9k_hw_ani_detach(struct ath_hw *ah);
+void ath9k_hw_ani_init(struct ath_hw *ah);
+void ath9k_hw_ani_disable(struct ath_hw *ah);
#endif /* ANI_H */
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5efc9345ca0d..1d59f10f68da 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -25,6 +25,8 @@
#include "hw.h"
#include "rc.h"
#include "debug.h"
+#include "../ath.h"
+#include "btcoex.h"
struct ath_node;
@@ -164,7 +166,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define WME_NUM_TID 16
#define ATH_TXBUF 512
#define ATH_TXMAXTRY 13
-#define ATH_11N_TXMAXTRY 10
#define ATH_MGT_TXMAXTRY 4
#define WME_BA_BMP_SIZE 64
#define WME_MAX_BA WME_BA_BMP_SIZE
@@ -191,12 +192,9 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_AGGR_MIN_QDEPTH 2
#define ATH_AMPDU_SUBFRAME_DEFAULT 32
#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1)
-#define ATH_AMPDU_LIMIT_DEFAULT ATH_AMPDU_LIMIT_MAX
#define IEEE80211_SEQ_SEQ_SHIFT 4
#define IEEE80211_SEQ_MAX 4096
-#define IEEE80211_MIN_AMPDU_BUF 0x8
-#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
#define IEEE80211_WEP_IVLEN 3
#define IEEE80211_WEP_KIDLEN 1
#define IEEE80211_WEP_CRCLEN 4
@@ -226,6 +224,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)])
+#define ATH_TX_COMPLETE_POLL_INT 1000
+
enum ATH_AGGR_STATUS {
ATH_AGGR_DONE,
ATH_AGGR_BAW_CLOSED,
@@ -239,8 +239,8 @@ struct ath_txq {
spinlock_t axq_lock;
u32 axq_depth;
u8 axq_aggr_depth;
- u32 axq_totalqueued;
bool stopped;
+ bool axq_tx_inprogress;
struct ath_buf *axq_linkbuf;
/* first desc of the last descriptor that contains CTS */
@@ -272,7 +272,6 @@ struct ath_atx_tid {
int sched;
int paused;
u8 state;
- int addba_exchangeattempts;
};
struct ath_atx_ac {
@@ -292,12 +291,28 @@ struct ath_tx_control {
#define ATH_TX_XRETRY 0x02
#define ATH_TX_BAR 0x04
+#define ATH_RSSI_LPF_LEN 10
+#define RSSI_LPF_THRESHOLD -20
+#define ATH9K_RSSI_BAD 0x80
+#define ATH_RSSI_EP_MULTIPLIER (1<<7)
+#define ATH_EP_MUL(x, mul) ((x) * (mul))
+#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
+#define ATH_LPF_RSSI(x, y, len) \
+ ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y))
+#define ATH_RSSI_LPF(x, y) do { \
+ if ((y) >= RSSI_LPF_THRESHOLD) \
+ x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
+} while (0)
+#define ATH_EP_RND(x, mul) \
+ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+
struct ath_node {
struct ath_softc *an_sc;
struct ath_atx_tid tid[WME_NUM_TID];
struct ath_atx_ac ac[WME_NUM_AC];
u16 maxampdu;
u8 mpdudensity;
+ int last_rssi;
};
struct ath_tx {
@@ -348,9 +363,9 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
void ath_tx_tasklet(struct ath_softc *sc);
void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
-int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
- u16 tid, u16 *ssn);
-int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+ u16 tid, u16 *ssn);
+void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
/********/
@@ -440,7 +455,8 @@ struct ath_ani {
/* LED Control */
/********************/
-#define ATH_LED_PIN 1
+#define ATH_LED_PIN_DEF 1
+#define ATH_LED_PIN_9287 8
#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */
#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */
@@ -506,6 +522,8 @@ struct ath_led {
#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17)
#define SC_OP_WAIT_FOR_TX_ACK BIT(18)
#define SC_OP_BEACON_SYNC BIT(19)
+#define SC_OP_BTCOEX_ENABLED BIT(20)
+#define SC_OP_BT_PRIORITY_DETECTED BIT(21)
struct ath_bus_ops {
void (*read_cachesize)(struct ath_softc *sc, int *csz);
@@ -519,6 +537,8 @@ struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
+ struct ath_common common;
+
spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */
struct ath_wiphy *pri_wiphy;
struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may
@@ -541,6 +561,8 @@ struct ath_softc {
int irq;
spinlock_t sc_resetlock;
spinlock_t sc_serial_rw;
+ spinlock_t ani_lock;
+ spinlock_t sc_pm_lock;
struct mutex mutex;
u8 curbssid[ETH_ALEN];
@@ -549,7 +571,6 @@ struct ath_softc {
u32 sc_flags; /* SC_OP_* */
u16 curtxpow;
u16 curaid;
- u16 cachelsz;
u8 nbcnvifs;
u16 nvifs;
u8 tx_chainmask;
@@ -557,7 +578,8 @@ struct ath_softc {
u32 keymax;
DECLARE_BITMAP(keymap, ATH_KEYMAX);
u8 splitmic;
- atomic_t ps_usecount;
+ bool ps_enabled;
+ unsigned long ps_usecount;
enum ath9k_int imask;
enum ath9k_ht_extprotspacing ht_extprotspacing;
enum ath9k_ht_macmode tx_chan_width;
@@ -584,12 +606,13 @@ struct ath_softc {
int beacon_interval;
struct ath_ani ani;
- struct ath9k_node_stats nodestats;
#ifdef CONFIG_ATH9K_DEBUG
struct ath9k_debug debug;
#endif
struct ath_bus_ops *bus_ops;
struct ath_beacon_config cur_beacon_conf;
+ struct delayed_work tx_complete_work;
+ struct ath_btcoex_info btcoex_info;
};
struct ath_wiphy {
@@ -611,6 +634,16 @@ int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
int ath_cabq_update(struct ath_softc *);
+static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
+{
+ return &ah->ah_sc->common;
+}
+
+static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah)
+{
+ return &(ath9k_hw_common(ah)->regulatory);
+}
+
static inline void ath_read_cachesize(struct ath_softc *sc, int *csz)
{
sc->bus_ops->read_cachesize(sc, csz);
@@ -625,7 +658,7 @@ extern struct ieee80211_ops ath9k_ops;
irqreturn_t ath_isr(int irq, void *dev);
void ath_cleanup(struct ath_softc *sc);
-int ath_attach(u16 devid, struct ath_softc *sc);
+int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid);
void ath_detach(struct ath_softc *sc);
const char *ath_mac_bb_name(u32 mac_bb_version);
const char *ath_rf_name(u16 rf_version);
@@ -654,27 +687,8 @@ static inline int ath_ahb_init(void) { return 0; };
static inline void ath_ahb_exit(void) {};
#endif
-static inline void ath9k_ps_wakeup(struct ath_softc *sc)
-{
- if (atomic_inc_return(&sc->ps_usecount) == 1)
- if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
- sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
- }
-}
-
-static inline void ath9k_ps_restore(struct ath_softc *sc)
-{
- if (atomic_dec_and_test(&sc->ps_usecount))
- if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
- !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
- SC_OP_WAIT_FOR_CAB |
- SC_OP_WAIT_FOR_PSPOLL_DATA |
- SC_OP_WAIT_FOR_TX_ACK)))
- ath9k_hw_setpower(sc->sc_ah,
- sc->sc_ah->restore_mode);
-}
-
+void ath9k_ps_wakeup(struct ath_softc *sc);
+void ath9k_ps_restore(struct ath_softc *sc);
void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
int ath9k_wiphy_add(struct ath_softc *sc);
@@ -690,8 +704,10 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
struct ath_wiphy *selected);
bool ath9k_wiphy_scanning(struct ath_softc *sc);
void ath9k_wiphy_work(struct work_struct *work);
+bool ath9k_all_wiphys_idle(struct ath_softc *sc);
void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val);
unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset);
+int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
#endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 3639a2e6987d..45c4ea57616b 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -674,13 +674,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
- /*
- * It looks like mac80211 may end up using beacon interval of zero in
- * some cases (at least for mesh point). Avoid getting into an
- * infinite loop by using a bit safer value instead..
- */
- if (intval == 0)
- intval = 100;
/* Pull nexttbtt forward to reflect the current TSF */
@@ -745,6 +738,14 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
iftype = sc->sc_ah->opmode;
}
+ /*
+ * It looks like mac80211 may end up using beacon interval of zero in
+ * some cases (at least for mesh point). Avoid getting into an
+ * infinite loop by using a bit safer value instead. To be safe,
+ * do sanity check on beacon interval for all operating modes.
+ */
+ if (cur_conf->beacon_interval == 0)
+ cur_conf->beacon_interval = 100;
switch (iftype) {
case NL80211_IFTYPE_AP:
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
new file mode 100644
index 000000000000..55f607b7699e
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+
+static const struct ath_btcoex_config ath_bt_config = { 0, true, true,
+ ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true };
+
+static const u16 ath_subsysid_tbl[] = {
+ AR9280_COEX2WIRE_SUBSYSID,
+ AT9285_COEX3WIRE_SA_SUBSYSID,
+ AT9285_COEX3WIRE_DA_SUBSYSID
+};
+
+/*
+ * Checks the subsystem id of the device to see if it
+ * supports btcoex
+ */
+bool ath_btcoex_supported(u16 subsysid)
+{
+ int i;
+
+ if (!subsysid)
+ return false;
+
+ for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++)
+ if (subsysid == ath_subsysid_tbl[i])
+ return true;
+
+ return false;
+}
+
+/*
+ * Detects if there is any priority bt traffic
+ */
+static void ath_detect_bt_priority(struct ath_softc *sc)
+{
+ struct ath_btcoex_info *btinfo = &sc->btcoex_info;
+
+ if (ath9k_hw_gpio_get(sc->sc_ah, btinfo->btpriority_gpio))
+ btinfo->bt_priority_cnt++;
+
+ if (time_after(jiffies, btinfo->bt_priority_time +
+ msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
+ if (btinfo->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
+ DPRINTF(sc, ATH_DBG_BTCOEX,
+ "BT priority traffic detected");
+ sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
+ } else {
+ sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+ }
+
+ btinfo->bt_priority_cnt = 0;
+ btinfo->bt_priority_time = jiffies;
+ }
+}
+
+/*
+ * Configures appropriate weight based on stomp type.
+ */
+static void ath_btcoex_bt_stomp(struct ath_softc *sc,
+ struct ath_btcoex_info *btinfo,
+ int stomp_type)
+{
+
+ switch (stomp_type) {
+ case ATH_BTCOEX_STOMP_ALL:
+ ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
+ AR_STOMP_ALL_WLAN_WGHT);
+ break;
+ case ATH_BTCOEX_STOMP_LOW:
+ ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
+ AR_STOMP_LOW_WLAN_WGHT);
+ break;
+ case ATH_BTCOEX_STOMP_NONE:
+ ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
+ AR_STOMP_NONE_WLAN_WGHT);
+ break;
+ default:
+ DPRINTF(sc, ATH_DBG_BTCOEX, "Invalid Stomptype\n");
+ break;
+ }
+
+ ath9k_hw_btcoex_enable(sc->sc_ah);
+}
+
+/*
+ * This is the master bt coex timer which runs for every
+ * 45ms, bt traffic will be given priority during 55% of this
+ * period while wlan gets remaining 45%
+ */
+
+static void ath_btcoex_period_timer(unsigned long data)
+{
+ struct ath_softc *sc = (struct ath_softc *) data;
+ struct ath_btcoex_info *btinfo = &sc->btcoex_info;
+
+ ath_detect_bt_priority(sc);
+
+ spin_lock_bh(&btinfo->btcoex_lock);
+
+ ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type);
+
+ spin_unlock_bh(&btinfo->btcoex_lock);
+
+ if (btinfo->btcoex_period != btinfo->btcoex_no_stomp) {
+ if (btinfo->hw_timer_enabled)
+ ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
+
+ ath_gen_timer_start(sc->sc_ah,
+ btinfo->no_stomp_timer,
+ (ath9k_hw_gettsf32(sc->sc_ah) +
+ btinfo->btcoex_no_stomp),
+ btinfo->btcoex_no_stomp * 10);
+ btinfo->hw_timer_enabled = true;
+ }
+
+ mod_timer(&btinfo->period_timer, jiffies +
+ msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
+}
+
+/*
+ * Generic tsf based hw timer which configures weight
+ * registers to time slice between wlan and bt traffic
+ */
+
+static void ath_btcoex_no_stomp_timer(void *arg)
+{
+ struct ath_softc *sc = (struct ath_softc *)arg;
+ struct ath_btcoex_info *btinfo = &sc->btcoex_info;
+
+ DPRINTF(sc, ATH_DBG_BTCOEX, "no stomp timer running \n");
+
+ spin_lock_bh(&btinfo->btcoex_lock);
+
+ if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
+ ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE);
+ else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
+ ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW);
+
+ spin_unlock_bh(&btinfo->btcoex_lock);
+}
+
+static int ath_init_btcoex_info(struct ath_hw *hw,
+ struct ath_btcoex_info *btcoex_info)
+{
+ u32 i;
+ int qnum;
+
+ qnum = ath_tx_get_qnum(hw->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
+
+ btcoex_info->bt_coex_mode =
+ (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) |
+ SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) |
+ SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) |
+ SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
+ SM(ath_bt_config.bt_mode, AR_BT_MODE) |
+ SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) |
+ SM(ath_bt_config.bt_rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) |
+ SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) |
+ SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) |
+ SM(qnum, AR_BT_QCU_THRESH);
+
+ btcoex_info->bt_coex_mode2 =
+ SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |
+ SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |
+ AR_BT_DISABLE_BT_ANT;
+
+ btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+
+ btcoex_info->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
+
+ btcoex_info->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
+ btcoex_info->btcoex_period / 100;
+
+ for (i = 0; i < 32; i++)
+ hw->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i;
+
+ setup_timer(&btcoex_info->period_timer, ath_btcoex_period_timer,
+ (unsigned long) hw->ah_sc);
+
+ btcoex_info->no_stomp_timer = ath_gen_timer_alloc(hw,
+ ath_btcoex_no_stomp_timer,
+ ath_btcoex_no_stomp_timer,
+ (void *)hw->ah_sc, AR_FIRST_NDP_TIMER);
+
+ if (btcoex_info->no_stomp_timer == NULL)
+ return -ENOMEM;
+
+ spin_lock_init(&btcoex_info->btcoex_lock);
+
+ return 0;
+}
+
+int ath9k_hw_btcoex_init(struct ath_hw *ah)
+{
+ struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
+ int ret = 0;
+
+ if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) {
+ /* connect bt_active to baseband */
+ REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
+ AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
+
+ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
+
+ /* Set input mux for bt_active to gpio pin */
+ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_ACTIVE,
+ btcoex_info->btactive_gpio);
+
+ /* Configure the desired gpio port for input */
+ ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio);
+ } else {
+ /* btcoex 3-wire */
+ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
+ AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
+
+ /* Set input mux for bt_prority_async and
+ * bt_active_async to GPIO pins */
+ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_ACTIVE,
+ btcoex_info->btactive_gpio);
+
+ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_PRIORITY,
+ btcoex_info->btpriority_gpio);
+
+ /* Configure the desired GPIO ports for input */
+
+ ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio);
+ ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio);
+
+ ret = ath_init_btcoex_info(ah, btcoex_info);
+ }
+
+ return ret;
+}
+
+void ath9k_hw_btcoex_enable(struct ath_hw *ah)
+{
+ struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
+
+ if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) {
+ /* Configure the desired GPIO port for TX_FRAME output */
+ ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
+ AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
+ } else {
+ /*
+ * Program coex mode and weight registers to
+ * enable coex 3-wire
+ */
+ REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_info->bt_coex_mode);
+ REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_info->bt_coex_weights);
+ REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_info->bt_coex_mode2);
+
+ REG_RMW_FIELD(ah, AR_QUIET1,
+ AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
+ REG_RMW_FIELD(ah, AR_PCU_MISC,
+ AR_PCU_BT_ANT_PREVENT_RX, 0);
+
+ ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
+ AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
+ }
+
+ REG_RMW(ah, AR_GPIO_PDPU,
+ (0x2 << (btcoex_info->btactive_gpio * 2)),
+ (0x3 << (btcoex_info->btactive_gpio * 2)));
+
+ ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED;
+}
+
+void ath9k_hw_btcoex_disable(struct ath_hw *ah)
+{
+ struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
+
+ ath9k_hw_set_gpio(ah, btcoex_info->wlanactive_gpio, 0);
+
+ ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+
+ if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) {
+ REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
+ REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
+ REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
+ }
+
+ ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED;
+}
+
+/*
+ * Pause btcoex timer and bt duty cycle timer
+ */
+void ath_btcoex_timer_pause(struct ath_softc *sc,
+ struct ath_btcoex_info *btinfo)
+{
+
+ del_timer_sync(&btinfo->period_timer);
+
+ if (btinfo->hw_timer_enabled)
+ ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
+
+ btinfo->hw_timer_enabled = false;
+}
+
+/*
+ * (Re)start btcoex timers
+ */
+void ath_btcoex_timer_resume(struct ath_softc *sc,
+ struct ath_btcoex_info *btinfo)
+{
+
+ DPRINTF(sc, ATH_DBG_BTCOEX, "Starting btcoex timers");
+
+ /* make sure duty cycle timer is also stopped when resuming */
+ if (btinfo->hw_timer_enabled)
+ ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
+
+ btinfo->bt_priority_cnt = 0;
+ btinfo->bt_priority_time = jiffies;
+ sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+
+ mod_timer(&btinfo->period_timer, jiffies);
+}
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
new file mode 100644
index 000000000000..297b027fd3c3
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BTCOEX_H
+#define BTCOEX_H
+
+#define ATH_WLANACTIVE_GPIO 5
+#define ATH_BTACTIVE_GPIO 6
+#define ATH_BTPRIORITY_GPIO 7
+
+#define ATH_BTCOEX_DEF_BT_PERIOD 45
+#define ATH_BTCOEX_DEF_DUTY_CYCLE 55
+#define ATH_BTCOEX_BMISS_THRESH 50
+
+#define ATH_BT_PRIORITY_TIME_THRESHOLD 1000 /* ms */
+#define ATH_BT_CNT_THRESHOLD 3
+
+enum ath_btcoex_scheme {
+ ATH_BTCOEX_CFG_NONE,
+ ATH_BTCOEX_CFG_2WIRE,
+ ATH_BTCOEX_CFG_3WIRE,
+};
+
+enum ath_stomp_type {
+ ATH_BTCOEX_NO_STOMP,
+ ATH_BTCOEX_STOMP_ALL,
+ ATH_BTCOEX_STOMP_LOW,
+ ATH_BTCOEX_STOMP_NONE
+};
+
+enum ath_bt_mode {
+ ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */
+ ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */
+ ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */
+ ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */
+};
+
+struct ath_btcoex_config {
+ u8 bt_time_extend;
+ bool bt_txstate_extend;
+ bool bt_txframe_extend;
+ enum ath_bt_mode bt_mode; /* coexistence mode */
+ bool bt_quiet_collision;
+ bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/
+ u8 bt_priority_time;
+ u8 bt_first_slot_time;
+ bool bt_hold_rx_clear;
+};
+
+struct ath_btcoex_info {
+ enum ath_btcoex_scheme btcoex_scheme;
+ u8 wlanactive_gpio;
+ u8 btactive_gpio;
+ u8 btpriority_gpio;
+ u8 bt_duty_cycle; /* BT duty cycle in percentage */
+ int bt_stomp_type; /* Types of BT stomping */
+ u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */
+ u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */
+ u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */
+ u32 btcoex_no_stomp; /* in usec */
+ u32 btcoex_period; /* in usec */
+ u32 bt_priority_cnt;
+ unsigned long bt_priority_time;
+ bool hw_timer_enabled;
+ spinlock_t btcoex_lock;
+ struct timer_list period_timer; /* Timer for BT period */
+ struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/
+};
+
+bool ath_btcoex_supported(u16 subsysid);
+int ath9k_hw_btcoex_init(struct ath_hw *ah);
+void ath9k_hw_btcoex_enable(struct ath_hw *ah);
+void ath9k_hw_btcoex_disable(struct ath_hw *ah);
+void ath_btcoex_timer_resume(struct ath_softc *sc,
+ struct ath_btcoex_info *btinfo);
+void ath_btcoex_timer_pause(struct ath_softc *sc,
+ struct ath_btcoex_info *btinfo);
+
+static inline void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info,
+ u32 bt_weight,
+ u32 wlan_weight)
+{
+ btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) |
+ SM(wlan_weight, AR_BTCOEX_WL_WGHT);
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index a32d7e7fecbe..3234995e8881 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -116,7 +116,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
"NF calibrated [ctl] [chain 1] is %d\n", nf);
nfarray[1] = nf;
- if (!AR_SREV_9280(ah)) {
+ if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
AR_PHY_CH2_MINCCA_PWR);
if (nf & 0x100)
@@ -154,7 +154,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
"NF calibrated [ext] [chain 1] is %d\n", nf);
nfarray[4] = nf;
- if (!AR_SREV_9280(ah)) {
+ if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
AR_PHY_CH2_EXT_MINCCA_PWR);
if (nf & 0x100)
@@ -613,7 +613,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
if (AR_SREV_9285(ah))
chainmask = 0x9;
- else if (AR_SREV_9280(ah))
+ else if (AR_SREV_9280(ah) || AR_SREV_9287(ah))
chainmask = 0x1B;
else
chainmask = 0x3F;
@@ -691,15 +691,22 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
{
int i, j;
+ s16 noise_floor;
+
+ if (AR_SREV_9280(ah))
+ noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
+ else if (AR_SREV_9285(ah))
+ noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
+ else
+ noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
for (i = 0; i < NUM_NF_READINGS; i++) {
ah->nfCalHist[i].currIndex = 0;
- ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
+ ah->nfCalHist[i].privNF = noise_floor;
ah->nfCalHist[i].invalidNFcount =
AR_PHY_CCA_FILTERWINDOW_LENGTH;
for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
- ah->nfCalHist[i].nfCalBuffer[j] =
- AR_PHY_CCA_MAX_GOOD_VALUE;
+ ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
}
}
}
@@ -722,31 +729,139 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
static void ath9k_olc_temp_compensation(struct ath_hw *ah)
{
u32 rddata, i;
- int delta, currPDADC, regval;
+ int delta, currPDADC, regval, slope;
rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
-
currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
- if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
- delta = (currPDADC - ah->initPDADC + 4) / 8;
- else
- delta = (currPDADC - ah->initPDADC + 5) / 10;
- if (delta != ah->PDADCdelta) {
- ah->PDADCdelta = delta;
- for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
- regval = ah->originalGain[i] - delta;
- if (regval < 0)
- regval = 0;
+ if (OLC_FOR_AR9287_10_LATER) {
+ if (ah->initPDADC == 0 || currPDADC == 0) {
+ return;
+ } else {
+ slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
+ if (slope == 0)
+ delta = 0;
+ else
+ delta = ((currPDADC - ah->initPDADC)*4) / slope;
+ REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
+ AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
+ REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
+ AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
+ }
+ } else {
+ if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
+ delta = (currPDADC - ah->initPDADC + 4) / 8;
+ else
+ delta = (currPDADC - ah->initPDADC + 5) / 10;
+
+ if (delta != ah->PDADCdelta) {
+ ah->PDADCdelta = delta;
+ for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
+ regval = ah->originalGain[i] - delta;
+ if (regval < 0)
+ regval = 0;
- REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4,
- AR_PHY_TX_GAIN, regval);
+ REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4,
+ AR_PHY_TX_GAIN, regval);
+ }
}
}
}
-static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
+static void ath9k_hw_9271_pa_cal(struct ath_hw *ah)
+{
+ u32 regVal;
+ unsigned int i;
+ u32 regList [][2] = {
+ { 0x786c, 0 },
+ { 0x7854, 0 },
+ { 0x7820, 0 },
+ { 0x7824, 0 },
+ { 0x7868, 0 },
+ { 0x783c, 0 },
+ { 0x7838, 0 } ,
+ { 0x7828, 0 } ,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(regList); i++)
+ regList[i][1] = REG_READ(ah, regList[i][0]);
+
+ regVal = REG_READ(ah, 0x7834);
+ regVal &= (~(0x1));
+ REG_WRITE(ah, 0x7834, regVal);
+ regVal = REG_READ(ah, 0x9808);
+ regVal |= (0x1 << 27);
+ REG_WRITE(ah, 0x9808, regVal);
+
+ /* 786c,b23,1, pwddac=1 */
+ REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
+ /* 7854, b5,1, pdrxtxbb=1 */
+ REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
+ /* 7854, b7,1, pdv2i=1 */
+ REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
+ /* 7854, b8,1, pddacinterface=1 */
+ REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
+ /* 7824,b12,0, offcal=0 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
+ /* 7838, b1,0, pwddb=0 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
+ /* 7820,b11,0, enpacal=0 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
+ /* 7820,b25,1, pdpadrv1=0 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
+ /* 7820,b24,0, pdpadrv2=0 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1,AR9285_AN_RF2G1_PDPADRV2,0);
+ /* 7820,b23,0, pdpaout=0 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
+ /* 783c,b14-16,7, padrvgn2tab_0=7 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G8,AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
+ /*
+ * 7838,b29-31,0, padrvgn1tab_0=0
+ * does not matter since we turn it off
+ */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G7,AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
+
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
+
+ /* Set:
+ * localmode=1,bmode=1,bmoderxtx=1,synthon=1,
+ * txon=1,paon=1,oscon=1,synthon_force=1
+ */
+ REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
+ udelay(30);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0);
+
+ /* find off_6_1; */
+ for (i = 6; i >= 0; i--) {
+ regVal = REG_READ(ah, 0x7834);
+ regVal |= (1 << (20 + i));
+ REG_WRITE(ah, 0x7834, regVal);
+ udelay(1);
+ //regVal = REG_READ(ah, 0x7834);
+ regVal &= (~(0x1 << (20 + i)));
+ regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9)
+ << (20 + i));
+ REG_WRITE(ah, 0x7834, regVal);
+ }
+
+ /* Empirical offset correction */
+#if 0
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0x20);
+#endif
+
+ regVal = REG_READ(ah, 0x7834);
+ regVal |= 0x1;
+ REG_WRITE(ah, 0x7834, regVal);
+ regVal = REG_READ(ah, 0x9808);
+ regVal &= (~(0x1 << 27));
+ REG_WRITE(ah, 0x9808, regVal);
+
+ for (i = 0; i < ARRAY_SIZE(regList); i++)
+ REG_WRITE(ah, regList[i][0], regList[i][1]);
+}
+
+static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset)
{
u32 regVal;
@@ -762,6 +877,13 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
{ 0x7838, 0 },
};
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
+
+ /* PA CAL is not needed for high power solution */
+ if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
+ AR5416_EEP_TXGAIN_HIGH_POWER)
+ return;
+
if (AR_SREV_9285_11(ah)) {
REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
udelay(10);
@@ -784,13 +906,13 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
- REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
- REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);
REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
udelay(30);
@@ -802,7 +924,6 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
regVal |= (1 << (19 + i));
REG_WRITE(ah, 0x7834, regVal);
udelay(1);
- regVal = REG_READ(ah, 0x7834);
regVal &= (~(0x1 << (19 + i)));
reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
regVal |= (reg_field << (19 + i));
@@ -821,6 +942,17 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
offs_6_1 = offset>>1;
offs_0 = offset & 1;
+ if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) {
+ if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
+ ah->pacal_info.max_skipcount =
+ 2 * ah->pacal_info.max_skipcount;
+ ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
+ } else {
+ ah->pacal_info.max_skipcount = 1;
+ ah->pacal_info.skipcount = 0;
+ ah->pacal_info.prev_offset = offset;
+ }
+
REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
@@ -862,14 +994,30 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
}
}
+ /* Do NF cal only at longer intervals */
if (longcal) {
- if (AR_SREV_9285_11_OR_LATER(ah))
- ath9k_hw_9285_pa_cal(ah);
+ /* Do periodic PAOffset Cal */
+ if (AR_SREV_9271(ah))
+ ath9k_hw_9271_pa_cal(ah);
+ else if (AR_SREV_9285_11_OR_LATER(ah)) {
+ if (!ah->pacal_info.skipcount)
+ ath9k_hw_9285_pa_cal(ah, false);
+ else
+ ah->pacal_info.skipcount--;
+ }
- if (OLC_FOR_AR9280_20_LATER)
+ if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER)
ath9k_olc_temp_compensation(ah);
+
+ /* Get the value from the previous NF cal and update history buffer */
ath9k_hw_getnf(ah, chan);
+
+ /*
+ * Load the NF from history buffer of the current channel.
+ * NF is slow time-variant, so it is OK to use a historical value.
+ */
ath9k_hw_loadnf(ah, ah->curchan);
+
ath9k_hw_start_nfcal(ah);
}
@@ -922,8 +1070,11 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
return false;
} else {
if (AR_SREV_9280_10_OR_LATER(ah)) {
- REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
- REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+ if (!AR_SREV_9287_10_OR_LATER(ah))
+ REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
+ AR_PHY_ADC_CTL_OFF_PWDADC);
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_FLTR_CAL);
}
/* Calibrate the AGC */
@@ -941,14 +1092,17 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
}
if (AR_SREV_9280_10_OR_LATER(ah)) {
- REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
- REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+ if (!AR_SREV_9287_10_OR_LATER(ah))
+ REG_SET_BIT(ah, AR_PHY_ADC_CTL,
+ AR_PHY_ADC_CTL_OFF_PWDADC);
+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_FLTR_CAL);
}
}
/* Do PA Calibration */
if (AR_SREV_9285_11_OR_LATER(ah))
- ath9k_hw_9285_pa_cal(ah);
+ ath9k_hw_9285_pa_cal(ah, true);
/* Do NF Calibration after DC offset and other calibrations */
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index fe5367f14148..019bcbba40ed 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -25,7 +25,9 @@ extern const struct ath9k_percal_data adc_dc_cal_multi_sample;
extern const struct ath9k_percal_data adc_dc_cal_single_sample;
extern const struct ath9k_percal_data adc_init_dc_cal;
-#define AR_PHY_CCA_MAX_GOOD_VALUE -85
+#define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE -85
+#define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE -112
+#define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE -118
#define AR_PHY_CCA_MAX_HIGH_VALUE -62
#define AR_PHY_CCA_MIN_BAD_VALUE -140
#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3
@@ -108,6 +110,13 @@ struct ath9k_nfcal_hist {
u8 invalidNFcount;
};
+#define MAX_PACAL_SKIPCOUNT 8
+struct ath9k_pacal_info{
+ int32_t prev_offset; /* Previous value of PA offset value */
+ int8_t max_skipcount; /* Max No. of times PACAL can be skipped */
+ int8_t skipcount; /* No. of times the PACAL to be skipped */
+};
+
bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
void ath9k_hw_start_nfcal(struct ath_hw *ah);
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 6d20725d6451..2be4c2252047 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -93,6 +93,8 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
int i, qcuOffset = 0, dcuOffset = 0;
u32 *qcuBase = &val[0], *dcuBase = &val[4];
+ ath9k_ps_wakeup(sc);
+
REG_WRITE(ah, AR_MACMISC,
((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
(AR_MACMISC_MISC_OBS_BUS_1 <<
@@ -159,6 +161,8 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len,
"AR_CR: 0x%x \n", REG_READ(ah, AR_CR));
+ ath9k_ps_restore(sc);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -486,6 +490,83 @@ static const struct file_operations fops_wiphy = {
.owner = THIS_MODULE
};
+#define PR(str, elem) \
+ do { \
+ len += snprintf(buf + len, size - len, \
+ "%s%13u%11u%10u%10u\n", str, \
+ sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BE]].elem, \
+ sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BK]].elem, \
+ sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VI]].elem, \
+ sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VO]].elem); \
+} while(0)
+
+static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ char *buf;
+ unsigned int len = 0, size = 2048;
+ ssize_t retval = 0;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return 0;
+
+ len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO");
+
+ PR("MPDUs Queued: ", queued);
+ PR("MPDUs Completed: ", completed);
+ PR("Aggregates: ", a_aggr);
+ PR("AMPDUs Queued: ", a_queued);
+ PR("AMPDUs Completed:", a_completed);
+ PR("AMPDUs Retried: ", a_retries);
+ PR("AMPDUs XRetried: ", a_xretries);
+ PR("FIFO Underrun: ", fifo_underrun);
+ PR("TXOP Exceeded: ", xtxop);
+ PR("TXTIMER Expiry: ", timer_exp);
+ PR("DESC CFG Error: ", desc_cfg_err);
+ PR("DATA Underrun: ", data_underrun);
+ PR("DELIM Underrun: ", delim_underrun);
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+}
+
+void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf)
+{
+ struct ath_desc *ds = bf->bf_desc;
+
+ if (bf_isampdu(bf)) {
+ if (bf_isxretried(bf))
+ TX_STAT_INC(txq->axq_qnum, a_xretries);
+ else
+ TX_STAT_INC(txq->axq_qnum, a_completed);
+ } else {
+ TX_STAT_INC(txq->axq_qnum, completed);
+ }
+
+ if (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO)
+ TX_STAT_INC(txq->axq_qnum, fifo_underrun);
+ if (ds->ds_txstat.ts_status & ATH9K_TXERR_XTXOP)
+ TX_STAT_INC(txq->axq_qnum, xtxop);
+ if (ds->ds_txstat.ts_status & ATH9K_TXERR_TIMER_EXPIRED)
+ TX_STAT_INC(txq->axq_qnum, timer_exp);
+ if (ds->ds_txstat.ts_flags & ATH9K_TX_DESC_CFG_ERR)
+ TX_STAT_INC(txq->axq_qnum, desc_cfg_err);
+ if (ds->ds_txstat.ts_flags & ATH9K_TX_DATA_UNDERRUN)
+ TX_STAT_INC(txq->axq_qnum, data_underrun);
+ if (ds->ds_txstat.ts_flags & ATH9K_TX_DELIM_UNDERRUN)
+ TX_STAT_INC(txq->axq_qnum, delim_underrun);
+}
+
+static const struct file_operations fops_xmit = {
+ .read = read_file_xmit,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE
+};
int ath9k_init_debug(struct ath_softc *sc)
{
@@ -500,35 +581,42 @@ int ath9k_init_debug(struct ath_softc *sc)
goto err;
sc->debug.debugfs_debug = debugfs_create_file("debug",
- S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
+ S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
if (!sc->debug.debugfs_debug)
goto err;
- sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
+ sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR,
sc->debug.debugfs_phy, sc, &fops_dma);
if (!sc->debug.debugfs_dma)
goto err;
sc->debug.debugfs_interrupt = debugfs_create_file("interrupt",
- S_IRUGO,
+ S_IRUSR,
sc->debug.debugfs_phy,
sc, &fops_interrupt);
if (!sc->debug.debugfs_interrupt)
goto err;
sc->debug.debugfs_rcstat = debugfs_create_file("rcstat",
- S_IRUGO,
+ S_IRUSR,
sc->debug.debugfs_phy,
sc, &fops_rcstat);
if (!sc->debug.debugfs_rcstat)
goto err;
sc->debug.debugfs_wiphy = debugfs_create_file(
- "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc,
+ "wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc,
&fops_wiphy);
if (!sc->debug.debugfs_wiphy)
goto err;
+ sc->debug.debugfs_xmit = debugfs_create_file("xmit",
+ S_IRUSR,
+ sc->debug.debugfs_phy,
+ sc, &fops_xmit);
+ if (!sc->debug.debugfs_xmit)
+ goto err;
+
return 0;
err:
ath9k_exit_debug(sc);
@@ -537,6 +625,7 @@ err:
void ath9k_exit_debug(struct ath_softc *sc)
{
+ debugfs_remove(sc->debug.debugfs_xmit);
debugfs_remove(sc->debug.debugfs_wiphy);
debugfs_remove(sc->debug.debugfs_rcstat);
debugfs_remove(sc->debug.debugfs_interrupt);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index edda15bf2c15..7241f4748338 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -30,11 +30,22 @@ enum ATH_DEBUG {
ATH_DBG_CONFIG = 0x00000200,
ATH_DBG_FATAL = 0x00000400,
ATH_DBG_PS = 0x00000800,
+ ATH_DBG_HWTIMER = 0x00001000,
+ ATH_DBG_BTCOEX = 0x00002000,
ATH_DBG_ANY = 0xffffffff
};
#define DBG_DEFAULT (ATH_DBG_FATAL)
+struct ath_txq;
+struct ath_buf;
+
+#ifdef CONFIG_ATH9K_DEBUG
+#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
+#else
+#define TX_STAT_INC(q, c) do { } while (0)
+#endif
+
#ifdef CONFIG_ATH9K_DEBUG
/**
@@ -87,9 +98,45 @@ struct ath_rc_stats {
u8 per;
};
+/**
+ * struct ath_tx_stats - Statistics about TX
+ * @queued: Total MPDUs (non-aggr) queued
+ * @completed: Total MPDUs (non-aggr) completed
+ * @a_aggr: Total no. of aggregates queued
+ * @a_queued: Total AMPDUs queued
+ * @a_completed: Total AMPDUs completed
+ * @a_retries: No. of AMPDUs retried (SW)
+ * @a_xretries: No. of AMPDUs dropped due to xretries
+ * @fifo_underrun: FIFO underrun occurrences
+ Valid only for:
+ - non-aggregate condition.
+ - first packet of aggregate.
+ * @xtxop: No. of frames filtered because of TXOP limit
+ * @timer_exp: Transmit timer expiry
+ * @desc_cfg_err: Descriptor configuration errors
+ * @data_urn: TX data underrun errors
+ * @delim_urn: TX delimiter underrun errors
+ */
+struct ath_tx_stats {
+ u32 queued;
+ u32 completed;
+ u32 a_aggr;
+ u32 a_queued;
+ u32 a_completed;
+ u32 a_retries;
+ u32 a_xretries;
+ u32 fifo_underrun;
+ u32 xtxop;
+ u32 timer_exp;
+ u32 desc_cfg_err;
+ u32 data_underrun;
+ u32 delim_underrun;
+};
+
struct ath_stats {
struct ath_interrupt_stats istats;
struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
+ struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
};
struct ath9k_debug {
@@ -100,6 +147,7 @@ struct ath9k_debug {
struct dentry *debugfs_interrupt;
struct dentry *debugfs_rcstat;
struct dentry *debugfs_wiphy;
+ struct dentry *debugfs_xmit;
struct ath_stats stats;
};
@@ -110,6 +158,8 @@ int ath9k_debug_create_root(void);
void ath9k_debug_remove_root(void);
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb);
+void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf);
void ath_debug_stat_retries(struct ath_softc *sc, int rix,
int xretries, int retries, u8 per);
@@ -148,6 +198,12 @@ static inline void ath_debug_stat_rc(struct ath_softc *sc,
{
}
+static inline void ath_debug_stat_tx(struct ath_softc *sc,
+ struct ath_txq *txq,
+ struct ath_buf *bf)
+{
+}
+
static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix,
int xretries, int retries, u8 per)
{
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index ce0e86c36a82..b6e52d0f8c48 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -16,9 +16,16 @@
#include "ath9k.h"
-static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah,
- u32 reg, u32 mask,
- u32 shift, u32 val)
+static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
+{
+ if (fbin == AR5416_BCHAN_UNUSED)
+ return fbin;
+
+ return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
+}
+
+void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
+ u32 shift, u32 val)
{
u32 regVal;
@@ -33,19 +40,8 @@ static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah,
return;
}
-static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
-{
-
- if (fbin == AR5416_BCHAN_UNUSED)
- return fbin;
-
- return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
-}
-
-static inline int16_t ath9k_hw_interpolate(u16 target,
- u16 srcLeft, u16 srcRight,
- int16_t targetLeft,
- int16_t targetRight)
+int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
+ int16_t targetLeft, int16_t targetRight)
{
int16_t rv;
@@ -59,9 +55,8 @@ static inline int16_t ath9k_hw_interpolate(u16 target,
return rv;
}
-static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList,
- u16 listSize, u16 *indexL,
- u16 *indexR)
+bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
+ u16 *indexL, u16 *indexR)
{
u16 i;
@@ -88,16 +83,16 @@ static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList,
return false;
}
-static inline bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
+bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
{
struct ath_softc *sc = ah->ah_sc;
return sc->bus_ops->eeprom_read(ah, off, data);
}
-static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
- u8 *pVpdList, u16 numIntercepts,
- u8 *pRetVpdList)
+void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
+ u8 *pVpdList, u16 numIntercepts,
+ u8 *pRetVpdList)
{
u16 i, k;
u8 currPwr = pwrMin;
@@ -120,16 +115,14 @@ static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
pRetVpdList[i] = (u8) k;
currPwr += 2;
}
-
- return true;
}
-static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
- struct ath9k_channel *chan,
- struct cal_target_power_leg *powInfo,
- u16 numChannels,
- struct cal_target_power_leg *pNewPower,
- u16 numRates, bool isExtTarget)
+void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ struct cal_target_power_leg *powInfo,
+ u16 numChannels,
+ struct cal_target_power_leg *pNewPower,
+ u16 numRates, bool isExtTarget)
{
struct chan_centers centers;
u16 clo, chi;
@@ -150,10 +143,10 @@ static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
IS_CHAN_2GHZ(chan))) {
matchIndex = i;
break;
- } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
- IS_CHAN_2GHZ(chan))) &&
- (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
- IS_CHAN_2GHZ(chan)))) {
+ } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+ IS_CHAN_2GHZ(chan)) && i > 0 &&
+ freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+ IS_CHAN_2GHZ(chan))) {
lowIndex = i - 1;
break;
}
@@ -179,75 +172,12 @@ static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
}
}
-static void ath9k_get_txgain_index(struct ath_hw *ah,
- struct ath9k_channel *chan,
- struct calDataPerFreqOpLoop *rawDatasetOpLoop,
- u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx)
-{
- u8 pcdac, i = 0;
- u16 idxL = 0, idxR = 0, numPiers;
- bool match;
- struct chan_centers centers;
-
- ath9k_hw_get_channel_centers(ah, chan, &centers);
-
- for (numPiers = 0; numPiers < availPiers; numPiers++)
- if (calChans[numPiers] == AR5416_BCHAN_UNUSED)
- break;
-
- match = ath9k_hw_get_lower_upper_index(
- (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
- calChans, numPiers, &idxL, &idxR);
- if (match) {
- pcdac = rawDatasetOpLoop[idxL].pcdac[0][0];
- *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0];
- } else {
- pcdac = rawDatasetOpLoop[idxR].pcdac[0][0];
- *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] +
- rawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
- }
-
- while (pcdac > ah->originalGain[i] &&
- i < (AR9280_TX_GAIN_TABLE_SIZE - 1))
- i++;
-
- *pcdacIdx = i;
- return;
-}
-
-static void ath9k_olc_get_pdadcs(struct ath_hw *ah,
- u32 initTxGain,
- int txPower,
- u8 *pPDADCValues)
-{
- u32 i;
- u32 offset;
-
- REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0,
- AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
- REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1,
- AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
-
- REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7,
- AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain);
-
- offset = txPower;
- for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++)
- if (i < offset)
- pPDADCValues[i] = 0x0;
- else
- pPDADCValues[i] = 0xFF;
-}
-
-
-
-
-static void ath9k_hw_get_target_powers(struct ath_hw *ah,
- struct ath9k_channel *chan,
- struct cal_target_power_ht *powInfo,
- u16 numChannels,
- struct cal_target_power_ht *pNewPower,
- u16 numRates, bool isHt40Target)
+void ath9k_hw_get_target_powers(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ struct cal_target_power_ht *powInfo,
+ u16 numChannels,
+ struct cal_target_power_ht *pNewPower,
+ u16 numRates, bool isHt40Target)
{
struct chan_centers centers;
u16 clo, chi;
@@ -268,10 +198,10 @@ static void ath9k_hw_get_target_powers(struct ath_hw *ah,
matchIndex = i;
break;
} else
- if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
- IS_CHAN_2GHZ(chan))) &&
- (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
- IS_CHAN_2GHZ(chan)))) {
+ if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+ IS_CHAN_2GHZ(chan)) && i > 0 &&
+ freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+ IS_CHAN_2GHZ(chan))) {
lowIndex = i - 1;
break;
}
@@ -297,9 +227,8 @@ static void ath9k_hw_get_target_powers(struct ath_hw *ah,
}
}
-static u16 ath9k_hw_get_max_edge_power(u16 freq,
- struct cal_ctl_edges *pRdEdgesPower,
- bool is2GHz, int num_band_edges)
+u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
+ bool is2GHz, int num_band_edges)
{
u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
int i;
@@ -325,2451 +254,14 @@ static u16 ath9k_hw_get_max_edge_power(u16 freq,
return twiceMaxEdgePower;
}
-/****************************************/
-/* EEPROM Operations for 4K sized cards */
-/****************************************/
-
-static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah)
-{
- return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF);
-}
-
-static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah)
-{
- return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF);
-}
-
-static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
-{
-#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
- u16 *eep_data = (u16 *)&ah->eeprom.map4k;
- int addr, eep_start_loc = 0;
-
- eep_start_loc = 64;
-
- if (!ath9k_hw_use_flash(ah)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Reading from EEPROM, not flash\n");
- }
-
- for (addr = 0; addr < SIZE_EEPROM_4K; addr++) {
- if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Unable to read eeprom region \n");
- return false;
- }
- eep_data++;
- }
-
- return true;
-#undef SIZE_EEPROM_4K
-}
-
-static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
-{
-#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
- struct ar5416_eeprom_4k *eep =
- (struct ar5416_eeprom_4k *) &ah->eeprom.map4k;
- u16 *eepdata, temp, magic, magic2;
- u32 sum = 0, el;
- bool need_swap = false;
- int i, addr;
-
-
- if (!ath9k_hw_use_flash(ah)) {
- if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
- &magic)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Reading Magic # failed\n");
- return false;
- }
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Read Magic = 0x%04X\n", magic);
-
- if (magic != AR5416_EEPROM_MAGIC) {
- magic2 = swab16(magic);
-
- if (magic2 == AR5416_EEPROM_MAGIC) {
- need_swap = true;
- eepdata = (u16 *) (&ah->eeprom);
-
- for (addr = 0; addr < EEPROM_4K_SIZE; addr++) {
- temp = swab16(*eepdata);
- *eepdata = temp;
- eepdata++;
- }
- } else {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Invalid EEPROM Magic. "
- "endianness mismatch.\n");
- return -EINVAL;
- }
- }
- }
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
- need_swap ? "True" : "False");
-
- if (need_swap)
- el = swab16(ah->eeprom.map4k.baseEepHeader.length);
- else
- el = ah->eeprom.map4k.baseEepHeader.length;
-
- if (el > sizeof(struct ar5416_eeprom_4k))
- el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16);
- else
- el = el / sizeof(u16);
-
- eepdata = (u16 *)(&ah->eeprom);
-
- for (i = 0; i < el; i++)
- sum ^= *eepdata++;
-
- if (need_swap) {
- u32 integer;
- u16 word;
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "EEPROM Endianness is not native.. Changing\n");
-
- word = swab16(eep->baseEepHeader.length);
- eep->baseEepHeader.length = word;
-
- word = swab16(eep->baseEepHeader.checksum);
- eep->baseEepHeader.checksum = word;
-
- word = swab16(eep->baseEepHeader.version);
- eep->baseEepHeader.version = word;
-
- word = swab16(eep->baseEepHeader.regDmn[0]);
- eep->baseEepHeader.regDmn[0] = word;
-
- word = swab16(eep->baseEepHeader.regDmn[1]);
- eep->baseEepHeader.regDmn[1] = word;
-
- word = swab16(eep->baseEepHeader.rfSilent);
- eep->baseEepHeader.rfSilent = word;
-
- word = swab16(eep->baseEepHeader.blueToothOptions);
- eep->baseEepHeader.blueToothOptions = word;
-
- word = swab16(eep->baseEepHeader.deviceCap);
- eep->baseEepHeader.deviceCap = word;
-
- integer = swab32(eep->modalHeader.antCtrlCommon);
- eep->modalHeader.antCtrlCommon = integer;
-
- for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
- integer = swab32(eep->modalHeader.antCtrlChain[i]);
- eep->modalHeader.antCtrlChain[i] = integer;
- }
-
- for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
- word = swab16(eep->modalHeader.spurChans[i].spurChan);
- eep->modalHeader.spurChans[i].spurChan = word;
- }
- }
-
- if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
- ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
- sum, ah->eep_ops->get_eeprom_ver(ah));
- return -EINVAL;
- }
-
- return 0;
-#undef EEPROM_4K_SIZE
-}
-
-static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
- enum eeprom_param param)
-{
- struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
- struct modal_eep_4k_header *pModal = &eep->modalHeader;
- struct base_eep_header_4k *pBase = &eep->baseEepHeader;
-
- switch (param) {
- case EEP_NFTHRESH_2:
- return pModal->noiseFloorThreshCh[0];
- case AR_EEPROM_MAC(0):
- return pBase->macAddr[0] << 8 | pBase->macAddr[1];
- case AR_EEPROM_MAC(1):
- return pBase->macAddr[2] << 8 | pBase->macAddr[3];
- case AR_EEPROM_MAC(2):
- return pBase->macAddr[4] << 8 | pBase->macAddr[5];
- case EEP_REG_0:
- return pBase->regDmn[0];
- case EEP_REG_1:
- return pBase->regDmn[1];
- case EEP_OP_CAP:
- return pBase->deviceCap;
- case EEP_OP_MODE:
- return pBase->opCapFlags;
- case EEP_RF_SILENT:
- return pBase->rfSilent;
- case EEP_OB_2:
- return pModal->ob_01;
- case EEP_DB_2:
- return pModal->db1_01;
- case EEP_MINOR_REV:
- return pBase->version & AR5416_EEP_VER_MINOR_MASK;
- case EEP_TX_MASK:
- return pBase->txMask;
- case EEP_RX_MASK:
- return pBase->rxMask;
- case EEP_FRAC_N_5G:
- return 0;
- default:
- return 0;
- }
-}
-
-static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah,
- struct ath9k_channel *chan,
- struct cal_data_per_freq_4k *pRawDataSet,
- u8 *bChans, u16 availPiers,
- u16 tPdGainOverlap, int16_t *pMinCalPower,
- u16 *pPdGainBoundaries, u8 *pPDADCValues,
- u16 numXpdGains)
-{
-#define TMP_VAL_VPD_TABLE \
- ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep));
- int i, j, k;
- int16_t ss;
- u16 idxL = 0, idxR = 0, numPiers;
- static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
- static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
- static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-
- u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
- u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS];
- u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS];
- int16_t vpdStep;
- int16_t tmpVal;
- u16 sizeCurrVpdTable, maxIndex, tgtIndex;
- bool match;
- int16_t minDelta = 0;
- struct chan_centers centers;
-#define PD_GAIN_BOUNDARY_DEFAULT 58;
-
- ath9k_hw_get_channel_centers(ah, chan, &centers);
-
- for (numPiers = 0; numPiers < availPiers; numPiers++) {
- if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
- break;
- }
-
- match = ath9k_hw_get_lower_upper_index(
- (u8)FREQ2FBIN(centers.synth_center,
- IS_CHAN_2GHZ(chan)), bChans, numPiers,
- &idxL, &idxR);
-
- if (match) {
- for (i = 0; i < numXpdGains; i++) {
- minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
- maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pRawDataSet[idxL].pwrPdg[i],
- pRawDataSet[idxL].vpdPdg[i],
- AR5416_EEP4K_PD_GAIN_ICEPTS,
- vpdTableI[i]);
- }
- } else {
- for (i = 0; i < numXpdGains; i++) {
- pVpdL = pRawDataSet[idxL].vpdPdg[i];
- pPwrL = pRawDataSet[idxL].pwrPdg[i];
- pVpdR = pRawDataSet[idxR].vpdPdg[i];
- pPwrR = pRawDataSet[idxR].pwrPdg[i];
-
- minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
-
- maxPwrT4[i] =
- min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1],
- pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]);
-
-
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrL, pVpdL,
- AR5416_EEP4K_PD_GAIN_ICEPTS,
- vpdTableL[i]);
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrR, pVpdR,
- AR5416_EEP4K_PD_GAIN_ICEPTS,
- vpdTableR[i]);
-
- for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
- vpdTableI[i][j] =
- (u8)(ath9k_hw_interpolate((u16)
- FREQ2FBIN(centers.
- synth_center,
- IS_CHAN_2GHZ
- (chan)),
- bChans[idxL], bChans[idxR],
- vpdTableL[i][j], vpdTableR[i][j]));
- }
- }
- }
-
- *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
-
- k = 0;
-
- for (i = 0; i < numXpdGains; i++) {
- if (i == (numXpdGains - 1))
- pPdGainBoundaries[i] =
- (u16)(maxPwrT4[i] / 2);
- else
- pPdGainBoundaries[i] =
- (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
-
- pPdGainBoundaries[i] =
- min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
-
- if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
- minDelta = pPdGainBoundaries[0] - 23;
- pPdGainBoundaries[0] = 23;
- } else {
- minDelta = 0;
- }
-
- if (i == 0) {
- if (AR_SREV_9280_10_OR_LATER(ah))
- ss = (int16_t)(0 - (minPwrT4[i] / 2));
- else
- ss = 0;
- } else {
- ss = (int16_t)((pPdGainBoundaries[i - 1] -
- (minPwrT4[i] / 2)) -
- tPdGainOverlap + 1 + minDelta);
- }
- vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
- vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
-
- while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
- tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
- pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
- ss++;
- }
-
- sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
- tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
- (minPwrT4[i] / 2));
- maxIndex = (tgtIndex < sizeCurrVpdTable) ?
- tgtIndex : sizeCurrVpdTable;
-
- while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1)))
- pPDADCValues[k++] = vpdTableI[i][ss++];
-
- vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
- vpdTableI[i][sizeCurrVpdTable - 2]);
- vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
-
- if (tgtIndex >= maxIndex) {
- while ((ss <= tgtIndex) &&
- (k < (AR5416_NUM_PDADC_VALUES - 1))) {
- tmpVal = (int16_t) TMP_VAL_VPD_TABLE;
- pPDADCValues[k++] = (u8)((tmpVal > 255) ?
- 255 : tmpVal);
- ss++;
- }
- }
- }
-
- while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) {
- pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT;
- i++;
- }
-
- while (k < AR5416_NUM_PDADC_VALUES) {
- pPDADCValues[k] = pPDADCValues[k - 1];
- k++;
- }
-
- return;
-#undef TMP_VAL_VPD_TABLE
-}
-
-static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
- struct ath9k_channel *chan,
- int16_t *pTxPowerIndexOffset)
-{
- struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
- struct cal_data_per_freq_4k *pRawDataset;
- u8 *pCalBChans = NULL;
- u16 pdGainOverlap_t2;
- static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
- u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK];
- u16 numPiers, i, j;
- int16_t tMinCalPower;
- u16 numXpdGain, xpdMask;
- u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 };
- u32 reg32, regOffset, regChainOffset;
-
- xpdMask = pEepData->modalHeader.xpdGain;
-
- if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
- AR5416_EEP_MINOR_VER_2) {
- pdGainOverlap_t2 =
- pEepData->modalHeader.pdGainOverlap;
- } else {
- pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
- AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
- }
-
- pCalBChans = pEepData->calFreqPier2G;
- numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS;
-
- numXpdGain = 0;
-
- for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) {
- if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) {
- if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS)
- break;
- xpdGainValues[numXpdGain] =
- (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i);
- numXpdGain++;
- }
- }
-
- REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
- (numXpdGain - 1) & 0x3);
- REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
- xpdGainValues[0]);
- REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
- xpdGainValues[1]);
- REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0);
-
- for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
- if (AR_SREV_5416_20_OR_LATER(ah) &&
- (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
- (i != 0)) {
- regChainOffset = (i == 1) ? 0x2000 : 0x1000;
- } else
- regChainOffset = i * 0x1000;
-
- if (pEepData->baseEepHeader.txMask & (1 << i)) {
- pRawDataset = pEepData->calPierData2G[i];
-
- ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan,
- pRawDataset, pCalBChans,
- numPiers, pdGainOverlap_t2,
- &tMinCalPower, gainBoundaries,
- pdadcValues, numXpdGain);
-
- if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
- REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
- SM(pdGainOverlap_t2,
- AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
- | SM(gainBoundaries[0],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
- | SM(gainBoundaries[1],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
- | SM(gainBoundaries[2],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
- | SM(gainBoundaries[3],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
- }
-
- regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
- for (j = 0; j < 32; j++) {
- reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
- ((pdadcValues[4 * j + 1] & 0xFF) << 8) |
- ((pdadcValues[4 * j + 2] & 0xFF) << 16)|
- ((pdadcValues[4 * j + 3] & 0xFF) << 24);
- REG_WRITE(ah, regOffset, reg32);
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC (%d,%4x): %4.4x %8.8x\n",
- i, regChainOffset, regOffset,
- reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC: Chain %d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d |\n",
- i, 4 * j, pdadcValues[4 * j],
- 4 * j + 1, pdadcValues[4 * j + 1],
- 4 * j + 2, pdadcValues[4 * j + 2],
- 4 * j + 3,
- pdadcValues[4 * j + 3]);
-
- regOffset += 4;
- }
- }
- }
-
- *pTxPowerIndexOffset = 0;
-}
-
-static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
- struct ath9k_channel *chan,
- int16_t *ratesArray,
- u16 cfgCtl,
- u16 AntennaReduction,
- u16 twiceMaxRegulatoryPower,
- u16 powerLimit)
-{
- struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
- u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
- static const u16 tpScaleReductionTable[5] =
- { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
-
- int i;
- int16_t twiceLargestAntenna;
- struct cal_ctl_data_4k *rep;
- struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
- 0, { 0, 0, 0, 0}
- };
- struct cal_target_power_leg targetPowerOfdmExt = {
- 0, { 0, 0, 0, 0} }, targetPowerCckExt = {
- 0, { 0, 0, 0, 0 }
- };
- struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
- 0, {0, 0, 0, 0}
- };
- u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
- u16 ctlModesFor11g[] =
- { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
- CTL_2GHT40
- };
- u16 numCtlModes, *pCtlMode, ctlMode, freq;
- struct chan_centers centers;
- int tx_chainmask;
- u16 twiceMinEdgePower;
-
- tx_chainmask = ah->txchainmask;
-
- ath9k_hw_get_channel_centers(ah, chan, &centers);
-
- twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0];
-
- twiceLargestAntenna = (int16_t)min(AntennaReduction -
- twiceLargestAntenna, 0);
-
- maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
-
- if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) {
- maxRegAllowedPower -=
- (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2);
- }
-
- scaledPower = min(powerLimit, maxRegAllowedPower);
- scaledPower = max((u16)0, scaledPower);
-
- numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
- pCtlMode = ctlModesFor11g;
-
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->calTargetPowerCck,
- AR5416_NUM_2G_CCK_TARGET_POWERS,
- &targetPowerCck, 4, false);
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->calTargetPower2G,
- AR5416_NUM_2G_20_TARGET_POWERS,
- &targetPowerOfdm, 4, false);
- ath9k_hw_get_target_powers(ah, chan,
- pEepData->calTargetPower2GHT20,
- AR5416_NUM_2G_20_TARGET_POWERS,
- &targetPowerHt20, 8, false);
-
- if (IS_CHAN_HT40(chan)) {
- numCtlModes = ARRAY_SIZE(ctlModesFor11g);
- ath9k_hw_get_target_powers(ah, chan,
- pEepData->calTargetPower2GHT40,
- AR5416_NUM_2G_40_TARGET_POWERS,
- &targetPowerHt40, 8, true);
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->calTargetPowerCck,
- AR5416_NUM_2G_CCK_TARGET_POWERS,
- &targetPowerCckExt, 4, true);
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->calTargetPower2G,
- AR5416_NUM_2G_20_TARGET_POWERS,
- &targetPowerOfdmExt, 4, true);
- }
-
- for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
- bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
- (pCtlMode[ctlMode] == CTL_2GHT40);
- if (isHt40CtlMode)
- freq = centers.synth_center;
- else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
- freq = centers.ext_center;
- else
- freq = centers.ctl_center;
-
- if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
- ah->eep_ops->get_eeprom_rev(ah) <= 2)
- twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
- "EXT_ADDITIVE %d\n",
- ctlMode, numCtlModes, isHt40CtlMode,
- (pCtlMode[ctlMode] & EXT_ADDITIVE));
-
- for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) &&
- pEepData->ctlIndex[i]; i++) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- " LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
- "pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
- "chan %d\n",
- i, cfgCtl, pCtlMode[ctlMode],
- pEepData->ctlIndex[i], chan->channel);
-
- if ((((cfgCtl & ~CTL_MODE_M) |
- (pCtlMode[ctlMode] & CTL_MODE_M)) ==
- pEepData->ctlIndex[i]) ||
- (((cfgCtl & ~CTL_MODE_M) |
- (pCtlMode[ctlMode] & CTL_MODE_M)) ==
- ((pEepData->ctlIndex[i] & CTL_MODE_M) |
- SD_NO_CTL))) {
- rep = &(pEepData->ctlData[i]);
-
- twiceMinEdgePower =
- ath9k_hw_get_max_edge_power(freq,
- rep->ctlEdges[ar5416_get_ntxchains
- (tx_chainmask) - 1],
- IS_CHAN_2GHZ(chan),
- AR5416_EEP4K_NUM_BAND_EDGES);
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- " MATCH-EE_IDX %d: ch %d is2 %d "
- "2xMinEdge %d chainmask %d chains %d\n",
- i, freq, IS_CHAN_2GHZ(chan),
- twiceMinEdgePower, tx_chainmask,
- ar5416_get_ntxchains
- (tx_chainmask));
- if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
- twiceMaxEdgePower =
- min(twiceMaxEdgePower,
- twiceMinEdgePower);
- } else {
- twiceMaxEdgePower = twiceMinEdgePower;
- break;
- }
- }
- }
-
- minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- " SEL-Min ctlMode %d pCtlMode %d "
- "2xMaxEdge %d sP %d minCtlPwr %d\n",
- ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
- scaledPower, minCtlPower);
-
- switch (pCtlMode[ctlMode]) {
- case CTL_11B:
- for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x);
- i++) {
- targetPowerCck.tPow2x[i] =
- min((u16)targetPowerCck.tPow2x[i],
- minCtlPower);
- }
- break;
- case CTL_11G:
- for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x);
- i++) {
- targetPowerOfdm.tPow2x[i] =
- min((u16)targetPowerOfdm.tPow2x[i],
- minCtlPower);
- }
- break;
- case CTL_2GHT20:
- for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x);
- i++) {
- targetPowerHt20.tPow2x[i] =
- min((u16)targetPowerHt20.tPow2x[i],
- minCtlPower);
- }
- break;
- case CTL_11B_EXT:
- targetPowerCckExt.tPow2x[0] = min((u16)
- targetPowerCckExt.tPow2x[0],
- minCtlPower);
- break;
- case CTL_11G_EXT:
- targetPowerOfdmExt.tPow2x[0] = min((u16)
- targetPowerOfdmExt.tPow2x[0],
- minCtlPower);
- break;
- case CTL_2GHT40:
- for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x);
- i++) {
- targetPowerHt40.tPow2x[i] =
- min((u16)targetPowerHt40.tPow2x[i],
- minCtlPower);
- }
- break;
- default:
- break;
- }
- }
-
- ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
- ratesArray[rate18mb] = ratesArray[rate24mb] =
- targetPowerOfdm.tPow2x[0];
- ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
- ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
- ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
- ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
-
- for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
- ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
-
- ratesArray[rate1l] = targetPowerCck.tPow2x[0];
- ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1];
- ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2];
- ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3];
-
- if (IS_CHAN_HT40(chan)) {
- for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
- ratesArray[rateHt40_0 + i] =
- targetPowerHt40.tPow2x[i];
- }
- ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
- ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
- ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
- ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
- }
-}
-
-static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
- struct ath9k_channel *chan,
- u16 cfgCtl,
- u8 twiceAntennaReduction,
- u8 twiceMaxRegulatoryPower,
- u8 powerLimit)
-{
- struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
- struct modal_eep_4k_header *pModal = &pEepData->modalHeader;
- int16_t ratesArray[Ar5416RateSize];
- int16_t txPowerIndexOffset = 0;
- u8 ht40PowerIncForPdadc = 2;
- int i;
-
- memset(ratesArray, 0, sizeof(ratesArray));
-
- if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
- AR5416_EEP_MINOR_VER_2) {
- ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
- }
-
- ath9k_hw_set_4k_power_per_rate_table(ah, chan,
- &ratesArray[0], cfgCtl,
- twiceAntennaReduction,
- twiceMaxRegulatoryPower,
- powerLimit);
-
- ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset);
-
- for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
- ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
- if (ratesArray[i] > AR5416_MAX_RATE_POWER)
- ratesArray[i] = AR5416_MAX_RATE_POWER;
- }
-
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- for (i = 0; i < Ar5416RateSize; i++)
- ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
- }
-
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
- ATH9K_POW_SM(ratesArray[rate18mb], 24)
- | ATH9K_POW_SM(ratesArray[rate12mb], 16)
- | ATH9K_POW_SM(ratesArray[rate9mb], 8)
- | ATH9K_POW_SM(ratesArray[rate6mb], 0));
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
- ATH9K_POW_SM(ratesArray[rate54mb], 24)
- | ATH9K_POW_SM(ratesArray[rate48mb], 16)
- | ATH9K_POW_SM(ratesArray[rate36mb], 8)
- | ATH9K_POW_SM(ratesArray[rate24mb], 0));
-
- if (IS_CHAN_2GHZ(chan)) {
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
- ATH9K_POW_SM(ratesArray[rate2s], 24)
- | ATH9K_POW_SM(ratesArray[rate2l], 16)
- | ATH9K_POW_SM(ratesArray[rateXr], 8)
- | ATH9K_POW_SM(ratesArray[rate1l], 0));
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
- ATH9K_POW_SM(ratesArray[rate11s], 24)
- | ATH9K_POW_SM(ratesArray[rate11l], 16)
- | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
- | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
- }
-
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
- ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
- | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
- | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
- | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
- ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
- | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
- | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
- | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
-
- if (IS_CHAN_HT40(chan)) {
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
- ATH9K_POW_SM(ratesArray[rateHt40_3] +
- ht40PowerIncForPdadc, 24)
- | ATH9K_POW_SM(ratesArray[rateHt40_2] +
- ht40PowerIncForPdadc, 16)
- | ATH9K_POW_SM(ratesArray[rateHt40_1] +
- ht40PowerIncForPdadc, 8)
- | ATH9K_POW_SM(ratesArray[rateHt40_0] +
- ht40PowerIncForPdadc, 0));
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
- ATH9K_POW_SM(ratesArray[rateHt40_7] +
- ht40PowerIncForPdadc, 24)
- | ATH9K_POW_SM(ratesArray[rateHt40_6] +
- ht40PowerIncForPdadc, 16)
- | ATH9K_POW_SM(ratesArray[rateHt40_5] +
- ht40PowerIncForPdadc, 8)
- | ATH9K_POW_SM(ratesArray[rateHt40_4] +
- ht40PowerIncForPdadc, 0));
-
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
- ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
- | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
- | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
- | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
- }
-
- i = rate6mb;
-
- if (IS_CHAN_HT40(chan))
- i = rateHt40_0;
- else if (IS_CHAN_HT20(chan))
- i = rateHt20_0;
-
- if (AR_SREV_9280_10_OR_LATER(ah))
- ah->regulatory.max_power_level =
- ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
- else
- ah->regulatory.max_power_level = ratesArray[i];
-
-}
-
-static void ath9k_hw_4k_set_addac(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- struct modal_eep_4k_header *pModal;
- struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
- u8 biaslevel;
-
- if (ah->hw_version.macVersion != AR_SREV_VERSION_9160)
- return;
-
- if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7)
- return;
-
- pModal = &eep->modalHeader;
-
- if (pModal->xpaBiasLvl != 0xff) {
- biaslevel = pModal->xpaBiasLvl;
- INI_RA(&ah->iniAddac, 7, 1) =
- (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3;
- }
-}
-
-static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
- struct modal_eep_4k_header *pModal,
- struct ar5416_eeprom_4k *eep,
- u8 txRxAttenLocal, int regChainOffset)
-{
- REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
- pModal->antCtrlChain[0]);
-
- REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
- (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) &
- ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
- AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
- SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
- SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
-
- if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
- AR5416_EEP_MINOR_VER_3) {
- txRxAttenLocal = pModal->txRxAttenCh[0];
-
- REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
- AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]);
- REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
- AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
- REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
- AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
- pModal->xatten2Margin[0]);
- REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
- AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]);
- }
-
- REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
- AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
- REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
- AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
-
- if (AR_SREV_9285_11(ah))
- REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
-}
-
-static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- struct modal_eep_4k_header *pModal;
- struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
- u8 txRxAttenLocal;
- u8 ob[5], db1[5], db2[5];
- u8 ant_div_control1, ant_div_control2;
- u32 regVal;
-
- pModal = &eep->modalHeader;
- txRxAttenLocal = 23;
-
- REG_WRITE(ah, AR_PHY_SWITCH_COM,
- ah->eep_ops->get_eeprom_antenna_cfg(ah, chan));
-
- /* Single chain for 4K EEPROM*/
- ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0);
-
- /* Initialize Ant Diversity settings from EEPROM */
- if (pModal->version == 3) {
- ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf);
- ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf);
- regVal = REG_READ(ah, 0x99ac);
- regVal &= (~(0x7f000000));
- regVal |= ((ant_div_control1 & 0x1) << 24);
- regVal |= (((ant_div_control1 >> 1) & 0x1) << 29);
- regVal |= (((ant_div_control1 >> 2) & 0x1) << 30);
- regVal |= ((ant_div_control2 & 0x3) << 25);
- regVal |= (((ant_div_control2 >> 2) & 0x3) << 27);
- REG_WRITE(ah, 0x99ac, regVal);
- regVal = REG_READ(ah, 0x99ac);
- regVal = REG_READ(ah, 0xa208);
- regVal &= (~(0x1 << 13));
- regVal |= (((ant_div_control1 >> 3) & 0x1) << 13);
- REG_WRITE(ah, 0xa208, regVal);
- regVal = REG_READ(ah, 0xa208);
- }
-
- if (pModal->version >= 2) {
- ob[0] = (pModal->ob_01 & 0xf);
- ob[1] = (pModal->ob_01 >> 4) & 0xf;
- ob[2] = (pModal->ob_234 & 0xf);
- ob[3] = ((pModal->ob_234 >> 4) & 0xf);
- ob[4] = ((pModal->ob_234 >> 8) & 0xf);
-
- db1[0] = (pModal->db1_01 & 0xf);
- db1[1] = ((pModal->db1_01 >> 4) & 0xf);
- db1[2] = (pModal->db1_234 & 0xf);
- db1[3] = ((pModal->db1_234 >> 4) & 0xf);
- db1[4] = ((pModal->db1_234 >> 8) & 0xf);
-
- db2[0] = (pModal->db2_01 & 0xf);
- db2[1] = ((pModal->db2_01 >> 4) & 0xf);
- db2[2] = (pModal->db2_234 & 0xf);
- db2[3] = ((pModal->db2_234 >> 4) & 0xf);
- db2[4] = ((pModal->db2_234 >> 8) & 0xf);
-
- } else if (pModal->version == 1) {
- ob[0] = (pModal->ob_01 & 0xf);
- ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf;
- db1[0] = (pModal->db1_01 & 0xf);
- db1[1] = db1[2] = db1[3] =
- db1[4] = ((pModal->db1_01 >> 4) & 0xf);
- db2[0] = (pModal->db2_01 & 0xf);
- db2[1] = db2[2] = db2[3] =
- db2[4] = ((pModal->db2_01 >> 4) & 0xf);
- } else {
- int i;
- for (i = 0; i < 5; i++) {
- ob[i] = pModal->ob_01;
- db1[i] = pModal->db1_01;
- db2[i] = pModal->db1_01;
- }
- }
-
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]);
-
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]);
-
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]);
-
-
- if (AR_SREV_9285_11(ah))
- REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
-
- REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
- pModal->switchSettling);
- REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
- pModal->adcDesiredSize);
-
- REG_WRITE(ah, AR_PHY_RF_CTL4,
- SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) |
- SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) |
- SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) |
- SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
-
- REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
- pModal->txEndToRxOn);
- REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
- pModal->thresh62);
- REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62,
- pModal->thresh62);
-
- if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
- AR5416_EEP_MINOR_VER_2) {
- REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START,
- pModal->txFrameToDataStart);
- REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
- pModal->txFrameToPaOn);
- }
-
- if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
- AR5416_EEP_MINOR_VER_3) {
- if (IS_CHAN_HT40(chan))
- REG_RMW_FIELD(ah, AR_PHY_SETTLING,
- AR_PHY_SETTLING_SWITCH,
- pModal->swSettleHt40);
- }
-}
-
-static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
- struct modal_eep_4k_header *pModal = &eep->modalHeader;
-
- return pModal->antCtrlCommon & 0xFFFF;
-}
-
-static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah,
- enum ieee80211_band freq_band)
-{
- return 1;
-}
-
-static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
-{
-#define EEP_MAP4K_SPURCHAN \
- (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan)
-
- u16 spur_val = AR_NO_SPUR;
-
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur idx %d is2Ghz. %d val %x\n",
- i, is2GHz, ah->config.spurchans[i][is2GHz]);
-
- switch (ah->config.spurmode) {
- case SPUR_DISABLE:
- break;
- case SPUR_ENABLE_IOCTL:
- spur_val = ah->config.spurchans[i][is2GHz];
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur val from new loc. %d\n", spur_val);
- break;
- case SPUR_ENABLE_EEPROM:
- spur_val = EEP_MAP4K_SPURCHAN;
- break;
- }
-
- return spur_val;
-
-#undef EEP_MAP4K_SPURCHAN
-}
-
-static struct eeprom_ops eep_4k_ops = {
- .check_eeprom = ath9k_hw_4k_check_eeprom,
- .get_eeprom = ath9k_hw_4k_get_eeprom,
- .fill_eeprom = ath9k_hw_4k_fill_eeprom,
- .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver,
- .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev,
- .get_num_ant_config = ath9k_hw_4k_get_num_ant_config,
- .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg,
- .set_board_values = ath9k_hw_4k_set_board_values,
- .set_addac = ath9k_hw_4k_set_addac,
- .set_txpower = ath9k_hw_4k_set_txpower,
- .get_spur_channel = ath9k_hw_4k_get_spur_channel
-};
-
-/************************************************/
-/* EEPROM Operations for non-4K (Default) cards */
-/************************************************/
-
-static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah)
-{
- return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF);
-}
-
-static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah)
-{
- return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF);
-}
-
-static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
-{
-#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16))
- u16 *eep_data = (u16 *)&ah->eeprom.def;
- int addr, ar5416_eep_start_loc = 0x100;
-
- for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) {
- if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
- eep_data)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Unable to read eeprom region\n");
- return false;
- }
- eep_data++;
- }
- return true;
-#undef SIZE_EEPROM_DEF
-}
-
-static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
-{
- struct ar5416_eeprom_def *eep =
- (struct ar5416_eeprom_def *) &ah->eeprom.def;
- u16 *eepdata, temp, magic, magic2;
- u32 sum = 0, el;
- bool need_swap = false;
- int i, addr, size;
-
- if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n");
- return false;
- }
-
- if (!ath9k_hw_use_flash(ah)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Read Magic = 0x%04X\n", magic);
-
- if (magic != AR5416_EEPROM_MAGIC) {
- magic2 = swab16(magic);
-
- if (magic2 == AR5416_EEPROM_MAGIC) {
- size = sizeof(struct ar5416_eeprom_def);
- need_swap = true;
- eepdata = (u16 *) (&ah->eeprom);
-
- for (addr = 0; addr < size / sizeof(u16); addr++) {
- temp = swab16(*eepdata);
- *eepdata = temp;
- eepdata++;
- }
- } else {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Invalid EEPROM Magic. "
- "Endianness mismatch.\n");
- return -EINVAL;
- }
- }
- }
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
- need_swap ? "True" : "False");
-
- if (need_swap)
- el = swab16(ah->eeprom.def.baseEepHeader.length);
- else
- el = ah->eeprom.def.baseEepHeader.length;
-
- if (el > sizeof(struct ar5416_eeprom_def))
- el = sizeof(struct ar5416_eeprom_def) / sizeof(u16);
- else
- el = el / sizeof(u16);
-
- eepdata = (u16 *)(&ah->eeprom);
-
- for (i = 0; i < el; i++)
- sum ^= *eepdata++;
-
- if (need_swap) {
- u32 integer, j;
- u16 word;
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "EEPROM Endianness is not native.. Changing.\n");
-
- word = swab16(eep->baseEepHeader.length);
- eep->baseEepHeader.length = word;
-
- word = swab16(eep->baseEepHeader.checksum);
- eep->baseEepHeader.checksum = word;
-
- word = swab16(eep->baseEepHeader.version);
- eep->baseEepHeader.version = word;
-
- word = swab16(eep->baseEepHeader.regDmn[0]);
- eep->baseEepHeader.regDmn[0] = word;
-
- word = swab16(eep->baseEepHeader.regDmn[1]);
- eep->baseEepHeader.regDmn[1] = word;
-
- word = swab16(eep->baseEepHeader.rfSilent);
- eep->baseEepHeader.rfSilent = word;
-
- word = swab16(eep->baseEepHeader.blueToothOptions);
- eep->baseEepHeader.blueToothOptions = word;
-
- word = swab16(eep->baseEepHeader.deviceCap);
- eep->baseEepHeader.deviceCap = word;
-
- for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
- struct modal_eep_header *pModal =
- &eep->modalHeader[j];
- integer = swab32(pModal->antCtrlCommon);
- pModal->antCtrlCommon = integer;
-
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
- integer = swab32(pModal->antCtrlChain[i]);
- pModal->antCtrlChain[i] = integer;
- }
-
- for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
- word = swab16(pModal->spurChans[i].spurChan);
- pModal->spurChans[i].spurChan = word;
- }
- }
- }
-
- if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
- ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
- sum, ah->eep_ops->get_eeprom_ver(ah));
- return -EINVAL;
- }
-
- return 0;
-}
-
-static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
- enum eeprom_param param)
-{
- struct ar5416_eeprom_def *eep = &ah->eeprom.def;
- struct modal_eep_header *pModal = eep->modalHeader;
- struct base_eep_header *pBase = &eep->baseEepHeader;
-
- switch (param) {
- case EEP_NFTHRESH_5:
- return pModal[0].noiseFloorThreshCh[0];
- case EEP_NFTHRESH_2:
- return pModal[1].noiseFloorThreshCh[0];
- case AR_EEPROM_MAC(0):
- return pBase->macAddr[0] << 8 | pBase->macAddr[1];
- case AR_EEPROM_MAC(1):
- return pBase->macAddr[2] << 8 | pBase->macAddr[3];
- case AR_EEPROM_MAC(2):
- return pBase->macAddr[4] << 8 | pBase->macAddr[5];
- case EEP_REG_0:
- return pBase->regDmn[0];
- case EEP_REG_1:
- return pBase->regDmn[1];
- case EEP_OP_CAP:
- return pBase->deviceCap;
- case EEP_OP_MODE:
- return pBase->opCapFlags;
- case EEP_RF_SILENT:
- return pBase->rfSilent;
- case EEP_OB_5:
- return pModal[0].ob;
- case EEP_DB_5:
- return pModal[0].db;
- case EEP_OB_2:
- return pModal[1].ob;
- case EEP_DB_2:
- return pModal[1].db;
- case EEP_MINOR_REV:
- return AR5416_VER_MASK;
- case EEP_TX_MASK:
- return pBase->txMask;
- case EEP_RX_MASK:
- return pBase->rxMask;
- case EEP_RXGAIN_TYPE:
- return pBase->rxGainType;
- case EEP_TXGAIN_TYPE:
- return pBase->txGainType;
- case EEP_OL_PWRCTRL:
- if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
- return pBase->openLoopPwrCntl ? true : false;
- else
- return false;
- case EEP_RC_CHAIN_MASK:
- if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
- return pBase->rcChainMask;
- else
- return 0;
- case EEP_DAC_HPWR_5G:
- if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20)
- return pBase->dacHiPwrMode_5G;
- else
- return 0;
- case EEP_FRAC_N_5G:
- if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22)
- return pBase->frac_n_5g;
- else
- return 0;
- default:
- return 0;
- }
-}
-
-static void ath9k_hw_def_set_gain(struct ath_hw *ah,
- struct modal_eep_header *pModal,
- struct ar5416_eeprom_def *eep,
- u8 txRxAttenLocal, int regChainOffset, int i)
-{
- if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) {
- txRxAttenLocal = pModal->txRxAttenCh[i];
-
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
- AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
- pModal->bswMargin[i]);
- REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
- AR_PHY_GAIN_2GHZ_XATTEN1_DB,
- pModal->bswAtten[i]);
- REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
- AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
- pModal->xatten2Margin[i]);
- REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
- AR_PHY_GAIN_2GHZ_XATTEN2_DB,
- pModal->xatten2Db[i]);
- } else {
- REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
- (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
- ~AR_PHY_GAIN_2GHZ_BSW_MARGIN)
- | SM(pModal-> bswMargin[i],
- AR_PHY_GAIN_2GHZ_BSW_MARGIN));
- REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
- (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
- ~AR_PHY_GAIN_2GHZ_BSW_ATTEN)
- | SM(pModal->bswAtten[i],
- AR_PHY_GAIN_2GHZ_BSW_ATTEN));
- }
- }
-
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- REG_RMW_FIELD(ah,
- AR_PHY_RXGAIN + regChainOffset,
- AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
- REG_RMW_FIELD(ah,
- AR_PHY_RXGAIN + regChainOffset,
- AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]);
- } else {
- REG_WRITE(ah,
- AR_PHY_RXGAIN + regChainOffset,
- (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) &
- ~AR_PHY_RXGAIN_TXRX_ATTEN)
- | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN));
- REG_WRITE(ah,
- AR_PHY_GAIN_2GHZ + regChainOffset,
- (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
- ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
- SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
- }
-}
-
-static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- struct modal_eep_header *pModal;
- struct ar5416_eeprom_def *eep = &ah->eeprom.def;
- int i, regChainOffset;
- u8 txRxAttenLocal;
-
- pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
- txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
-
- REG_WRITE(ah, AR_PHY_SWITCH_COM,
- ah->eep_ops->get_eeprom_antenna_cfg(ah, chan));
-
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
- if (AR_SREV_9280(ah)) {
- if (i >= 2)
- break;
- }
-
- if (AR_SREV_5416_20_OR_LATER(ah) &&
- (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0))
- regChainOffset = (i == 1) ? 0x2000 : 0x1000;
- else
- regChainOffset = i * 0x1000;
-
- REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
- pModal->antCtrlChain[i]);
-
- REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
- (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) &
- ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
- AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
- SM(pModal->iqCalICh[i],
- AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
- SM(pModal->iqCalQCh[i],
- AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
-
- if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah))
- ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal,
- regChainOffset, i);
- }
-
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- if (IS_CHAN_2GHZ(chan)) {
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
- AR_AN_RF2G1_CH0_OB,
- AR_AN_RF2G1_CH0_OB_S,
- pModal->ob);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
- AR_AN_RF2G1_CH0_DB,
- AR_AN_RF2G1_CH0_DB_S,
- pModal->db);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
- AR_AN_RF2G1_CH1_OB,
- AR_AN_RF2G1_CH1_OB_S,
- pModal->ob_ch1);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
- AR_AN_RF2G1_CH1_DB,
- AR_AN_RF2G1_CH1_DB_S,
- pModal->db_ch1);
- } else {
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
- AR_AN_RF5G1_CH0_OB5,
- AR_AN_RF5G1_CH0_OB5_S,
- pModal->ob);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
- AR_AN_RF5G1_CH0_DB5,
- AR_AN_RF5G1_CH0_DB5_S,
- pModal->db);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
- AR_AN_RF5G1_CH1_OB5,
- AR_AN_RF5G1_CH1_OB5_S,
- pModal->ob_ch1);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
- AR_AN_RF5G1_CH1_DB5,
- AR_AN_RF5G1_CH1_DB5_S,
- pModal->db_ch1);
- }
- ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
- AR_AN_TOP2_XPABIAS_LVL,
- AR_AN_TOP2_XPABIAS_LVL_S,
- pModal->xpaBiasLvl);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
- AR_AN_TOP2_LOCALBIAS,
- AR_AN_TOP2_LOCALBIAS_S,
- pModal->local_bias);
- REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
- pModal->force_xpaon);
- }
-
- REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
- pModal->switchSettling);
- REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
- pModal->adcDesiredSize);
-
- if (!AR_SREV_9280_10_OR_LATER(ah))
- REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
- AR_PHY_DESIRED_SZ_PGA,
- pModal->pgaDesiredSize);
-
- REG_WRITE(ah, AR_PHY_RF_CTL4,
- SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
- | SM(pModal->txEndToXpaOff,
- AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
- | SM(pModal->txFrameToXpaOn,
- AR_PHY_RF_CTL4_FRAME_XPAA_ON)
- | SM(pModal->txFrameToXpaOn,
- AR_PHY_RF_CTL4_FRAME_XPAB_ON));
-
- REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
- pModal->txEndToRxOn);
-
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
- pModal->thresh62);
- REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
- AR_PHY_EXT_CCA0_THRESH62,
- pModal->thresh62);
- } else {
- REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62,
- pModal->thresh62);
- REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
- AR_PHY_EXT_CCA_THRESH62,
- pModal->thresh62);
- }
-
- if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) {
- REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
- AR_PHY_TX_END_DATA_START,
- pModal->txFrameToDataStart);
- REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
- pModal->txFrameToPaOn);
- }
-
- if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) {
- if (IS_CHAN_HT40(chan))
- REG_RMW_FIELD(ah, AR_PHY_SETTLING,
- AR_PHY_SETTLING_SWITCH,
- pModal->swSettleHt40);
- }
-
- if (AR_SREV_9280_20_OR_LATER(ah) &&
- AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
- REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL,
- AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK,
- pModal->miscBits);
-
-
- if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) {
- if (IS_CHAN_2GHZ(chan))
- REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE,
- eep->baseEepHeader.dacLpMode);
- else if (eep->baseEepHeader.dacHiPwrMode_5G)
- REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0);
- else
- REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE,
- eep->baseEepHeader.dacLpMode);
-
- REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP,
- pModal->miscBits >> 2);
-
- REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9,
- AR_PHY_TX_DESIRED_SCALE_CCK,
- eep->baseEepHeader.desiredScaleCCK);
- }
-}
-
-static void ath9k_hw_def_set_addac(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
-#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt])
- struct modal_eep_header *pModal;
- struct ar5416_eeprom_def *eep = &ah->eeprom.def;
- u8 biaslevel;
-
- if (ah->hw_version.macVersion != AR_SREV_VERSION_9160)
- return;
-
- if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7)
- return;
-
- pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
-
- if (pModal->xpaBiasLvl != 0xff) {
- biaslevel = pModal->xpaBiasLvl;
- } else {
- u16 resetFreqBin, freqBin, freqCount = 0;
- struct chan_centers centers;
-
- ath9k_hw_get_channel_centers(ah, chan, &centers);
-
- resetFreqBin = FREQ2FBIN(centers.synth_center,
- IS_CHAN_2GHZ(chan));
- freqBin = XPA_LVL_FREQ(0) & 0xff;
- biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14);
-
- freqCount++;
-
- while (freqCount < 3) {
- if (XPA_LVL_FREQ(freqCount) == 0x0)
- break;
-
- freqBin = XPA_LVL_FREQ(freqCount) & 0xff;
- if (resetFreqBin >= freqBin)
- biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14);
- else
- break;
- freqCount++;
- }
- }
-
- if (IS_CHAN_2GHZ(chan)) {
- INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac,
- 7, 1) & (~0x18)) | biaslevel << 3;
- } else {
- INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac,
- 6, 1) & (~0xc0)) | biaslevel << 6;
- }
-#undef XPA_LVL_FREQ
-}
-
-static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
- struct ath9k_channel *chan,
- struct cal_data_per_freq *pRawDataSet,
- u8 *bChans, u16 availPiers,
- u16 tPdGainOverlap, int16_t *pMinCalPower,
- u16 *pPdGainBoundaries, u8 *pPDADCValues,
- u16 numXpdGains)
-{
- int i, j, k;
- int16_t ss;
- u16 idxL = 0, idxR = 0, numPiers;
- static u8 vpdTableL[AR5416_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
- static u8 vpdTableR[AR5416_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
- static u8 vpdTableI[AR5416_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-
- u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
- u8 minPwrT4[AR5416_NUM_PD_GAINS];
- u8 maxPwrT4[AR5416_NUM_PD_GAINS];
- int16_t vpdStep;
- int16_t tmpVal;
- u16 sizeCurrVpdTable, maxIndex, tgtIndex;
- bool match;
- int16_t minDelta = 0;
- struct chan_centers centers;
-
- ath9k_hw_get_channel_centers(ah, chan, &centers);
-
- for (numPiers = 0; numPiers < availPiers; numPiers++) {
- if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
- break;
- }
-
- match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
- IS_CHAN_2GHZ(chan)),
- bChans, numPiers, &idxL, &idxR);
-
- if (match) {
- for (i = 0; i < numXpdGains; i++) {
- minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
- maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pRawDataSet[idxL].pwrPdg[i],
- pRawDataSet[idxL].vpdPdg[i],
- AR5416_PD_GAIN_ICEPTS,
- vpdTableI[i]);
- }
- } else {
- for (i = 0; i < numXpdGains; i++) {
- pVpdL = pRawDataSet[idxL].vpdPdg[i];
- pPwrL = pRawDataSet[idxL].pwrPdg[i];
- pVpdR = pRawDataSet[idxR].vpdPdg[i];
- pPwrR = pRawDataSet[idxR].pwrPdg[i];
-
- minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
-
- maxPwrT4[i] =
- min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1],
- pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
-
-
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrL, pVpdL,
- AR5416_PD_GAIN_ICEPTS,
- vpdTableL[i]);
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrR, pVpdR,
- AR5416_PD_GAIN_ICEPTS,
- vpdTableR[i]);
-
- for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
- vpdTableI[i][j] =
- (u8)(ath9k_hw_interpolate((u16)
- FREQ2FBIN(centers.
- synth_center,
- IS_CHAN_2GHZ
- (chan)),
- bChans[idxL], bChans[idxR],
- vpdTableL[i][j], vpdTableR[i][j]));
- }
- }
- }
-
- *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
-
- k = 0;
-
- for (i = 0; i < numXpdGains; i++) {
- if (i == (numXpdGains - 1))
- pPdGainBoundaries[i] =
- (u16)(maxPwrT4[i] / 2);
- else
- pPdGainBoundaries[i] =
- (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
-
- pPdGainBoundaries[i] =
- min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
-
- if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
- minDelta = pPdGainBoundaries[0] - 23;
- pPdGainBoundaries[0] = 23;
- } else {
- minDelta = 0;
- }
-
- if (i == 0) {
- if (AR_SREV_9280_10_OR_LATER(ah))
- ss = (int16_t)(0 - (minPwrT4[i] / 2));
- else
- ss = 0;
- } else {
- ss = (int16_t)((pPdGainBoundaries[i - 1] -
- (minPwrT4[i] / 2)) -
- tPdGainOverlap + 1 + minDelta);
- }
- vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
- vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
-
- while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
- tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
- pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
- ss++;
- }
-
- sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
- tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
- (minPwrT4[i] / 2));
- maxIndex = (tgtIndex < sizeCurrVpdTable) ?
- tgtIndex : sizeCurrVpdTable;
-
- while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
- pPDADCValues[k++] = vpdTableI[i][ss++];
- }
-
- vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
- vpdTableI[i][sizeCurrVpdTable - 2]);
- vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
-
- if (tgtIndex > maxIndex) {
- while ((ss <= tgtIndex) &&
- (k < (AR5416_NUM_PDADC_VALUES - 1))) {
- tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
- (ss - maxIndex + 1) * vpdStep));
- pPDADCValues[k++] = (u8)((tmpVal > 255) ?
- 255 : tmpVal);
- ss++;
- }
- }
- }
-
- while (i < AR5416_PD_GAINS_IN_MASK) {
- pPdGainBoundaries[i] = pPdGainBoundaries[i - 1];
- i++;
- }
-
- while (k < AR5416_NUM_PDADC_VALUES) {
- pPDADCValues[k] = pPDADCValues[k - 1];
- k++;
- }
-
- return;
-}
-
-static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
- struct ath9k_channel *chan,
- int16_t *pTxPowerIndexOffset)
-{
-#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x)
-#define SM_PDGAIN_B(x, y) \
- SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y)
-
- struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
- struct cal_data_per_freq *pRawDataset;
- u8 *pCalBChans = NULL;
- u16 pdGainOverlap_t2;
- static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
- u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
- u16 numPiers, i, j;
- int16_t tMinCalPower;
- u16 numXpdGain, xpdMask;
- u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
- u32 reg32, regOffset, regChainOffset;
- int16_t modalIdx;
-
- modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
- xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
-
- if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
- AR5416_EEP_MINOR_VER_2) {
- pdGainOverlap_t2 =
- pEepData->modalHeader[modalIdx].pdGainOverlap;
- } else {
- pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
- AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
- }
-
- if (IS_CHAN_2GHZ(chan)) {
- pCalBChans = pEepData->calFreqPier2G;
- numPiers = AR5416_NUM_2G_CAL_PIERS;
- } else {
- pCalBChans = pEepData->calFreqPier5G;
- numPiers = AR5416_NUM_5G_CAL_PIERS;
- }
-
- if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) {
- pRawDataset = pEepData->calPierData2G[0];
- ah->initPDADC = ((struct calDataPerFreqOpLoop *)
- pRawDataset)->vpdPdg[0][0];
- }
-
- numXpdGain = 0;
-
- for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
- if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
- if (numXpdGain >= AR5416_NUM_PD_GAINS)
- break;
- xpdGainValues[numXpdGain] =
- (u16)(AR5416_PD_GAINS_IN_MASK - i);
- numXpdGain++;
- }
- }
-
- REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
- (numXpdGain - 1) & 0x3);
- REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
- xpdGainValues[0]);
- REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
- xpdGainValues[1]);
- REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
- xpdGainValues[2]);
-
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
- if (AR_SREV_5416_20_OR_LATER(ah) &&
- (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
- (i != 0)) {
- regChainOffset = (i == 1) ? 0x2000 : 0x1000;
- } else
- regChainOffset = i * 0x1000;
-
- if (pEepData->baseEepHeader.txMask & (1 << i)) {
- if (IS_CHAN_2GHZ(chan))
- pRawDataset = pEepData->calPierData2G[i];
- else
- pRawDataset = pEepData->calPierData5G[i];
-
-
- if (OLC_FOR_AR9280_20_LATER) {
- u8 pcdacIdx;
- u8 txPower;
-
- ath9k_get_txgain_index(ah, chan,
- (struct calDataPerFreqOpLoop *)pRawDataset,
- pCalBChans, numPiers, &txPower, &pcdacIdx);
- ath9k_olc_get_pdadcs(ah, pcdacIdx,
- txPower/2, pdadcValues);
- } else {
- ath9k_hw_get_def_gain_boundaries_pdadcs(ah,
- chan, pRawDataset,
- pCalBChans, numPiers,
- pdGainOverlap_t2,
- &tMinCalPower,
- gainBoundaries,
- pdadcValues,
- numXpdGain);
- }
-
- if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
- if (OLC_FOR_AR9280_20_LATER) {
- REG_WRITE(ah,
- AR_PHY_TPCRG5 + regChainOffset,
- SM(0x6,
- AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
- SM_PD_GAIN(1) | SM_PD_GAIN(2) |
- SM_PD_GAIN(3) | SM_PD_GAIN(4));
- } else {
- REG_WRITE(ah,
- AR_PHY_TPCRG5 + regChainOffset,
- SM(pdGainOverlap_t2,
- AR_PHY_TPCRG5_PD_GAIN_OVERLAP)|
- SM_PDGAIN_B(0, 1) |
- SM_PDGAIN_B(1, 2) |
- SM_PDGAIN_B(2, 3) |
- SM_PDGAIN_B(3, 4));
- }
- }
-
- regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
- for (j = 0; j < 32; j++) {
- reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
- ((pdadcValues[4 * j + 1] & 0xFF) << 8) |
- ((pdadcValues[4 * j + 2] & 0xFF) << 16)|
- ((pdadcValues[4 * j + 3] & 0xFF) << 24);
- REG_WRITE(ah, regOffset, reg32);
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC (%d,%4x): %4.4x %8.8x\n",
- i, regChainOffset, regOffset,
- reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC: Chain %d | PDADC %3d "
- "Value %3d | PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | PDADC %3d "
- "Value %3d |\n",
- i, 4 * j, pdadcValues[4 * j],
- 4 * j + 1, pdadcValues[4 * j + 1],
- 4 * j + 2, pdadcValues[4 * j + 2],
- 4 * j + 3,
- pdadcValues[4 * j + 3]);
-
- regOffset += 4;
- }
- }
- }
-
- *pTxPowerIndexOffset = 0;
-#undef SM_PD_GAIN
-#undef SM_PDGAIN_B
-}
-
-static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
- struct ath9k_channel *chan,
- int16_t *ratesArray,
- u16 cfgCtl,
- u16 AntennaReduction,
- u16 twiceMaxRegulatoryPower,
- u16 powerLimit)
-{
-#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */
-#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */
-
- struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
- u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
- static const u16 tpScaleReductionTable[5] =
- { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
-
- int i;
- int16_t twiceLargestAntenna;
- struct cal_ctl_data *rep;
- struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
- 0, { 0, 0, 0, 0}
- };
- struct cal_target_power_leg targetPowerOfdmExt = {
- 0, { 0, 0, 0, 0} }, targetPowerCckExt = {
- 0, { 0, 0, 0, 0 }
- };
- struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
- 0, {0, 0, 0, 0}
- };
- u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
- u16 ctlModesFor11a[] =
- { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
- u16 ctlModesFor11g[] =
- { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
- CTL_2GHT40
- };
- u16 numCtlModes, *pCtlMode, ctlMode, freq;
- struct chan_centers centers;
- int tx_chainmask;
- u16 twiceMinEdgePower;
-
- tx_chainmask = ah->txchainmask;
-
- ath9k_hw_get_channel_centers(ah, chan, &centers);
-
- twiceLargestAntenna = max(
- pEepData->modalHeader
- [IS_CHAN_2GHZ(chan)].antennaGainCh[0],
- pEepData->modalHeader
- [IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
-
- twiceLargestAntenna = max((u8)twiceLargestAntenna,
- pEepData->modalHeader
- [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
-
- twiceLargestAntenna = (int16_t)min(AntennaReduction -
- twiceLargestAntenna, 0);
-
- maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
-
- if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) {
- maxRegAllowedPower -=
- (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2);
- }
-
- scaledPower = min(powerLimit, maxRegAllowedPower);
-
- switch (ar5416_get_ntxchains(tx_chainmask)) {
- case 1:
- break;
- case 2:
- scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
- break;
- case 3:
- scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
- break;
- }
-
- scaledPower = max((u16)0, scaledPower);
-
- if (IS_CHAN_2GHZ(chan)) {
- numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
- SUB_NUM_CTL_MODES_AT_2G_40;
- pCtlMode = ctlModesFor11g;
-
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->calTargetPowerCck,
- AR5416_NUM_2G_CCK_TARGET_POWERS,
- &targetPowerCck, 4, false);
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->calTargetPower2G,
- AR5416_NUM_2G_20_TARGET_POWERS,
- &targetPowerOfdm, 4, false);
- ath9k_hw_get_target_powers(ah, chan,
- pEepData->calTargetPower2GHT20,
- AR5416_NUM_2G_20_TARGET_POWERS,
- &targetPowerHt20, 8, false);
-
- if (IS_CHAN_HT40(chan)) {
- numCtlModes = ARRAY_SIZE(ctlModesFor11g);
- ath9k_hw_get_target_powers(ah, chan,
- pEepData->calTargetPower2GHT40,
- AR5416_NUM_2G_40_TARGET_POWERS,
- &targetPowerHt40, 8, true);
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->calTargetPowerCck,
- AR5416_NUM_2G_CCK_TARGET_POWERS,
- &targetPowerCckExt, 4, true);
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->calTargetPower2G,
- AR5416_NUM_2G_20_TARGET_POWERS,
- &targetPowerOfdmExt, 4, true);
- }
- } else {
- numCtlModes = ARRAY_SIZE(ctlModesFor11a) -
- SUB_NUM_CTL_MODES_AT_5G_40;
- pCtlMode = ctlModesFor11a;
-
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->calTargetPower5G,
- AR5416_NUM_5G_20_TARGET_POWERS,
- &targetPowerOfdm, 4, false);
- ath9k_hw_get_target_powers(ah, chan,
- pEepData->calTargetPower5GHT20,
- AR5416_NUM_5G_20_TARGET_POWERS,
- &targetPowerHt20, 8, false);
-
- if (IS_CHAN_HT40(chan)) {
- numCtlModes = ARRAY_SIZE(ctlModesFor11a);
- ath9k_hw_get_target_powers(ah, chan,
- pEepData->calTargetPower5GHT40,
- AR5416_NUM_5G_40_TARGET_POWERS,
- &targetPowerHt40, 8, true);
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->calTargetPower5G,
- AR5416_NUM_5G_20_TARGET_POWERS,
- &targetPowerOfdmExt, 4, true);
- }
- }
-
- for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
- bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
- (pCtlMode[ctlMode] == CTL_2GHT40);
- if (isHt40CtlMode)
- freq = centers.synth_center;
- else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
- freq = centers.ext_center;
- else
- freq = centers.ctl_center;
-
- if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
- ah->eep_ops->get_eeprom_rev(ah) <= 2)
- twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
- "EXT_ADDITIVE %d\n",
- ctlMode, numCtlModes, isHt40CtlMode,
- (pCtlMode[ctlMode] & EXT_ADDITIVE));
-
- for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- " LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
- "pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
- "chan %d\n",
- i, cfgCtl, pCtlMode[ctlMode],
- pEepData->ctlIndex[i], chan->channel);
-
- if ((((cfgCtl & ~CTL_MODE_M) |
- (pCtlMode[ctlMode] & CTL_MODE_M)) ==
- pEepData->ctlIndex[i]) ||
- (((cfgCtl & ~CTL_MODE_M) |
- (pCtlMode[ctlMode] & CTL_MODE_M)) ==
- ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
- rep = &(pEepData->ctlData[i]);
-
- twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
- rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1],
- IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES);
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- " MATCH-EE_IDX %d: ch %d is2 %d "
- "2xMinEdge %d chainmask %d chains %d\n",
- i, freq, IS_CHAN_2GHZ(chan),
- twiceMinEdgePower, tx_chainmask,
- ar5416_get_ntxchains
- (tx_chainmask));
- if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
- twiceMaxEdgePower = min(twiceMaxEdgePower,
- twiceMinEdgePower);
- } else {
- twiceMaxEdgePower = twiceMinEdgePower;
- break;
- }
- }
- }
-
- minCtlPower = min(twiceMaxEdgePower, scaledPower);
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- " SEL-Min ctlMode %d pCtlMode %d "
- "2xMaxEdge %d sP %d minCtlPwr %d\n",
- ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
- scaledPower, minCtlPower);
-
- switch (pCtlMode[ctlMode]) {
- case CTL_11B:
- for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
- targetPowerCck.tPow2x[i] =
- min((u16)targetPowerCck.tPow2x[i],
- minCtlPower);
- }
- break;
- case CTL_11A:
- case CTL_11G:
- for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
- targetPowerOfdm.tPow2x[i] =
- min((u16)targetPowerOfdm.tPow2x[i],
- minCtlPower);
- }
- break;
- case CTL_5GHT20:
- case CTL_2GHT20:
- for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
- targetPowerHt20.tPow2x[i] =
- min((u16)targetPowerHt20.tPow2x[i],
- minCtlPower);
- }
- break;
- case CTL_11B_EXT:
- targetPowerCckExt.tPow2x[0] = min((u16)
- targetPowerCckExt.tPow2x[0],
- minCtlPower);
- break;
- case CTL_11A_EXT:
- case CTL_11G_EXT:
- targetPowerOfdmExt.tPow2x[0] = min((u16)
- targetPowerOfdmExt.tPow2x[0],
- minCtlPower);
- break;
- case CTL_5GHT40:
- case CTL_2GHT40:
- for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
- targetPowerHt40.tPow2x[i] =
- min((u16)targetPowerHt40.tPow2x[i],
- minCtlPower);
- }
- break;
- default:
- break;
- }
- }
-
- ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
- ratesArray[rate18mb] = ratesArray[rate24mb] =
- targetPowerOfdm.tPow2x[0];
- ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
- ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
- ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
- ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
-
- for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
- ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
-
- if (IS_CHAN_2GHZ(chan)) {
- ratesArray[rate1l] = targetPowerCck.tPow2x[0];
- ratesArray[rate2s] = ratesArray[rate2l] =
- targetPowerCck.tPow2x[1];
- ratesArray[rate5_5s] = ratesArray[rate5_5l] =
- targetPowerCck.tPow2x[2];
- ;
- ratesArray[rate11s] = ratesArray[rate11l] =
- targetPowerCck.tPow2x[3];
- ;
- }
- if (IS_CHAN_HT40(chan)) {
- for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
- ratesArray[rateHt40_0 + i] =
- targetPowerHt40.tPow2x[i];
- }
- ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
- ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
- ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
- if (IS_CHAN_2GHZ(chan)) {
- ratesArray[rateExtCck] =
- targetPowerCckExt.tPow2x[0];
- }
- }
-}
-
-static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
- struct ath9k_channel *chan,
- u16 cfgCtl,
- u8 twiceAntennaReduction,
- u8 twiceMaxRegulatoryPower,
- u8 powerLimit)
-{
-#define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta)
- struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
- struct modal_eep_header *pModal =
- &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
- int16_t ratesArray[Ar5416RateSize];
- int16_t txPowerIndexOffset = 0;
- u8 ht40PowerIncForPdadc = 2;
- int i, cck_ofdm_delta = 0;
-
- memset(ratesArray, 0, sizeof(ratesArray));
-
- if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
- AR5416_EEP_MINOR_VER_2) {
- ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
- }
-
- ath9k_hw_set_def_power_per_rate_table(ah, chan,
- &ratesArray[0], cfgCtl,
- twiceAntennaReduction,
- twiceMaxRegulatoryPower,
- powerLimit);
-
- ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset);
-
- for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
- ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
- if (ratesArray[i] > AR5416_MAX_RATE_POWER)
- ratesArray[i] = AR5416_MAX_RATE_POWER;
- }
-
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- for (i = 0; i < Ar5416RateSize; i++)
- ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
- }
-
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
- ATH9K_POW_SM(ratesArray[rate18mb], 24)
- | ATH9K_POW_SM(ratesArray[rate12mb], 16)
- | ATH9K_POW_SM(ratesArray[rate9mb], 8)
- | ATH9K_POW_SM(ratesArray[rate6mb], 0));
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
- ATH9K_POW_SM(ratesArray[rate54mb], 24)
- | ATH9K_POW_SM(ratesArray[rate48mb], 16)
- | ATH9K_POW_SM(ratesArray[rate36mb], 8)
- | ATH9K_POW_SM(ratesArray[rate24mb], 0));
-
- if (IS_CHAN_2GHZ(chan)) {
- if (OLC_FOR_AR9280_20_LATER) {
- cck_ofdm_delta = 2;
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
- ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24)
- | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16)
- | ATH9K_POW_SM(ratesArray[rateXr], 8)
- | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0));
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
- ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24)
- | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16)
- | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8)
- | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0));
- } else {
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
- ATH9K_POW_SM(ratesArray[rate2s], 24)
- | ATH9K_POW_SM(ratesArray[rate2l], 16)
- | ATH9K_POW_SM(ratesArray[rateXr], 8)
- | ATH9K_POW_SM(ratesArray[rate1l], 0));
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
- ATH9K_POW_SM(ratesArray[rate11s], 24)
- | ATH9K_POW_SM(ratesArray[rate11l], 16)
- | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
- | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
- }
- }
-
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
- ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
- | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
- | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
- | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
- ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
- | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
- | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
- | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
-
- if (IS_CHAN_HT40(chan)) {
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
- ATH9K_POW_SM(ratesArray[rateHt40_3] +
- ht40PowerIncForPdadc, 24)
- | ATH9K_POW_SM(ratesArray[rateHt40_2] +
- ht40PowerIncForPdadc, 16)
- | ATH9K_POW_SM(ratesArray[rateHt40_1] +
- ht40PowerIncForPdadc, 8)
- | ATH9K_POW_SM(ratesArray[rateHt40_0] +
- ht40PowerIncForPdadc, 0));
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
- ATH9K_POW_SM(ratesArray[rateHt40_7] +
- ht40PowerIncForPdadc, 24)
- | ATH9K_POW_SM(ratesArray[rateHt40_6] +
- ht40PowerIncForPdadc, 16)
- | ATH9K_POW_SM(ratesArray[rateHt40_5] +
- ht40PowerIncForPdadc, 8)
- | ATH9K_POW_SM(ratesArray[rateHt40_4] +
- ht40PowerIncForPdadc, 0));
- if (OLC_FOR_AR9280_20_LATER) {
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
- ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
- | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16)
- | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
- | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0));
- } else {
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
- ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
- | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
- | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
- | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
- }
- }
-
- REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
- ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
- | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
-
- i = rate6mb;
-
- if (IS_CHAN_HT40(chan))
- i = rateHt40_0;
- else if (IS_CHAN_HT20(chan))
- i = rateHt20_0;
-
- if (AR_SREV_9280_10_OR_LATER(ah))
- ah->regulatory.max_power_level =
- ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
- else
- ah->regulatory.max_power_level = ratesArray[i];
-
- switch(ar5416_get_ntxchains(ah->txchainmask)) {
- case 1:
- break;
- case 2:
- ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
- break;
- case 3:
- ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
- break;
- default:
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Invalid chainmask configuration\n");
- break;
- }
-}
-
-static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah,
- enum ieee80211_band freq_band)
-{
- struct ar5416_eeprom_def *eep = &ah->eeprom.def;
- struct modal_eep_header *pModal =
- &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]);
- struct base_eep_header *pBase = &eep->baseEepHeader;
- u8 num_ant_config;
-
- num_ant_config = 1;
-
- if (pBase->version >= 0x0E0D)
- if (pModal->useAnt1)
- num_ant_config += 1;
-
- return num_ant_config;
-}
-
-static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- struct ar5416_eeprom_def *eep = &ah->eeprom.def;
- struct modal_eep_header *pModal =
- &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
-
- return pModal->antCtrlCommon & 0xFFFF;
-}
-
-static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
-{
-#define EEP_DEF_SPURCHAN \
- (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan)
-
- u16 spur_val = AR_NO_SPUR;
-
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur idx %d is2Ghz. %d val %x\n",
- i, is2GHz, ah->config.spurchans[i][is2GHz]);
-
- switch (ah->config.spurmode) {
- case SPUR_DISABLE:
- break;
- case SPUR_ENABLE_IOCTL:
- spur_val = ah->config.spurchans[i][is2GHz];
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur val from new loc. %d\n", spur_val);
- break;
- case SPUR_ENABLE_EEPROM:
- spur_val = EEP_DEF_SPURCHAN;
- break;
- }
-
- return spur_val;
-
-#undef EEP_DEF_SPURCHAN
-}
-
-static struct eeprom_ops eep_def_ops = {
- .check_eeprom = ath9k_hw_def_check_eeprom,
- .get_eeprom = ath9k_hw_def_get_eeprom,
- .fill_eeprom = ath9k_hw_def_fill_eeprom,
- .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver,
- .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev,
- .get_num_ant_config = ath9k_hw_def_get_num_ant_config,
- .get_eeprom_antenna_cfg = ath9k_hw_def_get_eeprom_antenna_cfg,
- .set_board_values = ath9k_hw_def_set_board_values,
- .set_addac = ath9k_hw_def_set_addac,
- .set_txpower = ath9k_hw_def_set_txpower,
- .get_spur_channel = ath9k_hw_def_get_spur_channel
-};
-
-int ath9k_hw_eeprom_attach(struct ath_hw *ah)
+int ath9k_hw_eeprom_init(struct ath_hw *ah)
{
int status;
- if (AR_SREV_9285(ah)) {
+ if (AR_SREV_9287(ah)) {
+ ah->eep_map = EEP_MAP_AR9287;
+ ah->eep_ops = &eep_AR9287_ops;
+ } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
ah->eep_map = EEP_MAP_4KBITS;
ah->eep_ops = &eep_4k_ops;
} else {
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 67b8bd12941a..4fe33f7eee9d 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -100,6 +100,8 @@
#define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK)
#define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \
ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+#define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_10_OR_LATER(ah) && \
+ ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c
#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2
@@ -176,6 +178,57 @@
#define AR9280_TX_GAIN_TABLE_SIZE 22
+#define AR9287_EEP_VER 0xE
+#define AR9287_EEP_VER_MINOR_MASK 0xFFF
+#define AR9287_EEP_MINOR_VER_1 0x1
+#define AR9287_EEP_MINOR_VER_2 0x2
+#define AR9287_EEP_MINOR_VER_3 0x3
+#define AR9287_EEP_MINOR_VER AR9287_EEP_MINOR_VER_3
+#define AR9287_EEP_MINOR_VER_b AR9287_EEP_MINOR_VER
+#define AR9287_EEP_NO_BACK_VER AR9287_EEP_MINOR_VER_1
+
+#define AR9287_EEP_START_LOC 128
+#define AR9287_NUM_2G_CAL_PIERS 3
+#define AR9287_NUM_2G_CCK_TARGET_POWERS 3
+#define AR9287_NUM_2G_20_TARGET_POWERS 3
+#define AR9287_NUM_2G_40_TARGET_POWERS 3
+#define AR9287_NUM_CTLS 12
+#define AR9287_NUM_BAND_EDGES 4
+#define AR9287_NUM_PD_GAINS 4
+#define AR9287_PD_GAINS_IN_MASK 4
+#define AR9287_PD_GAIN_ICEPTS 1
+#define AR9287_EEPROM_MODAL_SPURS 5
+#define AR9287_MAX_RATE_POWER 63
+#define AR9287_NUM_PDADC_VALUES 128
+#define AR9287_NUM_RATES 16
+#define AR9287_BCHAN_UNUSED 0xFF
+#define AR9287_MAX_PWR_RANGE_IN_HALF_DB 64
+#define AR9287_OPFLAGS_11A 0x01
+#define AR9287_OPFLAGS_11G 0x02
+#define AR9287_OPFLAGS_2G_HT40 0x08
+#define AR9287_OPFLAGS_2G_HT20 0x20
+#define AR9287_OPFLAGS_5G_HT40 0x04
+#define AR9287_OPFLAGS_5G_HT20 0x10
+#define AR9287_EEPMISC_BIG_ENDIAN 0x01
+#define AR9287_EEPMISC_WOW 0x02
+#define AR9287_MAX_CHAINS 2
+#define AR9287_ANT_16S 32
+#define AR9287_custdatasize 20
+
+#define AR9287_NUM_ANT_CHAIN_FIELDS 6
+#define AR9287_NUM_ANT_COMMON_FIELDS 4
+#define AR9287_SIZE_ANT_CHAIN_FIELD 2
+#define AR9287_SIZE_ANT_COMMON_FIELD 4
+#define AR9287_ANT_CHAIN_MASK 0x3
+#define AR9287_ANT_COMMON_MASK 0xf
+#define AR9287_CHAIN_0_IDX 0
+#define AR9287_CHAIN_1_IDX 1
+#define AR9287_DATA_SZ 32
+
+#define AR9287_PWR_TABLE_OFFSET_DB -5
+
+#define AR9287_CHECKSUM_LOCATION (AR9287_EEP_START_LOC + 1)
+
enum eeprom_param {
EEP_NFTHRESH_5,
EEP_NFTHRESH_2,
@@ -199,7 +252,11 @@ enum eeprom_param {
EEP_OL_PWRCTRL,
EEP_RC_CHAIN_MASK,
EEP_DAC_HPWR_5G,
- EEP_FRAC_N_5G
+ EEP_FRAC_N_5G,
+ EEP_DEV_TYPE,
+ EEP_TEMPSENSE_SLOPE,
+ EEP_TEMPSENSE_SLOPE_PAL_ON,
+ EEP_PWR_TABLE_OFFSET
};
enum ar5416_rates {
@@ -328,46 +385,123 @@ struct calDataPerFreqOpLoop {
} __packed;
struct modal_eep_4k_header {
- u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
- u32 antCtrlCommon;
- u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS];
- u8 switchSettling;
- u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS];
- u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS];
- u8 adcDesiredSize;
- u8 pgaDesiredSize;
- u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS];
- u8 txEndToXpaOff;
- u8 txEndToRxOn;
- u8 txFrameToXpaOn;
- u8 thresh62;
- u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS];
- u8 xpdGain;
- u8 xpd;
- u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS];
- u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS];
- u8 pdGainOverlap;
- u8 ob_01;
- u8 db1_01;
- u8 xpaBiasLvl;
- u8 txFrameToDataStart;
- u8 txFrameToPaOn;
- u8 ht40PowerIncForPdadc;
- u8 bswAtten[AR5416_EEP4K_MAX_CHAINS];
- u8 bswMargin[AR5416_EEP4K_MAX_CHAINS];
- u8 swSettleHt40;
- u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS];
- u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS];
- u8 db2_01;
- u8 version;
- u16 ob_234;
- u16 db1_234;
- u16 db2_234;
- u8 futureModal[4];
-
+ u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
+ u32 antCtrlCommon;
+ u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS];
+ u8 switchSettling;
+ u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS];
+ u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS];
+ u8 adcDesiredSize;
+ u8 pgaDesiredSize;
+ u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS];
+ u8 txEndToXpaOff;
+ u8 txEndToRxOn;
+ u8 txFrameToXpaOn;
+ u8 thresh62;
+ u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS];
+ u8 xpdGain;
+ u8 xpd;
+ u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS];
+ u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS];
+ u8 pdGainOverlap;
+#ifdef __BIG_ENDIAN_BITFIELD
+ u8 ob_1:4, ob_0:4;
+ u8 db1_1:4, db1_0:4;
+#else
+ u8 ob_0:4, ob_1:4;
+ u8 db1_0:4, db1_1:4;
+#endif
+ u8 xpaBiasLvl;
+ u8 txFrameToDataStart;
+ u8 txFrameToPaOn;
+ u8 ht40PowerIncForPdadc;
+ u8 bswAtten[AR5416_EEP4K_MAX_CHAINS];
+ u8 bswMargin[AR5416_EEP4K_MAX_CHAINS];
+ u8 swSettleHt40;
+ u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS];
+ u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS];
+#ifdef __BIG_ENDIAN_BITFIELD
+ u8 db2_1:4, db2_0:4;
+#else
+ u8 db2_0:4, db2_1:4;
+#endif
+ u8 version;
+#ifdef __BIG_ENDIAN_BITFIELD
+ u8 ob_3:4, ob_2:4;
+ u8 antdiv_ctl1:4, ob_4:4;
+ u8 db1_3:4, db1_2:4;
+ u8 antdiv_ctl2:4, db1_4:4;
+ u8 db2_2:4, db2_3:4;
+ u8 reserved:4, db2_4:4;
+#else
+ u8 ob_2:4, ob_3:4;
+ u8 ob_4:4, antdiv_ctl1:4;
+ u8 db1_2:4, db1_3:4;
+ u8 db1_4:4, antdiv_ctl2:4;
+ u8 db2_2:4, db2_3:4;
+ u8 db2_4:4, reserved:4;
+#endif
+ u8 futureModal[4];
struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
} __packed;
+struct base_eep_ar9287_header {
+ u16 length;
+ u16 checksum;
+ u16 version;
+ u8 opCapFlags;
+ u8 eepMisc;
+ u16 regDmn[2];
+ u8 macAddr[6];
+ u8 rxMask;
+ u8 txMask;
+ u16 rfSilent;
+ u16 blueToothOptions;
+ u16 deviceCap;
+ u32 binBuildNumber;
+ u8 deviceType;
+ u8 openLoopPwrCntl;
+ int8_t pwrTableOffset;
+ int8_t tempSensSlope;
+ int8_t tempSensSlopePalOn;
+ u8 futureBase[29];
+} __packed;
+
+struct modal_eep_ar9287_header {
+ u32 antCtrlChain[AR9287_MAX_CHAINS];
+ u32 antCtrlCommon;
+ int8_t antennaGainCh[AR9287_MAX_CHAINS];
+ u8 switchSettling;
+ u8 txRxAttenCh[AR9287_MAX_CHAINS];
+ u8 rxTxMarginCh[AR9287_MAX_CHAINS];
+ int8_t adcDesiredSize;
+ u8 txEndToXpaOff;
+ u8 txEndToRxOn;
+ u8 txFrameToXpaOn;
+ u8 thresh62;
+ int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS];
+ u8 xpdGain;
+ u8 xpd;
+ int8_t iqCalICh[AR9287_MAX_CHAINS];
+ int8_t iqCalQCh[AR9287_MAX_CHAINS];
+ u8 pdGainOverlap;
+ u8 xpaBiasLvl;
+ u8 txFrameToDataStart;
+ u8 txFrameToPaOn;
+ u8 ht40PowerIncForPdadc;
+ u8 bswAtten[AR9287_MAX_CHAINS];
+ u8 bswMargin[AR9287_MAX_CHAINS];
+ u8 swSettleHt40;
+ u8 version;
+ u8 db1;
+ u8 db2;
+ u8 ob_cck;
+ u8 ob_psk;
+ u8 ob_qam;
+ u8 ob_pal_off;
+ u8 futureModal[30];
+ struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS];
+} __packed;
struct cal_data_per_freq {
u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
@@ -402,6 +536,28 @@ struct cal_ctl_edges {
} __packed;
#endif
+struct cal_data_op_loop_ar9287 {
+ u8 pwrPdg[2][5];
+ u8 vpdPdg[2][5];
+ u8 pcdac[2][5];
+ u8 empty[2][5];
+} __packed;
+
+struct cal_data_per_freq_ar9287 {
+ u8 pwrPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
+ u8 vpdPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
+} __packed;
+
+union cal_data_per_freq_ar9287_u {
+ struct cal_data_op_loop_ar9287 calDataOpen;
+ struct cal_data_per_freq_ar9287 calDataClose;
+} __packed;
+
+struct cal_ctl_data_ar9287 {
+ struct cal_ctl_edges
+ ctlEdges[AR9287_MAX_CHAINS][AR9287_NUM_BAND_EDGES];
+} __packed;
+
struct cal_ctl_data {
struct cal_ctl_edges
ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
@@ -461,6 +617,26 @@ struct ar5416_eeprom_4k {
u8 padding;
} __packed;
+struct ar9287_eeprom {
+ struct base_eep_ar9287_header baseEepHeader;
+ u8 custData[AR9287_DATA_SZ];
+ struct modal_eep_ar9287_header modalHeader;
+ u8 calFreqPier2G[AR9287_NUM_2G_CAL_PIERS];
+ union cal_data_per_freq_ar9287_u
+ calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS];
+ struct cal_target_power_leg
+ calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS];
+ struct cal_target_power_leg
+ calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS];
+ struct cal_target_power_ht
+ calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS];
+ struct cal_target_power_ht
+ calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS];
+ u8 ctlIndex[AR9287_NUM_CTLS];
+ struct cal_ctl_data_ar9287 ctlData[AR9287_NUM_CTLS];
+ u8 padding;
+} __packed;
+
enum reg_ext_bitmap {
REG_EXT_JAPAN_MIDBAND = 1,
REG_EXT_FCC_DFS_HT40 = 2,
@@ -480,6 +656,7 @@ struct ath9k_country_entry {
enum ath9k_eep_map {
EEP_MAP_DEFAULT = 0x0,
EEP_MAP_4KBITS,
+ EEP_MAP_AR9287,
EEP_MAP_MAX
};
@@ -500,10 +677,39 @@ struct eeprom_ops {
u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
};
+void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
+ u32 shift, u32 val);
+int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
+ int16_t targetLeft,
+ int16_t targetRight);
+bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
+ u16 *indexL, u16 *indexR);
+bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data);
+void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
+ u8 *pVpdList, u16 numIntercepts,
+ u8 *pRetVpdList);
+void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ struct cal_target_power_leg *powInfo,
+ u16 numChannels,
+ struct cal_target_power_leg *pNewPower,
+ u16 numRates, bool isExtTarget);
+void ath9k_hw_get_target_powers(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ struct cal_target_power_ht *powInfo,
+ u16 numChannels,
+ struct cal_target_power_ht *pNewPower,
+ u16 numRates, bool isHt40Target);
+u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
+ bool is2GHz, int num_band_edges);
+int ath9k_hw_eeprom_init(struct ath_hw *ah);
+
#define ar5416_get_ntxchains(_txchainmask) \
(((_txchainmask >> 2) & 1) + \
((_txchainmask >> 1) & 1) + (_txchainmask & 1))
-int ath9k_hw_eeprom_attach(struct ath_hw *ah);
+extern const struct eeprom_ops eep_def_ops;
+extern const struct eeprom_ops eep_4k_ops;
+extern const struct eeprom_ops eep_AR9287_ops;
#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..b8eca7be5f3a
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -0,0 +1,1188 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+
+static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah)
+{
+ return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF);
+}
+
+static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah)
+{
+ return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF);
+}
+
+static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
+{
+#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
+ u16 *eep_data = (u16 *)&ah->eeprom.map4k;
+ int addr, eep_start_loc = 0;
+
+ eep_start_loc = 64;
+
+ if (!ath9k_hw_use_flash(ah)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Reading from EEPROM, not flash\n");
+ }
+
+ for (addr = 0; addr < SIZE_EEPROM_4K; addr++) {
+ if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Unable to read eeprom region \n");
+ return false;
+ }
+ eep_data++;
+ }
+
+ return true;
+#undef SIZE_EEPROM_4K
+}
+
+static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
+{
+#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
+ struct ar5416_eeprom_4k *eep =
+ (struct ar5416_eeprom_4k *) &ah->eeprom.map4k;
+ u16 *eepdata, temp, magic, magic2;
+ u32 sum = 0, el;
+ bool need_swap = false;
+ int i, addr;
+
+
+ if (!ath9k_hw_use_flash(ah)) {
+ if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
+ &magic)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Reading Magic # failed\n");
+ return false;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
+
+ if (magic != AR5416_EEPROM_MAGIC) {
+ magic2 = swab16(magic);
+
+ if (magic2 == AR5416_EEPROM_MAGIC) {
+ need_swap = true;
+ eepdata = (u16 *) (&ah->eeprom);
+
+ for (addr = 0; addr < EEPROM_4K_SIZE; addr++) {
+ temp = swab16(*eepdata);
+ *eepdata = temp;
+ eepdata++;
+ }
+ } else {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Invalid EEPROM Magic. "
+ "endianness mismatch.\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
+
+ if (need_swap)
+ el = swab16(ah->eeprom.map4k.baseEepHeader.length);
+ else
+ el = ah->eeprom.map4k.baseEepHeader.length;
+
+ if (el > sizeof(struct ar5416_eeprom_4k))
+ el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16);
+ else
+ el = el / sizeof(u16);
+
+ eepdata = (u16 *)(&ah->eeprom);
+
+ for (i = 0; i < el; i++)
+ sum ^= *eepdata++;
+
+ if (need_swap) {
+ u32 integer;
+ u16 word;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "EEPROM Endianness is not native.. Changing\n");
+
+ word = swab16(eep->baseEepHeader.length);
+ eep->baseEepHeader.length = word;
+
+ word = swab16(eep->baseEepHeader.checksum);
+ eep->baseEepHeader.checksum = word;
+
+ word = swab16(eep->baseEepHeader.version);
+ eep->baseEepHeader.version = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[0]);
+ eep->baseEepHeader.regDmn[0] = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[1]);
+ eep->baseEepHeader.regDmn[1] = word;
+
+ word = swab16(eep->baseEepHeader.rfSilent);
+ eep->baseEepHeader.rfSilent = word;
+
+ word = swab16(eep->baseEepHeader.blueToothOptions);
+ eep->baseEepHeader.blueToothOptions = word;
+
+ word = swab16(eep->baseEepHeader.deviceCap);
+ eep->baseEepHeader.deviceCap = word;
+
+ integer = swab32(eep->modalHeader.antCtrlCommon);
+ eep->modalHeader.antCtrlCommon = integer;
+
+ for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
+ integer = swab32(eep->modalHeader.antCtrlChain[i]);
+ eep->modalHeader.antCtrlChain[i] = integer;
+ }
+
+ for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
+ word = swab16(eep->modalHeader.spurChans[i].spurChan);
+ eep->modalHeader.spurChans[i].spurChan = word;
+ }
+ }
+
+ if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
+ ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ sum, ah->eep_ops->get_eeprom_ver(ah));
+ return -EINVAL;
+ }
+
+ return 0;
+#undef EEPROM_4K_SIZE
+}
+
+static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
+ enum eeprom_param param)
+{
+ struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+ struct modal_eep_4k_header *pModal = &eep->modalHeader;
+ struct base_eep_header_4k *pBase = &eep->baseEepHeader;
+
+ switch (param) {
+ case EEP_NFTHRESH_2:
+ return pModal->noiseFloorThreshCh[0];
+ case AR_EEPROM_MAC(0):
+ return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+ case AR_EEPROM_MAC(1):
+ return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+ case AR_EEPROM_MAC(2):
+ return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+ case EEP_REG_0:
+ return pBase->regDmn[0];
+ case EEP_REG_1:
+ return pBase->regDmn[1];
+ case EEP_OP_CAP:
+ return pBase->deviceCap;
+ case EEP_OP_MODE:
+ return pBase->opCapFlags;
+ case EEP_RF_SILENT:
+ return pBase->rfSilent;
+ case EEP_OB_2:
+ return pModal->ob_0;
+ case EEP_DB_2:
+ return pModal->db1_1;
+ case EEP_MINOR_REV:
+ return pBase->version & AR5416_EEP_VER_MINOR_MASK;
+ case EEP_TX_MASK:
+ return pBase->txMask;
+ case EEP_RX_MASK:
+ return pBase->rxMask;
+ case EEP_FRAC_N_5G:
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ struct cal_data_per_freq_4k *pRawDataSet,
+ u8 *bChans, u16 availPiers,
+ u16 tPdGainOverlap, int16_t *pMinCalPower,
+ u16 *pPdGainBoundaries, u8 *pPDADCValues,
+ u16 numXpdGains)
+{
+#define TMP_VAL_VPD_TABLE \
+ ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep));
+ int i, j, k;
+ int16_t ss;
+ u16 idxL = 0, idxR = 0, numPiers;
+ static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+
+ u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+ u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS];
+ u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS];
+ int16_t vpdStep;
+ int16_t tmpVal;
+ u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+ bool match;
+ int16_t minDelta = 0;
+ struct chan_centers centers;
+#define PD_GAIN_BOUNDARY_DEFAULT 58;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ for (numPiers = 0; numPiers < availPiers; numPiers++) {
+ if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
+ break;
+ }
+
+ match = ath9k_hw_get_lower_upper_index(
+ (u8)FREQ2FBIN(centers.synth_center,
+ IS_CHAN_2GHZ(chan)), bChans, numPiers,
+ &idxL, &idxR);
+
+ if (match) {
+ for (i = 0; i < numXpdGains; i++) {
+ minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
+ maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pRawDataSet[idxL].pwrPdg[i],
+ pRawDataSet[idxL].vpdPdg[i],
+ AR5416_EEP4K_PD_GAIN_ICEPTS,
+ vpdTableI[i]);
+ }
+ } else {
+ for (i = 0; i < numXpdGains; i++) {
+ pVpdL = pRawDataSet[idxL].vpdPdg[i];
+ pPwrL = pRawDataSet[idxL].pwrPdg[i];
+ pVpdR = pRawDataSet[idxR].vpdPdg[i];
+ pPwrR = pRawDataSet[idxR].pwrPdg[i];
+
+ minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+ maxPwrT4[i] =
+ min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1],
+ pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]);
+
+
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrL, pVpdL,
+ AR5416_EEP4K_PD_GAIN_ICEPTS,
+ vpdTableL[i]);
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrR, pVpdR,
+ AR5416_EEP4K_PD_GAIN_ICEPTS,
+ vpdTableR[i]);
+
+ for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+ vpdTableI[i][j] =
+ (u8)(ath9k_hw_interpolate((u16)
+ FREQ2FBIN(centers.
+ synth_center,
+ IS_CHAN_2GHZ
+ (chan)),
+ bChans[idxL], bChans[idxR],
+ vpdTableL[i][j], vpdTableR[i][j]));
+ }
+ }
+ }
+
+ *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
+
+ k = 0;
+
+ for (i = 0; i < numXpdGains; i++) {
+ if (i == (numXpdGains - 1))
+ pPdGainBoundaries[i] =
+ (u16)(maxPwrT4[i] / 2);
+ else
+ pPdGainBoundaries[i] =
+ (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
+
+ pPdGainBoundaries[i] =
+ min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
+
+ if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
+ minDelta = pPdGainBoundaries[0] - 23;
+ pPdGainBoundaries[0] = 23;
+ } else {
+ minDelta = 0;
+ }
+
+ if (i == 0) {
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ss = (int16_t)(0 - (minPwrT4[i] / 2));
+ else
+ ss = 0;
+ } else {
+ ss = (int16_t)((pPdGainBoundaries[i - 1] -
+ (minPwrT4[i] / 2)) -
+ tPdGainOverlap + 1 + minDelta);
+ }
+ vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+ while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
+ pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
+ ss++;
+ }
+
+ sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+ tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
+ (minPwrT4[i] / 2));
+ maxIndex = (tgtIndex < sizeCurrVpdTable) ?
+ tgtIndex : sizeCurrVpdTable;
+
+ while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1)))
+ pPDADCValues[k++] = vpdTableI[i][ss++];
+
+ vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
+ vpdTableI[i][sizeCurrVpdTable - 2]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+ if (tgtIndex >= maxIndex) {
+ while ((ss <= tgtIndex) &&
+ (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t) TMP_VAL_VPD_TABLE;
+ pPDADCValues[k++] = (u8)((tmpVal > 255) ?
+ 255 : tmpVal);
+ ss++;
+ }
+ }
+ }
+
+ while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) {
+ pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT;
+ i++;
+ }
+
+ while (k < AR5416_NUM_PDADC_VALUES) {
+ pPDADCValues[k] = pPDADCValues[k - 1];
+ k++;
+ }
+
+ return;
+#undef TMP_VAL_VPD_TABLE
+}
+
+static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ int16_t *pTxPowerIndexOffset)
+{
+ struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
+ struct cal_data_per_freq_4k *pRawDataset;
+ u8 *pCalBChans = NULL;
+ u16 pdGainOverlap_t2;
+ static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+ u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK];
+ u16 numPiers, i, j;
+ int16_t tMinCalPower;
+ u16 numXpdGain, xpdMask;
+ u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 };
+ u32 reg32, regOffset, regChainOffset;
+
+ xpdMask = pEepData->modalHeader.xpdGain;
+
+ if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ pdGainOverlap_t2 =
+ pEepData->modalHeader.pdGainOverlap;
+ } else {
+ pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+ }
+
+ pCalBChans = pEepData->calFreqPier2G;
+ numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS;
+
+ numXpdGain = 0;
+
+ for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) {
+ if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) {
+ if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS)
+ break;
+ xpdGainValues[numXpdGain] =
+ (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i);
+ numXpdGain++;
+ }
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+ (numXpdGain - 1) & 0x3);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+ xpdGainValues[0]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+ xpdGainValues[1]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0);
+
+ for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
+ if (AR_SREV_5416_20_OR_LATER(ah) &&
+ (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
+ (i != 0)) {
+ regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+ } else
+ regChainOffset = i * 0x1000;
+
+ if (pEepData->baseEepHeader.txMask & (1 << i)) {
+ pRawDataset = pEepData->calPierData2G[i];
+
+ ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan,
+ pRawDataset, pCalBChans,
+ numPiers, pdGainOverlap_t2,
+ &tMinCalPower, gainBoundaries,
+ pdadcValues, numXpdGain);
+
+ if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
+ REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
+ SM(pdGainOverlap_t2,
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+ | SM(gainBoundaries[0],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+ | SM(gainBoundaries[1],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+ | SM(gainBoundaries[2],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+ | SM(gainBoundaries[3],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+ }
+
+ regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
+ for (j = 0; j < 32; j++) {
+ reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
+ ((pdadcValues[4 * j + 1] & 0xFF) << 8) |
+ ((pdadcValues[4 * j + 2] & 0xFF) << 16)|
+ ((pdadcValues[4 * j + 3] & 0xFF) << 24);
+ REG_WRITE(ah, regOffset, reg32);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "PDADC (%d,%4x): %4.4x %8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "PDADC: Chain %d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1, pdadcValues[4 * j + 1],
+ 4 * j + 2, pdadcValues[4 * j + 2],
+ 4 * j + 3,
+ pdadcValues[4 * j + 3]);
+
+ regOffset += 4;
+ }
+ }
+ }
+
+ *pTxPowerIndexOffset = 0;
+}
+
+static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ int16_t *ratesArray,
+ u16 cfgCtl,
+ u16 AntennaReduction,
+ u16 twiceMaxRegulatoryPower,
+ u16 powerLimit)
+{
+#define CMP_TEST_GRP \
+ (((cfgCtl & ~CTL_MODE_M)| (pCtlMode[ctlMode] & CTL_MODE_M)) == \
+ pEepData->ctlIndex[i]) \
+ || (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
+ ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
+
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ int i;
+ int16_t twiceLargestAntenna;
+ u16 twiceMinEdgePower;
+ u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+ u16 numCtlModes, *pCtlMode, ctlMode, freq;
+ struct chan_centers centers;
+ struct cal_ctl_data_4k *rep;
+ struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
+ static const u16 tpScaleReductionTable[5] =
+ { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+ struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+ 0, { 0, 0, 0, 0}
+ };
+ struct cal_target_power_leg targetPowerOfdmExt = {
+ 0, { 0, 0, 0, 0} }, targetPowerCckExt = {
+ 0, { 0, 0, 0, 0 }
+ };
+ struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
+ 0, {0, 0, 0, 0}
+ };
+ u16 ctlModesFor11g[] =
+ { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
+ CTL_2GHT40
+ };
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0];
+ twiceLargestAntenna = (int16_t)min(AntennaReduction -
+ twiceLargestAntenna, 0);
+
+ maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+ if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
+ maxRegAllowedPower -=
+ (tpScaleReductionTable[(regulatory->tp_scale)] * 2);
+ }
+
+ scaledPower = min(powerLimit, maxRegAllowedPower);
+ scaledPower = max((u16)0, scaledPower);
+
+ numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
+ pCtlMode = ctlModesFor11g;
+
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPowerCck,
+ AR5416_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCck, 4, false);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower2G,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdm, 4, false);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower2GHT20,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerHt20, 8, false);
+
+ if (IS_CHAN_HT40(chan)) {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower2GHT40,
+ AR5416_NUM_2G_40_TARGET_POWERS,
+ &targetPowerHt40, 8, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPowerCck,
+ AR5416_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCckExt, 4, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower2G,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdmExt, 4, true);
+ }
+
+ for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+ bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+ (pCtlMode[ctlMode] == CTL_2GHT40);
+
+ if (isHt40CtlMode)
+ freq = centers.synth_center;
+ else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+ freq = centers.ext_center;
+ else
+ freq = centers.ctl_center;
+
+ if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
+ ah->eep_ops->get_eeprom_rev(ah) <= 2)
+ twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+
+ for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) &&
+ pEepData->ctlIndex[i]; i++) {
+
+ if (CMP_TEST_GRP) {
+ rep = &(pEepData->ctlData[i]);
+
+ twiceMinEdgePower = ath9k_hw_get_max_edge_power(
+ freq,
+ rep->ctlEdges[
+ ar5416_get_ntxchains(ah->txchainmask) - 1],
+ IS_CHAN_2GHZ(chan),
+ AR5416_EEP4K_NUM_BAND_EDGES);
+
+ if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+ twiceMaxEdgePower =
+ min(twiceMaxEdgePower,
+ twiceMinEdgePower);
+ } else {
+ twiceMaxEdgePower = twiceMinEdgePower;
+ break;
+ }
+ }
+ }
+
+ minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
+
+ switch (pCtlMode[ctlMode]) {
+ case CTL_11B:
+ for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
+ targetPowerCck.tPow2x[i] =
+ min((u16)targetPowerCck.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11G:
+ for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
+ targetPowerOfdm.tPow2x[i] =
+ min((u16)targetPowerOfdm.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_2GHT20:
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
+ targetPowerHt20.tPow2x[i] =
+ min((u16)targetPowerHt20.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11B_EXT:
+ targetPowerCckExt.tPow2x[0] =
+ min((u16)targetPowerCckExt.tPow2x[0],
+ minCtlPower);
+ break;
+ case CTL_11G_EXT:
+ targetPowerOfdmExt.tPow2x[0] =
+ min((u16)targetPowerOfdmExt.tPow2x[0],
+ minCtlPower);
+ break;
+ case CTL_2GHT40:
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+ targetPowerHt40.tPow2x[i] =
+ min((u16)targetPowerHt40.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ ratesArray[rate6mb] =
+ ratesArray[rate9mb] =
+ ratesArray[rate12mb] =
+ ratesArray[rate18mb] =
+ ratesArray[rate24mb] =
+ targetPowerOfdm.tPow2x[0];
+
+ ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+ ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+ ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+ ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+ ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+ ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+ ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1];
+ ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2];
+ ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3];
+
+ if (IS_CHAN_HT40(chan)) {
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+ ratesArray[rateHt40_0 + i] =
+ targetPowerHt40.tPow2x[i];
+ }
+ ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+ ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
+ }
+
+#undef CMP_TEST_GRP
+}
+
+static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ u16 cfgCtl,
+ u8 twiceAntennaReduction,
+ u8 twiceMaxRegulatoryPower,
+ u8 powerLimit)
+{
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
+ struct modal_eep_4k_header *pModal = &pEepData->modalHeader;
+ int16_t ratesArray[Ar5416RateSize];
+ int16_t txPowerIndexOffset = 0;
+ u8 ht40PowerIncForPdadc = 2;
+ int i;
+
+ memset(ratesArray, 0, sizeof(ratesArray));
+
+ if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+ }
+
+ ath9k_hw_set_4k_power_per_rate_table(ah, chan,
+ &ratesArray[0], cfgCtl,
+ twiceAntennaReduction,
+ twiceMaxRegulatoryPower,
+ powerLimit);
+
+ ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset);
+
+ for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+ ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
+ if (ratesArray[i] > AR5416_MAX_RATE_POWER)
+ ratesArray[i] = AR5416_MAX_RATE_POWER;
+ }
+
+
+ /* Update regulatory */
+
+ i = rate6mb;
+ if (IS_CHAN_HT40(chan))
+ i = rateHt40_0;
+ else if (IS_CHAN_HT20(chan))
+ i = rateHt20_0;
+
+ regulatory->max_power_level = ratesArray[i];
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ for (i = 0; i < Ar5416RateSize; i++)
+ ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+ }
+
+ /* OFDM power per rate */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+ ATH9K_POW_SM(ratesArray[rate18mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate6mb], 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+ ATH9K_POW_SM(ratesArray[rate54mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate24mb], 0));
+
+ /* CCK power per rate */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+ ATH9K_POW_SM(ratesArray[rate2s], 24)
+ | ATH9K_POW_SM(ratesArray[rate2l], 16)
+ | ATH9K_POW_SM(ratesArray[rateXr], 8)
+ | ATH9K_POW_SM(ratesArray[rate1l], 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+ ATH9K_POW_SM(ratesArray[rate11s], 24)
+ | ATH9K_POW_SM(ratesArray[rate11l], 16)
+ | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+ | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+
+ /* HT20 power per rate */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+ ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+ ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+
+ /* HT40 power per rate */
+ if (IS_CHAN_HT40(chan)) {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+ ATH9K_POW_SM(ratesArray[rateHt40_3] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+ ht40PowerIncForPdadc, 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+ ATH9K_POW_SM(ratesArray[rateHt40_7] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+ ht40PowerIncForPdadc, 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+ ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+ | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+ | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+ | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+ }
+}
+
+static void ath9k_hw_4k_set_addac(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ struct modal_eep_4k_header *pModal;
+ struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+ u8 biaslevel;
+
+ if (ah->hw_version.macVersion != AR_SREV_VERSION_9160)
+ return;
+
+ if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7)
+ return;
+
+ pModal = &eep->modalHeader;
+
+ if (pModal->xpaBiasLvl != 0xff) {
+ biaslevel = pModal->xpaBiasLvl;
+ INI_RA(&ah->iniAddac, 7, 1) =
+ (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3;
+ }
+}
+
+static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
+ struct modal_eep_4k_header *pModal,
+ struct ar5416_eeprom_4k *eep,
+ u8 txRxAttenLocal)
+{
+ REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0,
+ pModal->antCtrlChain[0]);
+
+ REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0),
+ (REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
+ ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+ SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+ SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+ if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_3) {
+ txRxAttenLocal = pModal->txRxAttenCh[0];
+
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ,
+ AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ,
+ AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ,
+ AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+ pModal->xatten2Margin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ,
+ AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]);
+
+ /* Set the block 1 value to block 0 value */
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+ pModal->bswMargin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+ pModal->xatten2Margin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+ pModal->xatten2Db[0]);
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN,
+ AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+ AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+
+ if (AR_SREV_9285_11(ah))
+ REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
+}
+
+/*
+ * Read EEPROM header info and program the device for correct operation
+ * given the channel value.
+ */
+static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ struct modal_eep_4k_header *pModal;
+ struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+ u8 txRxAttenLocal;
+ u8 ob[5], db1[5], db2[5];
+ u8 ant_div_control1, ant_div_control2;
+ u32 regVal;
+
+ pModal = &eep->modalHeader;
+ txRxAttenLocal = 23;
+
+ REG_WRITE(ah, AR_PHY_SWITCH_COM,
+ ah->eep_ops->get_eeprom_antenna_cfg(ah, chan));
+
+ /* Single chain for 4K EEPROM*/
+ ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal);
+
+ /* Initialize Ant Diversity settings from EEPROM */
+ if (pModal->version >= 3) {
+ ant_div_control1 = pModal->antdiv_ctl1;
+ ant_div_control2 = pModal->antdiv_ctl2;
+
+ regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
+ regVal &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL));
+
+ regVal |= SM(ant_div_control1,
+ AR_PHY_9285_ANT_DIV_CTL);
+ regVal |= SM(ant_div_control2,
+ AR_PHY_9285_ANT_DIV_ALT_LNACONF);
+ regVal |= SM((ant_div_control2 >> 2),
+ AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
+ regVal |= SM((ant_div_control1 >> 1),
+ AR_PHY_9285_ANT_DIV_ALT_GAINTB);
+ regVal |= SM((ant_div_control1 >> 2),
+ AR_PHY_9285_ANT_DIV_MAIN_GAINTB);
+
+
+ REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal);
+ regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
+ regVal = REG_READ(ah, AR_PHY_CCK_DETECT);
+ regVal &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
+ regVal |= SM((ant_div_control1 >> 3),
+ AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
+
+ REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal);
+ regVal = REG_READ(ah, AR_PHY_CCK_DETECT);
+ }
+
+ if (pModal->version >= 2) {
+ ob[0] = pModal->ob_0;
+ ob[1] = pModal->ob_1;
+ ob[2] = pModal->ob_2;
+ ob[3] = pModal->ob_3;
+ ob[4] = pModal->ob_4;
+
+ db1[0] = pModal->db1_0;
+ db1[1] = pModal->db1_1;
+ db1[2] = pModal->db1_2;
+ db1[3] = pModal->db1_3;
+ db1[4] = pModal->db1_4;
+
+ db2[0] = pModal->db2_0;
+ db2[1] = pModal->db2_1;
+ db2[2] = pModal->db2_2;
+ db2[3] = pModal->db2_3;
+ db2[4] = pModal->db2_4;
+ } else if (pModal->version == 1) {
+ ob[0] = pModal->ob_0;
+ ob[1] = ob[2] = ob[3] = ob[4] = pModal->ob_1;
+ db1[0] = pModal->db1_0;
+ db1[1] = db1[2] = db1[3] = db1[4] = pModal->db1_1;
+ db2[0] = pModal->db2_0;
+ db2[1] = db2[2] = db2[3] = db2[4] = pModal->db2_1;
+ } else {
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ ob[i] = pModal->ob_0;
+ db1[i] = pModal->db1_0;
+ db2[i] = pModal->db1_0;
+ }
+ }
+
+ if (AR_SREV_9271(ah)) {
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9271_AN_RF2G3_OB_cck,
+ AR9271_AN_RF2G3_OB_cck_S,
+ ob[0]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9271_AN_RF2G3_OB_psk,
+ AR9271_AN_RF2G3_OB_psk_S,
+ ob[1]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9271_AN_RF2G3_OB_qam,
+ AR9271_AN_RF2G3_OB_qam_S,
+ ob[2]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9271_AN_RF2G3_DB_1,
+ AR9271_AN_RF2G3_DB_1_S,
+ db1[0]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9271_AN_RF2G4_DB_2,
+ AR9271_AN_RF2G4_DB_2_S,
+ db2[0]);
+ } else {
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_0,
+ AR9285_AN_RF2G3_OB_0_S,
+ ob[0]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_1,
+ AR9285_AN_RF2G3_OB_1_S,
+ ob[1]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_2,
+ AR9285_AN_RF2G3_OB_2_S,
+ ob[2]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_3,
+ AR9285_AN_RF2G3_OB_3_S,
+ ob[3]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_4,
+ AR9285_AN_RF2G3_OB_4_S,
+ ob[4]);
+
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_DB1_0,
+ AR9285_AN_RF2G3_DB1_0_S,
+ db1[0]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_DB1_1,
+ AR9285_AN_RF2G3_DB1_1_S,
+ db1[1]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_DB1_2,
+ AR9285_AN_RF2G3_DB1_2_S,
+ db1[2]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB1_3,
+ AR9285_AN_RF2G4_DB1_3_S,
+ db1[3]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB1_4,
+ AR9285_AN_RF2G4_DB1_4_S, db1[4]);
+
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_0,
+ AR9285_AN_RF2G4_DB2_0_S,
+ db2[0]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_1,
+ AR9285_AN_RF2G4_DB2_1_S,
+ db2[1]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_2,
+ AR9285_AN_RF2G4_DB2_2_S,
+ db2[2]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_3,
+ AR9285_AN_RF2G4_DB2_3_S,
+ db2[3]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_4,
+ AR9285_AN_RF2G4_DB2_4_S,
+ db2[4]);
+ }
+
+
+ if (AR_SREV_9285_11(ah))
+ REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
+
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
+ pModal->switchSettling);
+ REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
+ pModal->adcDesiredSize);
+
+ REG_WRITE(ah, AR_PHY_RF_CTL4,
+ SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) |
+ SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) |
+ SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) |
+ SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
+ pModal->txEndToRxOn);
+ REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
+ pModal->thresh62);
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62,
+ pModal->thresh62);
+
+ if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START,
+ pModal->txFrameToDataStart);
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
+ pModal->txFrameToPaOn);
+ }
+
+ if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_3) {
+ if (IS_CHAN_HT40(chan))
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+ AR_PHY_SETTLING_SWITCH,
+ pModal->swSettleHt40);
+ }
+}
+
+static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+ struct modal_eep_4k_header *pModal = &eep->modalHeader;
+
+ return pModal->antCtrlCommon & 0xFFFF;
+}
+
+static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah,
+ enum ieee80211_band freq_band)
+{
+ return 1;
+}
+
+static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
+{
+#define EEP_MAP4K_SPURCHAN \
+ (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan)
+
+ u16 spur_val = AR_NO_SPUR;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Getting spur idx %d is2Ghz. %d val %x\n",
+ i, is2GHz, ah->config.spurchans[i][is2GHz]);
+
+ switch (ah->config.spurmode) {
+ case SPUR_DISABLE:
+ break;
+ case SPUR_ENABLE_IOCTL:
+ spur_val = ah->config.spurchans[i][is2GHz];
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
+ break;
+ case SPUR_ENABLE_EEPROM:
+ spur_val = EEP_MAP4K_SPURCHAN;
+ break;
+ }
+
+ return spur_val;
+
+#undef EEP_MAP4K_SPURCHAN
+}
+
+const struct eeprom_ops eep_4k_ops = {
+ .check_eeprom = ath9k_hw_4k_check_eeprom,
+ .get_eeprom = ath9k_hw_4k_get_eeprom,
+ .fill_eeprom = ath9k_hw_4k_fill_eeprom,
+ .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver,
+ .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev,
+ .get_num_ant_config = ath9k_hw_4k_get_num_ant_config,
+ .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg,
+ .set_board_values = ath9k_hw_4k_set_board_values,
+ .set_addac = ath9k_hw_4k_set_addac,
+ .set_txpower = ath9k_hw_4k_set_txpower,
+ .get_spur_channel = ath9k_hw_4k_get_spur_channel
+};
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..c20c21a79b21
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -0,0 +1,1177 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+
+static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah)
+{
+ return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF;
+}
+
+static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah)
+{
+ return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF;
+}
+
+static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
+{
+ struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+ u16 *eep_data;
+ int addr, eep_start_loc = AR9287_EEP_START_LOC;
+ eep_data = (u16 *)eep;
+
+ if (!ath9k_hw_use_flash(ah)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Reading from EEPROM, not flash\n");
+ }
+
+ for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16);
+ addr++) {
+ if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Unable to read eeprom region \n");
+ return false;
+ }
+ eep_data++;
+ }
+ return true;
+}
+
+static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
+{
+ u32 sum = 0, el, integer;
+ u16 temp, word, magic, magic2, *eepdata;
+ int i, addr;
+ bool need_swap = false;
+ struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+
+ if (!ath9k_hw_use_flash(ah)) {
+ if (!ath9k_hw_nvram_read
+ (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Reading Magic # failed\n");
+ return false;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
+ if (magic != AR5416_EEPROM_MAGIC) {
+ magic2 = swab16(magic);
+
+ if (magic2 == AR5416_EEPROM_MAGIC) {
+ need_swap = true;
+ eepdata = (u16 *)(&ah->eeprom);
+
+ for (addr = 0;
+ addr < sizeof(struct ar9287_eeprom) / sizeof(u16);
+ addr++) {
+ temp = swab16(*eepdata);
+ *eepdata = temp;
+ eepdata++;
+ }
+ } else {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Invalid EEPROM Magic. "
+ "endianness mismatch.\n");
+ return -EINVAL;
+ }
+ }
+ }
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ?
+ "True" : "False");
+
+ if (need_swap)
+ el = swab16(ah->eeprom.map9287.baseEepHeader.length);
+ else
+ el = ah->eeprom.map9287.baseEepHeader.length;
+
+ if (el > sizeof(struct ar9287_eeprom))
+ el = sizeof(struct ar9287_eeprom) / sizeof(u16);
+ else
+ el = el / sizeof(u16);
+
+ eepdata = (u16 *)(&ah->eeprom);
+ for (i = 0; i < el; i++)
+ sum ^= *eepdata++;
+
+ if (need_swap) {
+ word = swab16(eep->baseEepHeader.length);
+ eep->baseEepHeader.length = word;
+
+ word = swab16(eep->baseEepHeader.checksum);
+ eep->baseEepHeader.checksum = word;
+
+ word = swab16(eep->baseEepHeader.version);
+ eep->baseEepHeader.version = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[0]);
+ eep->baseEepHeader.regDmn[0] = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[1]);
+ eep->baseEepHeader.regDmn[1] = word;
+
+ word = swab16(eep->baseEepHeader.rfSilent);
+ eep->baseEepHeader.rfSilent = word;
+
+ word = swab16(eep->baseEepHeader.blueToothOptions);
+ eep->baseEepHeader.blueToothOptions = word;
+
+ word = swab16(eep->baseEepHeader.deviceCap);
+ eep->baseEepHeader.deviceCap = word;
+
+ integer = swab32(eep->modalHeader.antCtrlCommon);
+ eep->modalHeader.antCtrlCommon = integer;
+
+ for (i = 0; i < AR9287_MAX_CHAINS; i++) {
+ integer = swab32(eep->modalHeader.antCtrlChain[i]);
+ eep->modalHeader.antCtrlChain[i] = integer;
+ }
+
+ for (i = 0; i < AR9287_EEPROM_MODAL_SPURS; i++) {
+ word = swab16(eep->modalHeader.spurChans[i].spurChan);
+ eep->modalHeader.spurChans[i].spurChan = word;
+ }
+ }
+
+ if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER
+ || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ sum, ah->eep_ops->get_eeprom_ver(ah));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah,
+ enum eeprom_param param)
+{
+ struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+ struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
+ struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
+ u16 ver_minor;
+
+ ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK;
+ switch (param) {
+ case EEP_NFTHRESH_2:
+ return pModal->noiseFloorThreshCh[0];
+ case AR_EEPROM_MAC(0):
+ return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+ case AR_EEPROM_MAC(1):
+ return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+ case AR_EEPROM_MAC(2):
+ return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+ case EEP_REG_0:
+ return pBase->regDmn[0];
+ case EEP_REG_1:
+ return pBase->regDmn[1];
+ case EEP_OP_CAP:
+ return pBase->deviceCap;
+ case EEP_OP_MODE:
+ return pBase->opCapFlags;
+ case EEP_RF_SILENT:
+ return pBase->rfSilent;
+ case EEP_MINOR_REV:
+ return ver_minor;
+ case EEP_TX_MASK:
+ return pBase->txMask;
+ case EEP_RX_MASK:
+ return pBase->rxMask;
+ case EEP_DEV_TYPE:
+ return pBase->deviceType;
+ case EEP_OL_PWRCTRL:
+ return pBase->openLoopPwrCntl;
+ case EEP_TEMPSENSE_SLOPE:
+ if (ver_minor >= AR9287_EEP_MINOR_VER_2)
+ return pBase->tempSensSlope;
+ else
+ return 0;
+ case EEP_TEMPSENSE_SLOPE_PAL_ON:
+ if (ver_minor >= AR9287_EEP_MINOR_VER_3)
+ return pBase->tempSensSlopePalOn;
+ else
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+
+static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ struct cal_data_per_freq_ar9287 *pRawDataSet,
+ u8 *bChans, u16 availPiers,
+ u16 tPdGainOverlap, int16_t *pMinCalPower,
+ u16 *pPdGainBoundaries, u8 *pPDADCValues,
+ u16 numXpdGains)
+{
+#define TMP_VAL_VPD_TABLE \
+ ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep));
+
+ int i, j, k;
+ int16_t ss;
+ u16 idxL = 0, idxR = 0, numPiers;
+ u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+ u8 minPwrT4[AR9287_NUM_PD_GAINS];
+ u8 maxPwrT4[AR9287_NUM_PD_GAINS];
+ int16_t vpdStep;
+ int16_t tmpVal;
+ u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+ bool match;
+ int16_t minDelta = 0;
+ struct chan_centers centers;
+ static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ for (numPiers = 0; numPiers < availPiers; numPiers++) {
+ if (bChans[numPiers] == AR9287_BCHAN_UNUSED)
+ break;
+ }
+
+ match = ath9k_hw_get_lower_upper_index(
+ (u8)FREQ2FBIN(centers.synth_center,
+ IS_CHAN_2GHZ(chan)), bChans, numPiers,
+ &idxL, &idxR);
+
+ if (match) {
+ for (i = 0; i < numXpdGains; i++) {
+ minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
+ maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pRawDataSet[idxL].pwrPdg[i],
+ pRawDataSet[idxL].vpdPdg[i],
+ AR9287_PD_GAIN_ICEPTS, vpdTableI[i]);
+ }
+ } else {
+ for (i = 0; i < numXpdGains; i++) {
+ pVpdL = pRawDataSet[idxL].vpdPdg[i];
+ pPwrL = pRawDataSet[idxL].pwrPdg[i];
+ pVpdR = pRawDataSet[idxR].vpdPdg[i];
+ pPwrR = pRawDataSet[idxR].pwrPdg[i];
+
+ minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+ maxPwrT4[i] =
+ min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1],
+ pPwrR[AR9287_PD_GAIN_ICEPTS - 1]);
+
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrL, pVpdL,
+ AR9287_PD_GAIN_ICEPTS,
+ vpdTableL[i]);
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrR, pVpdR,
+ AR9287_PD_GAIN_ICEPTS,
+ vpdTableR[i]);
+
+ for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+ vpdTableI[i][j] =
+ (u8)(ath9k_hw_interpolate((u16)
+ FREQ2FBIN(centers. synth_center,
+ IS_CHAN_2GHZ(chan)),
+ bChans[idxL], bChans[idxR],
+ vpdTableL[i][j], vpdTableR[i][j]));
+ }
+ }
+ }
+ *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
+
+ k = 0;
+ for (i = 0; i < numXpdGains; i++) {
+ if (i == (numXpdGains - 1))
+ pPdGainBoundaries[i] = (u16)(maxPwrT4[i] / 2);
+ else
+ pPdGainBoundaries[i] = (u16)((maxPwrT4[i] +
+ minPwrT4[i+1]) / 4);
+
+ pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER,
+ pPdGainBoundaries[i]);
+
+
+ if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
+ minDelta = pPdGainBoundaries[0] - 23;
+ pPdGainBoundaries[0] = 23;
+ } else
+ minDelta = 0;
+
+ if (i == 0) {
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ss = (int16_t)(0 - (minPwrT4[i] / 2));
+ else
+ ss = 0;
+ } else
+ ss = (int16_t)((pPdGainBoundaries[i-1] -
+ (minPwrT4[i] / 2)) -
+ tPdGainOverlap + 1 + minDelta);
+
+ vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+ while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
+ pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
+ ss++;
+ }
+
+ sizeCurrVpdTable = (u8)((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+ tgtIndex = (u8)(pPdGainBoundaries[i] +
+ tPdGainOverlap - (minPwrT4[i] / 2));
+ maxIndex = (tgtIndex < sizeCurrVpdTable) ?
+ tgtIndex : sizeCurrVpdTable;
+
+ while ((ss < maxIndex) && (k < (AR9287_NUM_PDADC_VALUES - 1)))
+ pPDADCValues[k++] = vpdTableI[i][ss++];
+
+ vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
+ vpdTableI[i][sizeCurrVpdTable - 2]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+ if (tgtIndex > maxIndex) {
+ while ((ss <= tgtIndex) &&
+ (k < (AR9287_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t) TMP_VAL_VPD_TABLE;
+ pPDADCValues[k++] = (u8)((tmpVal > 255) ?
+ 255 : tmpVal);
+ ss++;
+ }
+ }
+ }
+
+ while (i < AR9287_PD_GAINS_IN_MASK) {
+ pPdGainBoundaries[i] = pPdGainBoundaries[i-1];
+ i++;
+ }
+
+ while (k < AR9287_NUM_PDADC_VALUES) {
+ pPDADCValues[k] = pPDADCValues[k-1];
+ k++;
+ }
+
+#undef TMP_VAL_VPD_TABLE
+}
+
+static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
+ u8 *pCalChans, u16 availPiers,
+ int8_t *pPwr)
+{
+ u16 idxL = 0, idxR = 0, numPiers;
+ bool match;
+ struct chan_centers centers;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ for (numPiers = 0; numPiers < availPiers; numPiers++) {
+ if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED)
+ break;
+ }
+
+ match = ath9k_hw_get_lower_upper_index(
+ (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
+ pCalChans, numPiers,
+ &idxL, &idxR);
+
+ if (match) {
+ *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0];
+ } else {
+ *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
+ (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
+ }
+
+}
+
+static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
+ int32_t txPower, u16 chain)
+{
+ u32 tmpVal;
+ u32 a;
+
+ tmpVal = REG_READ(ah, 0xa270);
+ tmpVal = tmpVal & 0xFCFFFFFF;
+ tmpVal = tmpVal | (0x3 << 24);
+ REG_WRITE(ah, 0xa270, tmpVal);
+
+ tmpVal = REG_READ(ah, 0xb270);
+ tmpVal = tmpVal & 0xFCFFFFFF;
+ tmpVal = tmpVal | (0x3 << 24);
+ REG_WRITE(ah, 0xb270, tmpVal);
+
+ if (chain == 0) {
+ tmpVal = REG_READ(ah, 0xa398);
+ tmpVal = tmpVal & 0xff00ffff;
+ a = (txPower)&0xff;
+ tmpVal = tmpVal | (a << 16);
+ REG_WRITE(ah, 0xa398, tmpVal);
+ }
+
+ if (chain == 1) {
+ tmpVal = REG_READ(ah, 0xb398);
+ tmpVal = tmpVal & 0xff00ffff;
+ a = (txPower)&0xff;
+ tmpVal = tmpVal | (a << 16);
+ REG_WRITE(ah, 0xb398, tmpVal);
+ }
+}
+
+static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ int16_t *pTxPowerIndexOffset)
+{
+ struct cal_data_per_freq_ar9287 *pRawDataset;
+ struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
+ u8 *pCalBChans = NULL;
+ u16 pdGainOverlap_t2;
+ u8 pdadcValues[AR9287_NUM_PDADC_VALUES];
+ u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK];
+ u16 numPiers = 0, i, j;
+ int16_t tMinCalPower;
+ u16 numXpdGain, xpdMask;
+ u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0};
+ u32 reg32, regOffset, regChainOffset;
+ int16_t modalIdx, diff = 0;
+ struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
+ modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
+ xpdMask = pEepData->modalHeader.xpdGain;
+ if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
+ AR9287_EEP_MINOR_VER_2)
+ pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
+ else
+ pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+
+ if (IS_CHAN_2GHZ(chan)) {
+ pCalBChans = pEepData->calFreqPier2G;
+ numPiers = AR9287_NUM_2G_CAL_PIERS;
+ if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ pRawDatasetOpenLoop =
+ (struct cal_data_op_loop_ar9287 *)
+ pEepData->calPierData2G[0];
+ ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0];
+ }
+ }
+
+ numXpdGain = 0;
+ for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) {
+ if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) {
+ if (numXpdGain >= AR9287_NUM_PD_GAINS)
+ break;
+ xpdGainValues[numXpdGain] =
+ (u16)(AR9287_PD_GAINS_IN_MASK-i);
+ numXpdGain++;
+ }
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+ (numXpdGain - 1) & 0x3);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+ xpdGainValues[0]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+ xpdGainValues[1]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+ xpdGainValues[2]);
+
+ for (i = 0; i < AR9287_MAX_CHAINS; i++) {
+ regChainOffset = i * 0x1000;
+ if (pEepData->baseEepHeader.txMask & (1 << i)) {
+ pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *)
+ pEepData->calPierData2G[i];
+ if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ int8_t txPower;
+ ar9287_eeprom_get_tx_gain_index(ah, chan,
+ pRawDatasetOpenLoop,
+ pCalBChans, numPiers,
+ &txPower);
+ ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i);
+ } else {
+ pRawDataset =
+ (struct cal_data_per_freq_ar9287 *)
+ pEepData->calPierData2G[i];
+ ath9k_hw_get_AR9287_gain_boundaries_pdadcs(
+ ah, chan, pRawDataset,
+ pCalBChans, numPiers,
+ pdGainOverlap_t2,
+ &tMinCalPower, gainBoundaries,
+ pdadcValues, numXpdGain);
+ }
+
+ if (i == 0) {
+ if (!ath9k_hw_AR9287_get_eeprom(
+ ah, EEP_OL_PWRCTRL)) {
+ REG_WRITE(ah, AR_PHY_TPCRG5 +
+ regChainOffset,
+ SM(pdGainOverlap_t2,
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
+ SM(gainBoundaries[0],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+ | SM(gainBoundaries[1],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+ | SM(gainBoundaries[2],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+ | SM(gainBoundaries[3],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+ }
+ }
+
+ if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB !=
+ pEepData->baseEepHeader.pwrTableOffset) {
+ diff = (u16)
+ (pEepData->baseEepHeader.pwrTableOffset
+ - (int32_t)AR9287_PWR_TABLE_OFFSET_DB);
+ diff *= 2;
+
+ for (j = 0;
+ j < ((u16)AR9287_NUM_PDADC_VALUES-diff);
+ j++)
+ pdadcValues[j] = pdadcValues[j+diff];
+
+ for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff);
+ j < AR9287_NUM_PDADC_VALUES; j++)
+ pdadcValues[j] =
+ pdadcValues[
+ AR9287_NUM_PDADC_VALUES-diff];
+ }
+
+ if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ regOffset = AR_PHY_BASE + (672 << 2) +
+ regChainOffset;
+ for (j = 0; j < 32; j++) {
+ reg32 = ((pdadcValues[4*j + 0]
+ & 0xFF) << 0) |
+ ((pdadcValues[4*j + 1]
+ & 0xFF) << 8) |
+ ((pdadcValues[4*j + 2]
+ & 0xFF) << 16) |
+ ((pdadcValues[4*j + 3]
+ & 0xFF) << 24) ;
+ REG_WRITE(ah, regOffset, reg32);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "PDADC (%d,%4x): %4.4x %8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "PDADC: Chain %d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1,
+ pdadcValues[4 * j + 1],
+ 4 * j + 2,
+ pdadcValues[4 * j + 2],
+ 4 * j + 3,
+ pdadcValues[4 * j + 3]);
+
+ regOffset += 4;
+ }
+ }
+ }
+ }
+
+ *pTxPowerIndexOffset = 0;
+}
+
+static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
+ struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl,
+ u16 AntennaReduction, u16 twiceMaxRegulatoryPower,
+ u16 powerLimit)
+{
+#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6
+#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ static const u16 tpScaleReductionTable[5] =
+ { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+ int i;
+ int16_t twiceLargestAntenna;
+ struct cal_ctl_data_ar9287 *rep;
+ struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
+ targetPowerCck = {0, {0, 0, 0, 0} };
+ struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} },
+ targetPowerCckExt = {0, {0, 0, 0, 0} };
+ struct cal_target_power_ht targetPowerHt20,
+ targetPowerHt40 = {0, {0, 0, 0, 0} };
+ u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+ u16 ctlModesFor11g[] =
+ {CTL_11B, CTL_11G, CTL_2GHT20,
+ CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40};
+ u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq;
+ struct chan_centers centers;
+ int tx_chainmask;
+ u16 twiceMinEdgePower;
+ struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
+ tx_chainmask = ah->txchainmask;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0],
+ pEepData->modalHeader.antennaGainCh[1]);
+
+ twiceLargestAntenna = (int16_t)min((AntennaReduction) -
+ twiceLargestAntenna, 0);
+
+ maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+ if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX)
+ maxRegAllowedPower -=
+ (tpScaleReductionTable[(regulatory->tp_scale)] * 2);
+
+ scaledPower = min(powerLimit, maxRegAllowedPower);
+
+ switch (ar5416_get_ntxchains(tx_chainmask)) {
+ case 1:
+ break;
+ case 2:
+ scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+ break;
+ case 3:
+ scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+ break;
+ }
+ scaledPower = max((u16)0, scaledPower);
+
+ if (IS_CHAN_2GHZ(chan)) {
+ numCtlModes =
+ ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
+ pCtlMode = ctlModesFor11g;
+
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPowerCck,
+ AR9287_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCck, 4, false);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower2G,
+ AR9287_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdm, 4, false);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower2GHT20,
+ AR9287_NUM_2G_20_TARGET_POWERS,
+ &targetPowerHt20, 8, false);
+
+ if (IS_CHAN_HT40(chan)) {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower2GHT40,
+ AR9287_NUM_2G_40_TARGET_POWERS,
+ &targetPowerHt40, 8, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPowerCck,
+ AR9287_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCckExt, 4, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower2G,
+ AR9287_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdmExt, 4, true);
+ }
+ }
+
+ for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+ bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+ (pCtlMode[ctlMode] == CTL_2GHT40);
+ if (isHt40CtlMode)
+ freq = centers.synth_center;
+ else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+ freq = centers.ext_center;
+ else
+ freq = centers.ctl_center;
+
+ if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
+ ah->eep_ops->get_eeprom_rev(ah) <= 2)
+ twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+
+ for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
+ if ((((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ pEepData->ctlIndex[i]) ||
+ (((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ ((pEepData->ctlIndex[i] &
+ CTL_MODE_M) | SD_NO_CTL))) {
+
+ rep = &(pEepData->ctlData[i]);
+ twiceMinEdgePower = ath9k_hw_get_max_edge_power(
+ freq,
+ rep->ctlEdges[ar5416_get_ntxchains(
+ tx_chainmask) - 1],
+ IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES);
+
+ if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
+ twiceMaxEdgePower = min(
+ twiceMaxEdgePower,
+ twiceMinEdgePower);
+ else {
+ twiceMaxEdgePower = twiceMinEdgePower;
+ break;
+ }
+ }
+ }
+
+ minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
+
+ switch (pCtlMode[ctlMode]) {
+ case CTL_11B:
+ for (i = 0;
+ i < ARRAY_SIZE(targetPowerCck.tPow2x);
+ i++) {
+ targetPowerCck.tPow2x[i] = (u8)min(
+ (u16)targetPowerCck.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11A:
+ case CTL_11G:
+ for (i = 0;
+ i < ARRAY_SIZE(targetPowerOfdm.tPow2x);
+ i++) {
+ targetPowerOfdm.tPow2x[i] = (u8)min(
+ (u16)targetPowerOfdm.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_5GHT20:
+ case CTL_2GHT20:
+ for (i = 0;
+ i < ARRAY_SIZE(targetPowerHt20.tPow2x);
+ i++) {
+ targetPowerHt20.tPow2x[i] = (u8)min(
+ (u16)targetPowerHt20.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11B_EXT:
+ targetPowerCckExt.tPow2x[0] = (u8)min(
+ (u16)targetPowerCckExt.tPow2x[0],
+ minCtlPower);
+ break;
+ case CTL_11A_EXT:
+ case CTL_11G_EXT:
+ targetPowerOfdmExt.tPow2x[0] = (u8)min(
+ (u16)targetPowerOfdmExt.tPow2x[0],
+ minCtlPower);
+ break;
+ case CTL_5GHT40:
+ case CTL_2GHT40:
+ for (i = 0;
+ i < ARRAY_SIZE(targetPowerHt40.tPow2x);
+ i++) {
+ targetPowerHt40.tPow2x[i] = (u8)min(
+ (u16)targetPowerHt40.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ ratesArray[rate6mb] =
+ ratesArray[rate9mb] =
+ ratesArray[rate12mb] =
+ ratesArray[rate18mb] =
+ ratesArray[rate24mb] =
+ targetPowerOfdm.tPow2x[0];
+
+ ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+ ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+ ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+ ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+ ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+ if (IS_CHAN_2GHZ(chan)) {
+ ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+ ratesArray[rate2s] = ratesArray[rate2l] =
+ targetPowerCck.tPow2x[1];
+ ratesArray[rate5_5s] = ratesArray[rate5_5l] =
+ targetPowerCck.tPow2x[2];
+ ratesArray[rate11s] = ratesArray[rate11l] =
+ targetPowerCck.tPow2x[3];
+ }
+ if (IS_CHAN_HT40(chan)) {
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++)
+ ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i];
+
+ ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+ if (IS_CHAN_2GHZ(chan))
+ ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
+ }
+
+#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN
+#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN
+}
+
+static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
+ struct ath9k_channel *chan, u16 cfgCtl,
+ u8 twiceAntennaReduction,
+ u8 twiceMaxRegulatoryPower,
+ u8 powerLimit)
+{
+#define INCREASE_MAXPOW_BY_TWO_CHAIN 6
+#define INCREASE_MAXPOW_BY_THREE_CHAIN 10
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
+ struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
+ int16_t ratesArray[Ar5416RateSize];
+ int16_t txPowerIndexOffset = 0;
+ u8 ht40PowerIncForPdadc = 2;
+ int i;
+
+ memset(ratesArray, 0, sizeof(ratesArray));
+
+ if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
+ AR9287_EEP_MINOR_VER_2)
+ ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+
+ ath9k_hw_set_AR9287_power_per_rate_table(ah, chan,
+ &ratesArray[0], cfgCtl,
+ twiceAntennaReduction,
+ twiceMaxRegulatoryPower,
+ powerLimit);
+
+ ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset);
+
+ for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+ ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
+ if (ratesArray[i] > AR9287_MAX_RATE_POWER)
+ ratesArray[i] = AR9287_MAX_RATE_POWER;
+ }
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ for (i = 0; i < Ar5416RateSize; i++)
+ ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+ ATH9K_POW_SM(ratesArray[rate18mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate6mb], 0));
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+ ATH9K_POW_SM(ratesArray[rate54mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate24mb], 0));
+
+ if (IS_CHAN_2GHZ(chan)) {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+ ATH9K_POW_SM(ratesArray[rate2s], 24)
+ | ATH9K_POW_SM(ratesArray[rate2l], 16)
+ | ATH9K_POW_SM(ratesArray[rateXr], 8)
+ | ATH9K_POW_SM(ratesArray[rate1l], 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+ ATH9K_POW_SM(ratesArray[rate11s], 24)
+ | ATH9K_POW_SM(ratesArray[rate11l], 16)
+ | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+ | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+ ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+ ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+
+ if (IS_CHAN_HT40(chan)) {
+ if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+ ATH9K_POW_SM(ratesArray[rateHt40_3], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_2], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_1], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_0], 0));
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+ ATH9K_POW_SM(ratesArray[rateHt40_7], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_6], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_5], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_4], 0));
+ } else {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+ ATH9K_POW_SM(ratesArray[rateHt40_3] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+ ht40PowerIncForPdadc, 0));
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+ ATH9K_POW_SM(ratesArray[rateHt40_7] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+ ht40PowerIncForPdadc, 0));
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+ ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+ | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+ | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+ | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+ }
+
+ if (IS_CHAN_2GHZ(chan))
+ i = rate1l;
+ else
+ i = rate6mb;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ regulatory->max_power_level =
+ ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2;
+ else
+ regulatory->max_power_level = ratesArray[i];
+
+ switch (ar5416_get_ntxchains(ah->txchainmask)) {
+ case 1:
+ break;
+ case 2:
+ regulatory->max_power_level +=
+ INCREASE_MAXPOW_BY_TWO_CHAIN;
+ break;
+ case 3:
+ regulatory->max_power_level +=
+ INCREASE_MAXPOW_BY_THREE_CHAIN;
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Invalid chainmask configuration\n");
+ break;
+ }
+}
+
+static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+}
+
+static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+ struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
+ u16 antWrites[AR9287_ANT_16S];
+ u32 regChainOffset;
+ u8 txRxAttenLocal;
+ int i, j, offset_num;
+
+ pModal = &eep->modalHeader;
+
+ antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF);
+ antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF);
+ antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF);
+ antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF);
+ antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF);
+ antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF);
+ antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF);
+ antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF);
+
+ offset_num = 8;
+
+ for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) {
+ antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf);
+ antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3);
+ antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3);
+ antWrites[j++] = 0;
+ antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3);
+ antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3);
+ antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3);
+ antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3);
+ }
+
+ REG_WRITE(ah, AR_PHY_SWITCH_COM,
+ ah->eep_ops->get_eeprom_antenna_cfg(ah, chan));
+
+ for (i = 0; i < AR9287_MAX_CHAINS; i++) {
+ regChainOffset = i * 0x1000;
+
+ REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+ pModal->antCtrlChain[i]);
+
+ REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+ (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset)
+ & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+ SM(pModal->iqCalICh[i],
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+ SM(pModal->iqCalQCh[i],
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+ txRxAttenLocal = pModal->txRxAttenCh[i];
+
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+ pModal->bswMargin[i]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN1_DB,
+ pModal->bswAtten[i]);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
+ AR9280_PHY_RXGAIN_TXRX_ATTEN,
+ txRxAttenLocal);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN,
+ pModal->rxTxMarginCh[i]);
+ }
+
+
+ if (IS_CHAN_HT40(chan))
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+ AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40);
+ else
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+ AR_PHY_SETTLING_SWITCH, pModal->switchSettling);
+
+ REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+ AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize);
+
+ REG_WRITE(ah, AR_PHY_RF_CTL4,
+ SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
+ | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
+ | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON)
+ | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL3,
+ AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn);
+
+ REG_RMW_FIELD(ah, AR_PHY_CCA,
+ AR9280_PHY_CCA_THRESH62, pModal->thresh62);
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
+ AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62);
+
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1,
+ AR9287_AN_RF2G3_DB1_S, pModal->db1);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2,
+ AR9287_AN_RF2G3_DB2_S, pModal->db2);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
+ AR9287_AN_RF2G3_OB_CCK,
+ AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
+ AR9287_AN_RF2G3_OB_PSK,
+ AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
+ AR9287_AN_RF2G3_OB_QAM,
+ AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
+ AR9287_AN_RF2G3_OB_PAL_OFF,
+ AR9287_AN_RF2G3_OB_PAL_OFF_S,
+ pModal->ob_pal_off);
+
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
+ AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S,
+ pModal->db1);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2,
+ AR9287_AN_RF2G3_DB2_S, pModal->db2);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
+ AR9287_AN_RF2G3_OB_CCK,
+ AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
+ AR9287_AN_RF2G3_OB_PSK,
+ AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
+ AR9287_AN_RF2G3_OB_QAM,
+ AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
+ AR9287_AN_RF2G3_OB_PAL_OFF,
+ AR9287_AN_RF2G3_OB_PAL_OFF_S,
+ pModal->ob_pal_off);
+
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+ AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart);
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+ AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn);
+
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2,
+ AR9287_AN_TOP2_XPABIAS_LVL,
+ AR9287_AN_TOP2_XPABIAS_LVL_S,
+ pModal->xpaBiasLvl);
+}
+
+static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah,
+ enum ieee80211_band freq_band)
+{
+ return 1;
+}
+
+static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+ struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
+
+ return pModal->antCtrlCommon & 0xFFFF;
+}
+
+static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah,
+ u16 i, bool is2GHz)
+{
+#define EEP_MAP9287_SPURCHAN \
+ (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan)
+ u16 spur_val = AR_NO_SPUR;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Getting spur idx %d is2Ghz. %d val %x\n",
+ i, is2GHz, ah->config.spurchans[i][is2GHz]);
+
+ switch (ah->config.spurmode) {
+ case SPUR_DISABLE:
+ break;
+ case SPUR_ENABLE_IOCTL:
+ spur_val = ah->config.spurchans[i][is2GHz];
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
+ break;
+ case SPUR_ENABLE_EEPROM:
+ spur_val = EEP_MAP9287_SPURCHAN;
+ break;
+ }
+
+ return spur_val;
+
+#undef EEP_MAP9287_SPURCHAN
+}
+
+const struct eeprom_ops eep_AR9287_ops = {
+ .check_eeprom = ath9k_hw_AR9287_check_eeprom,
+ .get_eeprom = ath9k_hw_AR9287_get_eeprom,
+ .fill_eeprom = ath9k_hw_AR9287_fill_eeprom,
+ .get_eeprom_ver = ath9k_hw_AR9287_get_eeprom_ver,
+ .get_eeprom_rev = ath9k_hw_AR9287_get_eeprom_rev,
+ .get_num_ant_config = ath9k_hw_AR9287_get_num_ant_config,
+ .get_eeprom_antenna_cfg = ath9k_hw_AR9287_get_eeprom_antenna_cfg,
+ .set_board_values = ath9k_hw_AR9287_set_board_values,
+ .set_addac = ath9k_hw_AR9287_set_addac,
+ .set_txpower = ath9k_hw_AR9287_set_txpower,
+ .get_spur_channel = ath9k_hw_AR9287_get_spur_channel
+};
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..ae7fb5dcb266
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -0,0 +1,1387 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+
+static void ath9k_get_txgain_index(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ struct calDataPerFreqOpLoop *rawDatasetOpLoop,
+ u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx)
+{
+ u8 pcdac, i = 0;
+ u16 idxL = 0, idxR = 0, numPiers;
+ bool match;
+ struct chan_centers centers;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ for (numPiers = 0; numPiers < availPiers; numPiers++)
+ if (calChans[numPiers] == AR5416_BCHAN_UNUSED)
+ break;
+
+ match = ath9k_hw_get_lower_upper_index(
+ (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
+ calChans, numPiers, &idxL, &idxR);
+ if (match) {
+ pcdac = rawDatasetOpLoop[idxL].pcdac[0][0];
+ *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0];
+ } else {
+ pcdac = rawDatasetOpLoop[idxR].pcdac[0][0];
+ *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] +
+ rawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
+ }
+
+ while (pcdac > ah->originalGain[i] &&
+ i < (AR9280_TX_GAIN_TABLE_SIZE - 1))
+ i++;
+
+ *pcdacIdx = i;
+ return;
+}
+
+static void ath9k_olc_get_pdadcs(struct ath_hw *ah,
+ u32 initTxGain,
+ int txPower,
+ u8 *pPDADCValues)
+{
+ u32 i;
+ u32 offset;
+
+ REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0,
+ AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
+ REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1,
+ AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
+
+ REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7,
+ AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain);
+
+ offset = txPower;
+ for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++)
+ if (i < offset)
+ pPDADCValues[i] = 0x0;
+ else
+ pPDADCValues[i] = 0xFF;
+}
+
+static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah)
+{
+ return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF);
+}
+
+static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah)
+{
+ return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF);
+}
+
+static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
+{
+#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16))
+ u16 *eep_data = (u16 *)&ah->eeprom.def;
+ int addr, ar5416_eep_start_loc = 0x100;
+
+ for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) {
+ if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
+ eep_data)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Unable to read eeprom region\n");
+ return false;
+ }
+ eep_data++;
+ }
+ return true;
+#undef SIZE_EEPROM_DEF
+}
+
+static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
+{
+ struct ar5416_eeprom_def *eep =
+ (struct ar5416_eeprom_def *) &ah->eeprom.def;
+ u16 *eepdata, temp, magic, magic2;
+ u32 sum = 0, el;
+ bool need_swap = false;
+ int i, addr, size;
+
+ if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n");
+ return false;
+ }
+
+ if (!ath9k_hw_use_flash(ah)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
+
+ if (magic != AR5416_EEPROM_MAGIC) {
+ magic2 = swab16(magic);
+
+ if (magic2 == AR5416_EEPROM_MAGIC) {
+ size = sizeof(struct ar5416_eeprom_def);
+ need_swap = true;
+ eepdata = (u16 *) (&ah->eeprom);
+
+ for (addr = 0; addr < size / sizeof(u16); addr++) {
+ temp = swab16(*eepdata);
+ *eepdata = temp;
+ eepdata++;
+ }
+ } else {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Invalid EEPROM Magic. "
+ "Endianness mismatch.\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
+
+ if (need_swap)
+ el = swab16(ah->eeprom.def.baseEepHeader.length);
+ else
+ el = ah->eeprom.def.baseEepHeader.length;
+
+ if (el > sizeof(struct ar5416_eeprom_def))
+ el = sizeof(struct ar5416_eeprom_def) / sizeof(u16);
+ else
+ el = el / sizeof(u16);
+
+ eepdata = (u16 *)(&ah->eeprom);
+
+ for (i = 0; i < el; i++)
+ sum ^= *eepdata++;
+
+ if (need_swap) {
+ u32 integer, j;
+ u16 word;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "EEPROM Endianness is not native.. Changing.\n");
+
+ word = swab16(eep->baseEepHeader.length);
+ eep->baseEepHeader.length = word;
+
+ word = swab16(eep->baseEepHeader.checksum);
+ eep->baseEepHeader.checksum = word;
+
+ word = swab16(eep->baseEepHeader.version);
+ eep->baseEepHeader.version = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[0]);
+ eep->baseEepHeader.regDmn[0] = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[1]);
+ eep->baseEepHeader.regDmn[1] = word;
+
+ word = swab16(eep->baseEepHeader.rfSilent);
+ eep->baseEepHeader.rfSilent = word;
+
+ word = swab16(eep->baseEepHeader.blueToothOptions);
+ eep->baseEepHeader.blueToothOptions = word;
+
+ word = swab16(eep->baseEepHeader.deviceCap);
+ eep->baseEepHeader.deviceCap = word;
+
+ for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
+ struct modal_eep_header *pModal =
+ &eep->modalHeader[j];
+ integer = swab32(pModal->antCtrlCommon);
+ pModal->antCtrlCommon = integer;
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ integer = swab32(pModal->antCtrlChain[i]);
+ pModal->antCtrlChain[i] = integer;
+ }
+
+ for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
+ word = swab16(pModal->spurChans[i].spurChan);
+ pModal->spurChans[i].spurChan = word;
+ }
+ }
+ }
+
+ if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
+ ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ sum, ah->eep_ops->get_eeprom_ver(ah));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
+ enum eeprom_param param)
+{
+ struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+ struct modal_eep_header *pModal = eep->modalHeader;
+ struct base_eep_header *pBase = &eep->baseEepHeader;
+
+ switch (param) {
+ case EEP_NFTHRESH_5:
+ return pModal[0].noiseFloorThreshCh[0];
+ case EEP_NFTHRESH_2:
+ return pModal[1].noiseFloorThreshCh[0];
+ case AR_EEPROM_MAC(0):
+ return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+ case AR_EEPROM_MAC(1):
+ return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+ case AR_EEPROM_MAC(2):
+ return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+ case EEP_REG_0:
+ return pBase->regDmn[0];
+ case EEP_REG_1:
+ return pBase->regDmn[1];
+ case EEP_OP_CAP:
+ return pBase->deviceCap;
+ case EEP_OP_MODE:
+ return pBase->opCapFlags;
+ case EEP_RF_SILENT:
+ return pBase->rfSilent;
+ case EEP_OB_5:
+ return pModal[0].ob;
+ case EEP_DB_5:
+ return pModal[0].db;
+ case EEP_OB_2:
+ return pModal[1].ob;
+ case EEP_DB_2:
+ return pModal[1].db;
+ case EEP_MINOR_REV:
+ return AR5416_VER_MASK;
+ case EEP_TX_MASK:
+ return pBase->txMask;
+ case EEP_RX_MASK:
+ return pBase->rxMask;
+ case EEP_RXGAIN_TYPE:
+ return pBase->rxGainType;
+ case EEP_TXGAIN_TYPE:
+ return pBase->txGainType;
+ case EEP_OL_PWRCTRL:
+ if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
+ return pBase->openLoopPwrCntl ? true : false;
+ else
+ return false;
+ case EEP_RC_CHAIN_MASK:
+ if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
+ return pBase->rcChainMask;
+ else
+ return 0;
+ case EEP_DAC_HPWR_5G:
+ if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20)
+ return pBase->dacHiPwrMode_5G;
+ else
+ return 0;
+ case EEP_FRAC_N_5G:
+ if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22)
+ return pBase->frac_n_5g;
+ else
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static void ath9k_hw_def_set_gain(struct ath_hw *ah,
+ struct modal_eep_header *pModal,
+ struct ar5416_eeprom_def *eep,
+ u8 txRxAttenLocal, int regChainOffset, int i)
+{
+ if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) {
+ txRxAttenLocal = pModal->txRxAttenCh[i];
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+ pModal->bswMargin[i]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN1_DB,
+ pModal->bswAtten[i]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+ pModal->xatten2Margin[i]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+ pModal->xatten2Db[i]);
+ } else {
+ REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
+ ~AR_PHY_GAIN_2GHZ_BSW_MARGIN)
+ | SM(pModal-> bswMargin[i],
+ AR_PHY_GAIN_2GHZ_BSW_MARGIN));
+ REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
+ ~AR_PHY_GAIN_2GHZ_BSW_ATTEN)
+ | SM(pModal->bswAtten[i],
+ AR_PHY_GAIN_2GHZ_BSW_ATTEN));
+ }
+ }
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ REG_RMW_FIELD(ah,
+ AR_PHY_RXGAIN + regChainOffset,
+ AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+ REG_RMW_FIELD(ah,
+ AR_PHY_RXGAIN + regChainOffset,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]);
+ } else {
+ REG_WRITE(ah,
+ AR_PHY_RXGAIN + regChainOffset,
+ (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) &
+ ~AR_PHY_RXGAIN_TXRX_ATTEN)
+ | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN));
+ REG_WRITE(ah,
+ AR_PHY_GAIN_2GHZ + regChainOffset,
+ (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
+ ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
+ SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
+ }
+}
+
+static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ struct modal_eep_header *pModal;
+ struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+ int i, regChainOffset;
+ u8 txRxAttenLocal;
+
+ pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+ txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
+
+ REG_WRITE(ah, AR_PHY_SWITCH_COM,
+ ah->eep_ops->get_eeprom_antenna_cfg(ah, chan));
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ if (AR_SREV_9280(ah)) {
+ if (i >= 2)
+ break;
+ }
+
+ if (AR_SREV_5416_20_OR_LATER(ah) &&
+ (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0))
+ regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+ else
+ regChainOffset = i * 0x1000;
+
+ REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+ pModal->antCtrlChain[i]);
+
+ REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+ (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) &
+ ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+ SM(pModal->iqCalICh[i],
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+ SM(pModal->iqCalQCh[i],
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+ if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah))
+ ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal,
+ regChainOffset, i);
+ }
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (IS_CHAN_2GHZ(chan)) {
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+ AR_AN_RF2G1_CH0_OB,
+ AR_AN_RF2G1_CH0_OB_S,
+ pModal->ob);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+ AR_AN_RF2G1_CH0_DB,
+ AR_AN_RF2G1_CH0_DB_S,
+ pModal->db);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+ AR_AN_RF2G1_CH1_OB,
+ AR_AN_RF2G1_CH1_OB_S,
+ pModal->ob_ch1);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+ AR_AN_RF2G1_CH1_DB,
+ AR_AN_RF2G1_CH1_DB_S,
+ pModal->db_ch1);
+ } else {
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+ AR_AN_RF5G1_CH0_OB5,
+ AR_AN_RF5G1_CH0_OB5_S,
+ pModal->ob);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+ AR_AN_RF5G1_CH0_DB5,
+ AR_AN_RF5G1_CH0_DB5_S,
+ pModal->db);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+ AR_AN_RF5G1_CH1_OB5,
+ AR_AN_RF5G1_CH1_OB5_S,
+ pModal->ob_ch1);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+ AR_AN_RF5G1_CH1_DB5,
+ AR_AN_RF5G1_CH1_DB5_S,
+ pModal->db_ch1);
+ }
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+ AR_AN_TOP2_XPABIAS_LVL,
+ AR_AN_TOP2_XPABIAS_LVL_S,
+ pModal->xpaBiasLvl);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+ AR_AN_TOP2_LOCALBIAS,
+ AR_AN_TOP2_LOCALBIAS_S,
+ pModal->local_bias);
+ REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
+ pModal->force_xpaon);
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
+ pModal->switchSettling);
+ REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
+ pModal->adcDesiredSize);
+
+ if (!AR_SREV_9280_10_OR_LATER(ah))
+ REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+ AR_PHY_DESIRED_SZ_PGA,
+ pModal->pgaDesiredSize);
+
+ REG_WRITE(ah, AR_PHY_RF_CTL4,
+ SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
+ | SM(pModal->txEndToXpaOff,
+ AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
+ | SM(pModal->txFrameToXpaOn,
+ AR_PHY_RF_CTL4_FRAME_XPAA_ON)
+ | SM(pModal->txFrameToXpaOn,
+ AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
+ pModal->txEndToRxOn);
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
+ pModal->thresh62);
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
+ AR_PHY_EXT_CCA0_THRESH62,
+ pModal->thresh62);
+ } else {
+ REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62,
+ pModal->thresh62);
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+ AR_PHY_EXT_CCA_THRESH62,
+ pModal->thresh62);
+ }
+
+ if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) {
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+ AR_PHY_TX_END_DATA_START,
+ pModal->txFrameToDataStart);
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
+ pModal->txFrameToPaOn);
+ }
+
+ if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) {
+ if (IS_CHAN_HT40(chan))
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+ AR_PHY_SETTLING_SWITCH,
+ pModal->swSettleHt40);
+ }
+
+ if (AR_SREV_9280_20_OR_LATER(ah) &&
+ AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
+ REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL,
+ AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK,
+ pModal->miscBits);
+
+
+ if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) {
+ if (IS_CHAN_2GHZ(chan))
+ REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE,
+ eep->baseEepHeader.dacLpMode);
+ else if (eep->baseEepHeader.dacHiPwrMode_5G)
+ REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0);
+ else
+ REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE,
+ eep->baseEepHeader.dacLpMode);
+
+ REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP,
+ pModal->miscBits >> 2);
+
+ REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9,
+ AR_PHY_TX_DESIRED_SCALE_CCK,
+ eep->baseEepHeader.desiredScaleCCK);
+ }
+}
+
+static void ath9k_hw_def_set_addac(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt])
+ struct modal_eep_header *pModal;
+ struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+ u8 biaslevel;
+
+ if (ah->hw_version.macVersion != AR_SREV_VERSION_9160)
+ return;
+
+ if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7)
+ return;
+
+ pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+
+ if (pModal->xpaBiasLvl != 0xff) {
+ biaslevel = pModal->xpaBiasLvl;
+ } else {
+ u16 resetFreqBin, freqBin, freqCount = 0;
+ struct chan_centers centers;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ resetFreqBin = FREQ2FBIN(centers.synth_center,
+ IS_CHAN_2GHZ(chan));
+ freqBin = XPA_LVL_FREQ(0) & 0xff;
+ biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14);
+
+ freqCount++;
+
+ while (freqCount < 3) {
+ if (XPA_LVL_FREQ(freqCount) == 0x0)
+ break;
+
+ freqBin = XPA_LVL_FREQ(freqCount) & 0xff;
+ if (resetFreqBin >= freqBin)
+ biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14);
+ else
+ break;
+ freqCount++;
+ }
+ }
+
+ if (IS_CHAN_2GHZ(chan)) {
+ INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac,
+ 7, 1) & (~0x18)) | biaslevel << 3;
+ } else {
+ INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac,
+ 6, 1) & (~0xc0)) | biaslevel << 6;
+ }
+#undef XPA_LVL_FREQ
+}
+
+static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ struct cal_data_per_freq *pRawDataSet,
+ u8 *bChans, u16 availPiers,
+ u16 tPdGainOverlap, int16_t *pMinCalPower,
+ u16 *pPdGainBoundaries, u8 *pPDADCValues,
+ u16 numXpdGains)
+{
+ int i, j, k;
+ int16_t ss;
+ u16 idxL = 0, idxR = 0, numPiers;
+ static u8 vpdTableL[AR5416_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableR[AR5416_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableI[AR5416_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+
+ u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+ u8 minPwrT4[AR5416_NUM_PD_GAINS];
+ u8 maxPwrT4[AR5416_NUM_PD_GAINS];
+ int16_t vpdStep;
+ int16_t tmpVal;
+ u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+ bool match;
+ int16_t minDelta = 0;
+ struct chan_centers centers;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ for (numPiers = 0; numPiers < availPiers; numPiers++) {
+ if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
+ break;
+ }
+
+ match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
+ IS_CHAN_2GHZ(chan)),
+ bChans, numPiers, &idxL, &idxR);
+
+ if (match) {
+ for (i = 0; i < numXpdGains; i++) {
+ minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
+ maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pRawDataSet[idxL].pwrPdg[i],
+ pRawDataSet[idxL].vpdPdg[i],
+ AR5416_PD_GAIN_ICEPTS,
+ vpdTableI[i]);
+ }
+ } else {
+ for (i = 0; i < numXpdGains; i++) {
+ pVpdL = pRawDataSet[idxL].vpdPdg[i];
+ pPwrL = pRawDataSet[idxL].pwrPdg[i];
+ pVpdR = pRawDataSet[idxR].vpdPdg[i];
+ pPwrR = pRawDataSet[idxR].pwrPdg[i];
+
+ minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+ maxPwrT4[i] =
+ min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1],
+ pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
+
+
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrL, pVpdL,
+ AR5416_PD_GAIN_ICEPTS,
+ vpdTableL[i]);
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrR, pVpdR,
+ AR5416_PD_GAIN_ICEPTS,
+ vpdTableR[i]);
+
+ for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+ vpdTableI[i][j] =
+ (u8)(ath9k_hw_interpolate((u16)
+ FREQ2FBIN(centers.
+ synth_center,
+ IS_CHAN_2GHZ
+ (chan)),
+ bChans[idxL], bChans[idxR],
+ vpdTableL[i][j], vpdTableR[i][j]));
+ }
+ }
+ }
+
+ *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
+
+ k = 0;
+
+ for (i = 0; i < numXpdGains; i++) {
+ if (i == (numXpdGains - 1))
+ pPdGainBoundaries[i] =
+ (u16)(maxPwrT4[i] / 2);
+ else
+ pPdGainBoundaries[i] =
+ (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
+
+ pPdGainBoundaries[i] =
+ min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
+
+ if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
+ minDelta = pPdGainBoundaries[0] - 23;
+ pPdGainBoundaries[0] = 23;
+ } else {
+ minDelta = 0;
+ }
+
+ if (i == 0) {
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ss = (int16_t)(0 - (minPwrT4[i] / 2));
+ else
+ ss = 0;
+ } else {
+ ss = (int16_t)((pPdGainBoundaries[i - 1] -
+ (minPwrT4[i] / 2)) -
+ tPdGainOverlap + 1 + minDelta);
+ }
+ vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+ while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
+ pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
+ ss++;
+ }
+
+ sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+ tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
+ (minPwrT4[i] / 2));
+ maxIndex = (tgtIndex < sizeCurrVpdTable) ?
+ tgtIndex : sizeCurrVpdTable;
+
+ while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ pPDADCValues[k++] = vpdTableI[i][ss++];
+ }
+
+ vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
+ vpdTableI[i][sizeCurrVpdTable - 2]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+ if (tgtIndex > maxIndex) {
+ while ((ss <= tgtIndex) &&
+ (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
+ (ss - maxIndex + 1) * vpdStep));
+ pPDADCValues[k++] = (u8)((tmpVal > 255) ?
+ 255 : tmpVal);
+ ss++;
+ }
+ }
+ }
+
+ while (i < AR5416_PD_GAINS_IN_MASK) {
+ pPdGainBoundaries[i] = pPdGainBoundaries[i - 1];
+ i++;
+ }
+
+ while (k < AR5416_NUM_PDADC_VALUES) {
+ pPDADCValues[k] = pPDADCValues[k - 1];
+ k++;
+ }
+
+ return;
+}
+
+static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ int16_t *pTxPowerIndexOffset)
+{
+#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x)
+#define SM_PDGAIN_B(x, y) \
+ SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y)
+
+ struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
+ struct cal_data_per_freq *pRawDataset;
+ u8 *pCalBChans = NULL;
+ u16 pdGainOverlap_t2;
+ static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+ u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
+ u16 numPiers, i, j;
+ int16_t tMinCalPower;
+ u16 numXpdGain, xpdMask;
+ u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
+ u32 reg32, regOffset, regChainOffset;
+ int16_t modalIdx;
+
+ modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
+ xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
+
+ if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ pdGainOverlap_t2 =
+ pEepData->modalHeader[modalIdx].pdGainOverlap;
+ } else {
+ pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+ }
+
+ if (IS_CHAN_2GHZ(chan)) {
+ pCalBChans = pEepData->calFreqPier2G;
+ numPiers = AR5416_NUM_2G_CAL_PIERS;
+ } else {
+ pCalBChans = pEepData->calFreqPier5G;
+ numPiers = AR5416_NUM_5G_CAL_PIERS;
+ }
+
+ if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) {
+ pRawDataset = pEepData->calPierData2G[0];
+ ah->initPDADC = ((struct calDataPerFreqOpLoop *)
+ pRawDataset)->vpdPdg[0][0];
+ }
+
+ numXpdGain = 0;
+
+ for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+ if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+ if (numXpdGain >= AR5416_NUM_PD_GAINS)
+ break;
+ xpdGainValues[numXpdGain] =
+ (u16)(AR5416_PD_GAINS_IN_MASK - i);
+ numXpdGain++;
+ }
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+ (numXpdGain - 1) & 0x3);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+ xpdGainValues[0]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+ xpdGainValues[1]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+ xpdGainValues[2]);
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ if (AR_SREV_5416_20_OR_LATER(ah) &&
+ (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
+ (i != 0)) {
+ regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+ } else
+ regChainOffset = i * 0x1000;
+
+ if (pEepData->baseEepHeader.txMask & (1 << i)) {
+ if (IS_CHAN_2GHZ(chan))
+ pRawDataset = pEepData->calPierData2G[i];
+ else
+ pRawDataset = pEepData->calPierData5G[i];
+
+
+ if (OLC_FOR_AR9280_20_LATER) {
+ u8 pcdacIdx;
+ u8 txPower;
+
+ ath9k_get_txgain_index(ah, chan,
+ (struct calDataPerFreqOpLoop *)pRawDataset,
+ pCalBChans, numPiers, &txPower, &pcdacIdx);
+ ath9k_olc_get_pdadcs(ah, pcdacIdx,
+ txPower/2, pdadcValues);
+ } else {
+ ath9k_hw_get_def_gain_boundaries_pdadcs(ah,
+ chan, pRawDataset,
+ pCalBChans, numPiers,
+ pdGainOverlap_t2,
+ &tMinCalPower,
+ gainBoundaries,
+ pdadcValues,
+ numXpdGain);
+ }
+
+ if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
+ if (OLC_FOR_AR9280_20_LATER) {
+ REG_WRITE(ah,
+ AR_PHY_TPCRG5 + regChainOffset,
+ SM(0x6,
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
+ SM_PD_GAIN(1) | SM_PD_GAIN(2) |
+ SM_PD_GAIN(3) | SM_PD_GAIN(4));
+ } else {
+ REG_WRITE(ah,
+ AR_PHY_TPCRG5 + regChainOffset,
+ SM(pdGainOverlap_t2,
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP)|
+ SM_PDGAIN_B(0, 1) |
+ SM_PDGAIN_B(1, 2) |
+ SM_PDGAIN_B(2, 3) |
+ SM_PDGAIN_B(3, 4));
+ }
+ }
+
+ regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
+ for (j = 0; j < 32; j++) {
+ reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
+ ((pdadcValues[4 * j + 1] & 0xFF) << 8) |
+ ((pdadcValues[4 * j + 2] & 0xFF) << 16)|
+ ((pdadcValues[4 * j + 3] & 0xFF) << 24);
+ REG_WRITE(ah, regOffset, reg32);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "PDADC (%d,%4x): %4.4x %8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "PDADC: Chain %d | PDADC %3d "
+ "Value %3d | PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | PDADC %3d "
+ "Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1, pdadcValues[4 * j + 1],
+ 4 * j + 2, pdadcValues[4 * j + 2],
+ 4 * j + 3,
+ pdadcValues[4 * j + 3]);
+
+ regOffset += 4;
+ }
+ }
+ }
+
+ *pTxPowerIndexOffset = 0;
+#undef SM_PD_GAIN
+#undef SM_PDGAIN_B
+}
+
+static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ int16_t *ratesArray,
+ u16 cfgCtl,
+ u16 AntennaReduction,
+ u16 twiceMaxRegulatoryPower,
+ u16 powerLimit)
+{
+#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */
+#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */
+
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
+ u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ static const u16 tpScaleReductionTable[5] =
+ { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+
+ int i;
+ int16_t twiceLargestAntenna;
+ struct cal_ctl_data *rep;
+ struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+ 0, { 0, 0, 0, 0}
+ };
+ struct cal_target_power_leg targetPowerOfdmExt = {
+ 0, { 0, 0, 0, 0} }, targetPowerCckExt = {
+ 0, { 0, 0, 0, 0 }
+ };
+ struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
+ 0, {0, 0, 0, 0}
+ };
+ u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+ u16 ctlModesFor11a[] =
+ { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
+ u16 ctlModesFor11g[] =
+ { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
+ CTL_2GHT40
+ };
+ u16 numCtlModes, *pCtlMode, ctlMode, freq;
+ struct chan_centers centers;
+ int tx_chainmask;
+ u16 twiceMinEdgePower;
+
+ tx_chainmask = ah->txchainmask;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ twiceLargestAntenna = max(
+ pEepData->modalHeader
+ [IS_CHAN_2GHZ(chan)].antennaGainCh[0],
+ pEepData->modalHeader
+ [IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
+
+ twiceLargestAntenna = max((u8)twiceLargestAntenna,
+ pEepData->modalHeader
+ [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
+
+ twiceLargestAntenna = (int16_t)min(AntennaReduction -
+ twiceLargestAntenna, 0);
+
+ maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
+ if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
+ maxRegAllowedPower -=
+ (tpScaleReductionTable[(regulatory->tp_scale)] * 2);
+ }
+
+ scaledPower = min(powerLimit, maxRegAllowedPower);
+
+ switch (ar5416_get_ntxchains(tx_chainmask)) {
+ case 1:
+ break;
+ case 2:
+ scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+ break;
+ case 3:
+ scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+ break;
+ }
+
+ scaledPower = max((u16)0, scaledPower);
+
+ if (IS_CHAN_2GHZ(chan)) {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
+ SUB_NUM_CTL_MODES_AT_2G_40;
+ pCtlMode = ctlModesFor11g;
+
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPowerCck,
+ AR5416_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCck, 4, false);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower2G,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdm, 4, false);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower2GHT20,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerHt20, 8, false);
+
+ if (IS_CHAN_HT40(chan)) {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower2GHT40,
+ AR5416_NUM_2G_40_TARGET_POWERS,
+ &targetPowerHt40, 8, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPowerCck,
+ AR5416_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCckExt, 4, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower2G,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdmExt, 4, true);
+ }
+ } else {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11a) -
+ SUB_NUM_CTL_MODES_AT_5G_40;
+ pCtlMode = ctlModesFor11a;
+
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower5G,
+ AR5416_NUM_5G_20_TARGET_POWERS,
+ &targetPowerOfdm, 4, false);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower5GHT20,
+ AR5416_NUM_5G_20_TARGET_POWERS,
+ &targetPowerHt20, 8, false);
+
+ if (IS_CHAN_HT40(chan)) {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11a);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower5GHT40,
+ AR5416_NUM_5G_40_TARGET_POWERS,
+ &targetPowerHt40, 8, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower5G,
+ AR5416_NUM_5G_20_TARGET_POWERS,
+ &targetPowerOfdmExt, 4, true);
+ }
+ }
+
+ for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+ bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+ (pCtlMode[ctlMode] == CTL_2GHT40);
+ if (isHt40CtlMode)
+ freq = centers.synth_center;
+ else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+ freq = centers.ext_center;
+ else
+ freq = centers.ctl_center;
+
+ if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
+ ah->eep_ops->get_eeprom_rev(ah) <= 2)
+ twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+
+ for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
+ if ((((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ pEepData->ctlIndex[i]) ||
+ (((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
+ rep = &(pEepData->ctlData[i]);
+
+ twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
+ rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1],
+ IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES);
+
+ if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+ twiceMaxEdgePower = min(twiceMaxEdgePower,
+ twiceMinEdgePower);
+ } else {
+ twiceMaxEdgePower = twiceMinEdgePower;
+ break;
+ }
+ }
+ }
+
+ minCtlPower = min(twiceMaxEdgePower, scaledPower);
+
+ switch (pCtlMode[ctlMode]) {
+ case CTL_11B:
+ for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
+ targetPowerCck.tPow2x[i] =
+ min((u16)targetPowerCck.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11A:
+ case CTL_11G:
+ for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
+ targetPowerOfdm.tPow2x[i] =
+ min((u16)targetPowerOfdm.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_5GHT20:
+ case CTL_2GHT20:
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
+ targetPowerHt20.tPow2x[i] =
+ min((u16)targetPowerHt20.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11B_EXT:
+ targetPowerCckExt.tPow2x[0] = min((u16)
+ targetPowerCckExt.tPow2x[0],
+ minCtlPower);
+ break;
+ case CTL_11A_EXT:
+ case CTL_11G_EXT:
+ targetPowerOfdmExt.tPow2x[0] = min((u16)
+ targetPowerOfdmExt.tPow2x[0],
+ minCtlPower);
+ break;
+ case CTL_5GHT40:
+ case CTL_2GHT40:
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+ targetPowerHt40.tPow2x[i] =
+ min((u16)targetPowerHt40.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
+ ratesArray[rate18mb] = ratesArray[rate24mb] =
+ targetPowerOfdm.tPow2x[0];
+ ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+ ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+ ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+ ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+ ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+ if (IS_CHAN_2GHZ(chan)) {
+ ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+ ratesArray[rate2s] = ratesArray[rate2l] =
+ targetPowerCck.tPow2x[1];
+ ratesArray[rate5_5s] = ratesArray[rate5_5l] =
+ targetPowerCck.tPow2x[2];
+ ratesArray[rate11s] = ratesArray[rate11l] =
+ targetPowerCck.tPow2x[3];
+ }
+ if (IS_CHAN_HT40(chan)) {
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+ ratesArray[rateHt40_0 + i] =
+ targetPowerHt40.tPow2x[i];
+ }
+ ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+ if (IS_CHAN_2GHZ(chan)) {
+ ratesArray[rateExtCck] =
+ targetPowerCckExt.tPow2x[0];
+ }
+ }
+}
+
+static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ u16 cfgCtl,
+ u8 twiceAntennaReduction,
+ u8 twiceMaxRegulatoryPower,
+ u8 powerLimit)
+{
+#define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta)
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
+ struct modal_eep_header *pModal =
+ &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
+ int16_t ratesArray[Ar5416RateSize];
+ int16_t txPowerIndexOffset = 0;
+ u8 ht40PowerIncForPdadc = 2;
+ int i, cck_ofdm_delta = 0;
+
+ memset(ratesArray, 0, sizeof(ratesArray));
+
+ if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+ }
+
+ ath9k_hw_set_def_power_per_rate_table(ah, chan,
+ &ratesArray[0], cfgCtl,
+ twiceAntennaReduction,
+ twiceMaxRegulatoryPower,
+ powerLimit);
+
+ ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset);
+
+ for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+ ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
+ if (ratesArray[i] > AR5416_MAX_RATE_POWER)
+ ratesArray[i] = AR5416_MAX_RATE_POWER;
+ }
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ for (i = 0; i < Ar5416RateSize; i++)
+ ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+ ATH9K_POW_SM(ratesArray[rate18mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate6mb], 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+ ATH9K_POW_SM(ratesArray[rate54mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate24mb], 0));
+
+ if (IS_CHAN_2GHZ(chan)) {
+ if (OLC_FOR_AR9280_20_LATER) {
+ cck_ofdm_delta = 2;
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+ ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24)
+ | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16)
+ | ATH9K_POW_SM(ratesArray[rateXr], 8)
+ | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+ ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24)
+ | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16)
+ | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8)
+ | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0));
+ } else {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+ ATH9K_POW_SM(ratesArray[rate2s], 24)
+ | ATH9K_POW_SM(ratesArray[rate2l], 16)
+ | ATH9K_POW_SM(ratesArray[rateXr], 8)
+ | ATH9K_POW_SM(ratesArray[rate1l], 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+ ATH9K_POW_SM(ratesArray[rate11s], 24)
+ | ATH9K_POW_SM(ratesArray[rate11l], 16)
+ | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+ | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+ }
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+ ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+ ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+
+ if (IS_CHAN_HT40(chan)) {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+ ATH9K_POW_SM(ratesArray[rateHt40_3] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+ ht40PowerIncForPdadc, 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+ ATH9K_POW_SM(ratesArray[rateHt40_7] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+ ht40PowerIncForPdadc, 0));
+ if (OLC_FOR_AR9280_20_LATER) {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+ ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+ | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16)
+ | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+ | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0));
+ } else {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+ ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+ | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+ | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+ | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+ }
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
+ ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
+ | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
+
+ i = rate6mb;
+
+ if (IS_CHAN_HT40(chan))
+ i = rateHt40_0;
+ else if (IS_CHAN_HT20(chan))
+ i = rateHt20_0;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ regulatory->max_power_level =
+ ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
+ else
+ regulatory->max_power_level = ratesArray[i];
+
+ switch(ar5416_get_ntxchains(ah->txchainmask)) {
+ case 1:
+ break;
+ case 2:
+ regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
+ break;
+ case 3:
+ regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Invalid chainmask configuration\n");
+ break;
+ }
+}
+
+static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah,
+ enum ieee80211_band freq_band)
+{
+ struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+ struct modal_eep_header *pModal =
+ &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]);
+ struct base_eep_header *pBase = &eep->baseEepHeader;
+ u8 num_ant_config;
+
+ num_ant_config = 1;
+
+ if (pBase->version >= 0x0E0D)
+ if (pModal->useAnt1)
+ num_ant_config += 1;
+
+ return num_ant_config;
+}
+
+static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+ struct modal_eep_header *pModal =
+ &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+
+ return pModal->antCtrlCommon & 0xFFFF;
+}
+
+static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
+{
+#define EEP_DEF_SPURCHAN \
+ (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan)
+
+ u16 spur_val = AR_NO_SPUR;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Getting spur idx %d is2Ghz. %d val %x\n",
+ i, is2GHz, ah->config.spurchans[i][is2GHz]);
+
+ switch (ah->config.spurmode) {
+ case SPUR_DISABLE:
+ break;
+ case SPUR_ENABLE_IOCTL:
+ spur_val = ah->config.spurchans[i][is2GHz];
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
+ break;
+ case SPUR_ENABLE_EEPROM:
+ spur_val = EEP_DEF_SPURCHAN;
+ break;
+ }
+
+ return spur_val;
+
+#undef EEP_DEF_SPURCHAN
+}
+
+const struct eeprom_ops eep_def_ops = {
+ .check_eeprom = ath9k_hw_def_check_eeprom,
+ .get_eeprom = ath9k_hw_def_get_eeprom,
+ .fill_eeprom = ath9k_hw_def_fill_eeprom,
+ .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver,
+ .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev,
+ .get_num_ant_config = ath9k_hw_def_get_num_ant_config,
+ .get_eeprom_antenna_cfg = ath9k_hw_def_get_eeprom_antenna_cfg,
+ .set_board_values = ath9k_hw_def_set_board_values,
+ .set_addac = ath9k_hw_def_set_addac,
+ .set_txpower = ath9k_hw_def_set_txpower,
+ .get_spur_channel = ath9k_hw_def_get_spur_channel
+};
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 34935a8ee59d..b6c6cca07812 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -16,14 +16,11 @@
#include <linux/io.h>
#include <asm/unaligned.h>
+#include <linux/pci.h>
#include "ath9k.h"
#include "initvals.h"
-static int btcoex_enable;
-module_param(btcoex_enable, bool, 0);
-MODULE_PARM_DESC(btcoex_enable, "Enable Bluetooth coexistence support");
-
#define ATH9K_CLOCK_RATE_CCK 22
#define ATH9K_CLOCK_RATE_5GHZ_OFDM 40
#define ATH9K_CLOCK_RATE_2GHZ_OFDM 44
@@ -380,12 +377,15 @@ static const char *ath9k_hw_devname(u16 devid)
return "Atheros 9280";
case AR9285_DEVID_PCIE:
return "Atheros 9285";
+ case AR5416_DEVID_AR9287_PCI:
+ case AR5416_DEVID_AR9287_PCIE:
+ return "Atheros 9287";
}
return NULL;
}
-static void ath9k_hw_set_defaults(struct ath_hw *ah)
+static void ath9k_hw_init_config(struct ath_hw *ah)
{
int i;
@@ -404,7 +404,7 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah)
ah->config.cck_trig_high = 200;
ah->config.cck_trig_low = 100;
ah->config.enable_ani = 1;
- ah->config.diversity_control = 0;
+ ah->config.diversity_control = ATH9K_ANT_VARIABLE;
ah->config.antenna_switch_swap = 0;
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
@@ -434,37 +434,24 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah)
ah->config.serialize_regmode = SER_REG_MODE_AUTO;
}
-static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
- int *status)
+static void ath9k_hw_init_defaults(struct ath_hw *ah)
{
- struct ath_hw *ah;
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
- ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
- if (ah == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Cannot allocate memory for state block\n");
- *status = -ENOMEM;
- return NULL;
- }
+ regulatory->country_code = CTRY_DEFAULT;
+ regulatory->power_limit = MAX_RATE_POWER;
+ regulatory->tp_scale = ATH9K_TP_SCALE_MAX;
- ah->ah_sc = sc;
ah->hw_version.magic = AR5416_MAGIC;
- ah->regulatory.country_code = CTRY_DEFAULT;
- ah->hw_version.devid = devid;
ah->hw_version.subvendorid = 0;
ah->ah_flags = 0;
- if ((devid == AR5416_AR9100_DEVID))
+ if (ah->hw_version.devid == AR5416_AR9100_DEVID)
ah->hw_version.macVersion = AR_SREV_VERSION_9100;
if (!AR_SREV_9100(ah))
ah->ah_flags = AH_USE_EEPROM;
- ah->regulatory.power_limit = MAX_RATE_POWER;
- ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX;
ah->atim_window = 0;
- ah->diversity_control = ah->config.diversity_control;
- ah->antenna_switch_swap =
- ah->config.antenna_switch_swap;
ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
ah->beacon_interval = 100;
ah->enable_32kHz_clock = DONT_USE_32KHZ;
@@ -475,7 +462,7 @@ static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
ah->gbeacon_rate = 0;
- return ah;
+ ah->power_mode = ATH9K_PM_UNDEFINED;
}
static int ath9k_hw_rfattach(struct ath_hw *ah)
@@ -588,7 +575,7 @@ static void ath9k_hw_init_txgain_ini(struct ath_hw *ah)
}
}
-static int ath9k_hw_post_attach(struct ath_hw *ah)
+static int ath9k_hw_post_init(struct ath_hw *ah)
{
int ecode;
@@ -599,7 +586,7 @@ static int ath9k_hw_post_attach(struct ath_hw *ah)
if (ecode != 0)
return ecode;
- ecode = ath9k_hw_eeprom_attach(ah);
+ ecode = ath9k_hw_eeprom_init(ah);
if (ecode != 0)
return ecode;
@@ -612,70 +599,52 @@ static int ath9k_hw_post_attach(struct ath_hw *ah)
if (!AR_SREV_9100(ah)) {
ath9k_hw_ani_setup(ah);
- ath9k_hw_ani_attach(ah);
+ ath9k_hw_ani_init(ah);
}
return 0;
}
-static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
- int *status)
+static bool ath9k_hw_devid_supported(u16 devid)
{
- struct ath_hw *ah;
- int ecode;
- u32 i, j;
-
- ah = ath9k_hw_newstate(devid, sc, status);
- if (ah == NULL)
- return NULL;
-
- ath9k_hw_set_defaults(ah);
-
- if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
- DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n");
- ecode = -EIO;
- goto bad;
- }
-
- if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
- DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
- ecode = -EIO;
- goto bad;
- }
-
- if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
- if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
- (AR_SREV_9280(ah) && !ah->is_pciexpress)) {
- ah->config.serialize_regmode =
- SER_REG_MODE_ON;
- } else {
- ah->config.serialize_regmode =
- SER_REG_MODE_OFF;
- }
- }
-
- DPRINTF(sc, ATH_DBG_RESET, "serialize_regmode is %d\n",
- ah->config.serialize_regmode);
-
- if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) &&
- (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) &&
- (ah->hw_version.macVersion != AR_SREV_VERSION_9160) &&
- (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Mac Chip Rev 0x%02x.%x is not supported by "
- "this driver\n", ah->hw_version.macVersion,
- ah->hw_version.macRev);
- ecode = -EOPNOTSUPP;
- goto bad;
+ switch (devid) {
+ case AR5416_DEVID_PCI:
+ case AR5416_DEVID_PCIE:
+ case AR5416_AR9100_DEVID:
+ case AR9160_DEVID_PCI:
+ case AR9280_DEVID_PCI:
+ case AR9280_DEVID_PCIE:
+ case AR9285_DEVID_PCIE:
+ case AR5416_DEVID_AR9287_PCI:
+ case AR5416_DEVID_AR9287_PCIE:
+ return true;
+ default:
+ break;
}
+ return false;
+}
- if (AR_SREV_9100(ah)) {
- ah->iq_caldata.calData = &iq_cal_multi_sample;
- ah->supp_cals = IQ_MISMATCH_CAL;
- ah->is_pciexpress = false;
+static bool ath9k_hw_macversion_supported(u32 macversion)
+{
+ switch (macversion) {
+ case AR_SREV_VERSION_5416_PCI:
+ case AR_SREV_VERSION_5416_PCIE:
+ case AR_SREV_VERSION_9160:
+ case AR_SREV_VERSION_9100:
+ case AR_SREV_VERSION_9280:
+ case AR_SREV_VERSION_9285:
+ case AR_SREV_VERSION_9287:
+ return true;
+ /* Not yet */
+ case AR_SREV_VERSION_9271:
+ default:
+ break;
}
- ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
+ return false;
+}
+static void ath9k_hw_init_cal_settings(struct ath_hw *ah)
+{
if (AR_SREV_9160_10_OR_LATER(ah)) {
if (AR_SREV_9280_10_OR_LATER(ah)) {
ah->iq_caldata.calData = &iq_cal_single_sample;
@@ -696,12 +665,49 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
}
ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
}
+}
- ah->ani_function = ATH9K_ANI_ALL;
- if (AR_SREV_9280_10_OR_LATER(ah))
- ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+static void ath9k_hw_init_mode_regs(struct ath_hw *ah)
+{
+ if (AR_SREV_9271(ah)) {
+ INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271_1_0,
+ ARRAY_SIZE(ar9271Modes_9271_1_0), 6);
+ INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271_1_0,
+ ARRAY_SIZE(ar9271Common_9271_1_0), 2);
+ return;
+ }
+
+ if (AR_SREV_9287_11_OR_LATER(ah)) {
+ INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1,
+ ARRAY_SIZE(ar9287Modes_9287_1_1), 6);
+ INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1,
+ ARRAY_SIZE(ar9287Common_9287_1_1), 2);
+ if (ah->config.pcie_clock_req)
+ INIT_INI_ARRAY(&ah->iniPcieSerdes,
+ ar9287PciePhy_clkreq_off_L1_9287_1_1,
+ ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2);
+ else
+ INIT_INI_ARRAY(&ah->iniPcieSerdes,
+ ar9287PciePhy_clkreq_always_on_L1_9287_1_1,
+ ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1),
+ 2);
+ } else if (AR_SREV_9287_10_OR_LATER(ah)) {
+ INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_0,
+ ARRAY_SIZE(ar9287Modes_9287_1_0), 6);
+ INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_0,
+ ARRAY_SIZE(ar9287Common_9287_1_0), 2);
+
+ if (ah->config.pcie_clock_req)
+ INIT_INI_ARRAY(&ah->iniPcieSerdes,
+ ar9287PciePhy_clkreq_off_L1_9287_1_0,
+ ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_0), 2);
+ else
+ INIT_INI_ARRAY(&ah->iniPcieSerdes,
+ ar9287PciePhy_clkreq_always_on_L1_9287_1_0,
+ ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_0),
+ 2);
+ } else if (AR_SREV_9285_12_OR_LATER(ah)) {
- if (AR_SREV_9285_12_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
@@ -832,17 +838,32 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac,
ARRAY_SIZE(ar5416Addac), 2);
}
+}
- if (ah->is_pciexpress)
- ath9k_hw_configpcipowersave(ah, 0);
- else
- ath9k_hw_disablepcie(ah);
-
- ecode = ath9k_hw_post_attach(ah);
- if (ecode != 0)
- goto bad;
+static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
+{
+ if (AR_SREV_9287_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9287Modes_rx_gain_9287_1_1,
+ ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6);
+ else if (AR_SREV_9287_10(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9287Modes_rx_gain_9287_1_0,
+ ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_0), 6);
+ else if (AR_SREV_9280_20(ah))
+ ath9k_hw_init_rxgain_ini(ah);
- if (AR_SREV_9285_12_OR_LATER(ah)) {
+ if (AR_SREV_9287_11(ah)) {
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9287Modes_tx_gain_9287_1_1,
+ ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6);
+ } else if (AR_SREV_9287_10(ah)) {
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9287Modes_tx_gain_9287_1_0,
+ ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_0), 6);
+ } else if (AR_SREV_9280_20(ah)) {
+ ath9k_hw_init_txgain_ini(ah);
+ } else if (AR_SREV_9285_12_OR_LATER(ah)) {
u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
/* txgain table */
@@ -857,16 +878,11 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
}
}
+}
- /* rxgain table */
- if (AR_SREV_9280_20(ah))
- ath9k_hw_init_rxgain_ini(ah);
-
- /* txgain table */
- if (AR_SREV_9280_20(ah))
- ath9k_hw_init_txgain_ini(ah);
-
- ath9k_hw_fill_cap_info(ah);
+static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah)
+{
+ u32 i, j;
if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) {
@@ -885,29 +901,97 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
}
}
}
+}
+
+int ath9k_hw_init(struct ath_hw *ah)
+{
+ int r = 0;
+
+ if (!ath9k_hw_devid_supported(ah->hw_version.devid))
+ return -EOPNOTSUPP;
+
+ ath9k_hw_init_defaults(ah);
+ ath9k_hw_init_config(ah);
+
+ if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n");
+ return -EIO;
+ }
+
+ if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
+ return -EIO;
+ }
+
+ if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
+ if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
+ (AR_SREV_9280(ah) && !ah->is_pciexpress)) {
+ ah->config.serialize_regmode =
+ SER_REG_MODE_ON;
+ } else {
+ ah->config.serialize_regmode =
+ SER_REG_MODE_OFF;
+ }
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n",
+ ah->config.serialize_regmode);
+
+ if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Mac Chip Rev 0x%02x.%x is not supported by "
+ "this driver\n", ah->hw_version.macVersion,
+ ah->hw_version.macRev);
+ return -EOPNOTSUPP;
+ }
+
+ if (AR_SREV_9100(ah)) {
+ ah->iq_caldata.calData = &iq_cal_multi_sample;
+ ah->supp_cals = IQ_MISMATCH_CAL;
+ ah->is_pciexpress = false;
+ }
+
+ if (AR_SREV_9271(ah))
+ ah->is_pciexpress = false;
+
+ ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
+
+ ath9k_hw_init_cal_settings(ah);
+
+ ah->ani_function = ATH9K_ANI_ALL;
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
- ecode = ath9k_hw_init_macaddr(ah);
- if (ecode != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
+ ath9k_hw_init_mode_regs(ah);
+
+ if (ah->is_pciexpress)
+ ath9k_hw_configpcipowersave(ah, 0);
+ else
+ ath9k_hw_disablepcie(ah);
+
+ r = ath9k_hw_post_init(ah);
+ if (r)
+ return r;
+
+ ath9k_hw_init_mode_gain_regs(ah);
+ ath9k_hw_fill_cap_info(ah);
+ ath9k_hw_init_11a_eeprom_fix(ah);
+
+ r = ath9k_hw_init_macaddr(ah);
+ if (r) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"Failed to initialize MAC address\n");
- goto bad;
+ return r;
}
- if (AR_SREV_9285(ah))
+ if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S);
else
ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
ath9k_init_nfcal_hist_buffer(ah);
- return ah;
-bad:
- if (ah)
- ath9k_hw_detach(ah);
- if (status)
- *status = ecode;
-
- return NULL;
+ return 0;
}
static void ath9k_hw_init_bb(struct ath_hw *ah,
@@ -1146,33 +1230,12 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid)
void ath9k_hw_detach(struct ath_hw *ah)
{
if (!AR_SREV_9100(ah))
- ath9k_hw_ani_detach(ah);
+ ath9k_hw_ani_disable(ah);
- ath9k_hw_rfdetach(ah);
+ ath9k_hw_rf_free(ah);
ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
kfree(ah);
-}
-
-struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error)
-{
- struct ath_hw *ah = NULL;
-
- switch (devid) {
- case AR5416_DEVID_PCI:
- case AR5416_DEVID_PCIE:
- case AR5416_AR9100_DEVID:
- case AR9160_DEVID_PCI:
- case AR9280_DEVID_PCI:
- case AR9280_DEVID_PCIE:
- case AR9285_DEVID_PCIE:
- ah = ath9k_hw_do_attach(devid, sc, error);
- break;
- default:
- *error = -ENXIO;
- break;
- }
-
- return ah;
+ ah = NULL;
}
/*******/
@@ -1182,6 +1245,27 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error)
static void ath9k_hw_override_ini(struct ath_hw *ah,
struct ath9k_channel *chan)
{
+ u32 val;
+
+ if (AR_SREV_9271(ah)) {
+ /*
+ * Enable spectral scan to solution for issues with stuck
+ * beacons on AR9271 1.0. The beacon stuck issue is not seeon on
+ * AR9271 1.1
+ */
+ if (AR_SREV_9271_10(ah)) {
+ val = REG_READ(ah, AR_PHY_SPECTRAL_SCAN) | AR_PHY_SPECTRAL_SCAN_ENABLE;
+ REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val);
+ }
+ else if (AR_SREV_9271_11(ah))
+ /*
+ * change AR_PHY_RF_CTL3 setting to fix MAC issue
+ * present on AR9271 1.1
+ */
+ REG_WRITE(ah, AR_PHY_RF_CTL3, 0x3a020001);
+ return;
+ }
+
/*
* Set the RX_ABORT and RX_DIS and clear if off only after
* RXE is set for MAC. This prevents frames with corrupted
@@ -1193,7 +1277,10 @@ static void ath9k_hw_override_ini(struct ath_hw *ah,
if (!AR_SREV_5416_20_OR_LATER(ah) ||
AR_SREV_9280_10_OR_LATER(ah))
return;
-
+ /*
+ * Disable BB clock gating
+ * Necessary to avoid issues on AR5416 2.0
+ */
REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
}
@@ -1245,11 +1332,21 @@ static void ath9k_olc_init(struct ath_hw *ah)
{
u32 i;
- for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++)
- ah->originalGain[i] =
- MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4),
- AR_PHY_TX_GAIN);
- ah->PDADCdelta = 0;
+ if (OLC_FOR_AR9287_10_LATER) {
+ REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9,
+ AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TXPC0,
+ AR9287_AN_TXPC0_TXPCMODE,
+ AR9287_AN_TXPC0_TXPCMODE_S,
+ AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE);
+ udelay(100);
+ } else {
+ for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++)
+ ah->originalGain[i] =
+ MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4),
+ AR_PHY_TX_GAIN);
+ ah->PDADCdelta = 0;
+ }
}
static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg,
@@ -1271,6 +1368,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
struct ath9k_channel *chan,
enum ath9k_ht_macmode macmode)
{
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
int i, regWrites = 0;
struct ieee80211_channel *channel = chan->chan;
u32 modesIndex, freqIndex;
@@ -1341,10 +1439,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
DO_DELAY(regWrites);
}
- if (AR_SREV_9280(ah))
+ if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah))
REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
- if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah))
+ if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) ||
+ AR_SREV_9287_10_OR_LATER(ah))
REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
for (i = 0; i < ah->iniCommon.ia_rows; i++) {
@@ -1376,11 +1475,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
ath9k_olc_init(ah);
ah->eep_ops->set_txpower(ah, chan,
- ath9k_regd_get_ctl(&ah->regulatory, chan),
+ ath9k_regd_get_ctl(regulatory, chan),
channel->max_antenna_gain * 2,
channel->max_power * 2,
min((u32) MAX_RATE_POWER,
- (u32) ah->regulatory.power_limit));
+ (u32) regulatory->power_limit));
if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
@@ -1424,23 +1523,48 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
{
u32 regval;
+ /*
+ * set AHB_MODE not to do cacheline prefetches
+ */
regval = REG_READ(ah, AR_AHB_MODE);
REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
+ /*
+ * let mac dma reads be in 128 byte chunks
+ */
regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
+ /*
+ * Restore TX Trigger Level to its pre-reset value.
+ * The initial value depends on whether aggregation is enabled, and is
+ * adjusted whenever underruns are detected.
+ */
REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level);
+ /*
+ * let mac dma writes be in 128 byte chunks
+ */
regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
+ /*
+ * Setup receive FIFO threshold to hold off TX activities
+ */
REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
+ /*
+ * reduce the number of usable entries in PCU TXBUF to avoid
+ * wrap around issues.
+ */
if (AR_SREV_9285(ah)) {
+ /* For AR9285 the number of Fifos are reduced to half.
+ * So set the usable tx buf size also to half to
+ * avoid data/delimiter underruns
+ */
REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);
- } else {
+ } else if (!AR_SREV_9271(ah)) {
REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
AR_PCU_TXBUF_CTRL_USABLE_SIZE);
}
@@ -1585,8 +1709,15 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
AR_RTC_FORCE_WAKE_ON_INT);
+ if (!AR_SREV_9100(ah))
+ REG_WRITE(ah, AR_RC, AR_RC_AHB);
+
REG_WRITE(ah, AR_RTC_RESET, 0);
udelay(2);
+
+ if (!AR_SREV_9100(ah))
+ REG_WRITE(ah, AR_RC, 0);
+
REG_WRITE(ah, AR_RTC_RESET, 1);
if (!ath9k_hw_wait(ah,
@@ -1673,6 +1804,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
struct ath9k_channel *chan,
enum ath9k_ht_macmode macmode)
{
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ieee80211_channel *channel = chan->chan;
u32 synthDelay, qnum;
@@ -1705,11 +1837,11 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
}
ah->eep_ops->set_txpower(ah, chan,
- ath9k_regd_get_ctl(&ah->regulatory, chan),
+ ath9k_regd_get_ctl(regulatory, chan),
channel->max_antenna_gain * 2,
channel->max_power * 2,
min((u32) MAX_RATE_POWER,
- (u32) ah->regulatory.power_limit));
+ (u32) regulatory->power_limit));
synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
if (IS_CHAN_B(chan))
@@ -2246,14 +2378,39 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_mark_phy_inactive(ah);
+ if (AR_SREV_9271(ah) && ah->htc_reset_init) {
+ REG_WRITE(ah,
+ AR9271_RESET_POWER_DOWN_CONTROL,
+ AR9271_RADIO_RF_RST);
+ udelay(50);
+ }
+
if (!ath9k_hw_chip_reset(ah, chan)) {
DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n");
return -EINVAL;
}
+ if (AR_SREV_9271(ah) && ah->htc_reset_init) {
+ ah->htc_reset_init = false;
+ REG_WRITE(ah,
+ AR9271_RESET_POWER_DOWN_CONTROL,
+ AR9271_GATE_MAC_CTL);
+ udelay(50);
+ }
+
if (AR_SREV_9280_10_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
+ if (AR_SREV_9287_12_OR_LATER(ah)) {
+ /* Enable ASYNC FIFO */
+ REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+ AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
+ REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
+ REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+ AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+ REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+ AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+ }
r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width);
if (r)
return r;
@@ -2330,6 +2487,27 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_init_user_settings(ah);
+ if (AR_SREV_9287_12_OR_LATER(ah)) {
+ REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
+ AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
+ REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
+ AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR);
+ REG_WRITE(ah, AR_D_GBL_IFS_EIFS,
+ AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR);
+
+ REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR);
+ REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR);
+
+ REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,
+ AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
+ REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
+ AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
+ }
+ if (AR_SREV_9287_12_OR_LATER(ah)) {
+ REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
+ AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
+ }
+
REG_WRITE(ah, AR_STA_ID1,
REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
@@ -2345,7 +2523,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_init_bb(ah, chan);
if (!ath9k_hw_init_cal(ah, chan))
- return -EIO;;
+ return -EIO;
rx_chainmask = ah->rxchainmask;
if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
@@ -2355,6 +2533,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ);
+ /*
+ * For big endian systems turn on swapping for descriptors
+ */
if (AR_SREV_9100(ah)) {
u32 mask;
mask = REG_READ(ah, AR_CFG);
@@ -2369,11 +2550,18 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
"Setting CFG 0x%x\n", REG_READ(ah, AR_CFG));
}
} else {
+ /* Configure AR9271 target WLAN */
+ if (AR_SREV_9271(ah))
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
#ifdef __BIG_ENDIAN
- REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+ else
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
#endif
}
+ if (ah->ah_sc->sc_flags & SC_OP_BTCOEX_ENABLED)
+ ath9k_hw_btcoex_enable(ah);
+
return 0;
}
@@ -2412,9 +2600,6 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
}
- if (ah->curchan == NULL)
- return true;
-
return true;
}
@@ -2728,7 +2913,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
return true;
}
-bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
+ enum ath9k_power_mode mode)
{
int status = true, setChip = true;
static const char *modes[] = {
@@ -2738,6 +2924,9 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
"UNDEFINED"
};
+ if (ah->power_mode == mode)
+ return status;
+
DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n",
modes[ah->power_mode], modes[mode]);
@@ -2762,6 +2951,51 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
return status;
}
+bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+{
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags);
+ ret = ath9k_hw_setpower_nolock(ah, mode);
+ spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags);
+
+ return ret;
+}
+
+void ath9k_ps_wakeup(struct ath_softc *sc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (++sc->ps_usecount != 1)
+ goto unlock;
+
+ ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
+
+ unlock:
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
+void ath9k_ps_restore(struct ath_softc *sc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (--sc->ps_usecount != 0)
+ goto unlock;
+
+ if (sc->ps_enabled &&
+ !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+ SC_OP_WAIT_FOR_CAB |
+ SC_OP_WAIT_FOR_PSPOLL_DATA |
+ SC_OP_WAIT_FOR_TX_ACK)))
+ ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
+
+ unlock:
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
/*
* Helper for ASPM support.
*
@@ -2790,7 +3024,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore)
/*
* AR9280 2.0 or later chips use SerDes values from the
* initvals.h initialized depending on chipset during
- * ath9k_hw_do_attach()
+ * ath9k_hw_init()
*/
for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) {
REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
@@ -2851,7 +3085,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore)
if (ah->config.pcie_waen) {
REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
} else {
- if (AR_SREV_9285(ah))
+ if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah))
REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT);
/*
* On AR9280 chips bit 22 of 0x4004 needs to be set to
@@ -2985,6 +3219,23 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
if (AR_SREV_9100(ah))
return true;
+ if (isr & AR_ISR_GENTMR) {
+ u32 s5_s;
+
+ s5_s = REG_READ(ah, AR_ISR_S5_S);
+ if (isr & AR_ISR_GENTMR) {
+ ah->intr_gen_timer_trigger =
+ MS(s5_s, AR_ISR_S5_GENTIMER_TRIG);
+
+ ah->intr_gen_timer_thresh =
+ MS(s5_s, AR_ISR_S5_GENTIMER_THRESH);
+
+ if (ah->intr_gen_timer_trigger)
+ *masked |= ATH9K_INT_GENTIMER;
+
+ }
+ }
+
if (sync_cause) {
fatal_int =
(sync_cause &
@@ -3021,11 +3272,6 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
return true;
}
-enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah)
-{
- return ah->mask_reg;
-}
-
enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
{
u32 omask = ah->mask_reg;
@@ -3263,27 +3509,30 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
void ath9k_hw_fill_cap_info(struct ath_hw *ah)
{
struct ath9k_hw_capabilities *pCap = &ah->caps;
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
+
u16 capField = 0, eeval;
eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
- ah->regulatory.current_rd = eeval;
+ regulatory->current_rd = eeval;
eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1);
if (AR_SREV_9285_10_OR_LATER(ah))
eeval |= AR9285_RDEXT_DEFAULT;
- ah->regulatory.current_rd_ext = eeval;
+ regulatory->current_rd_ext = eeval;
capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP);
if (ah->opmode != NL80211_IFTYPE_AP &&
ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) {
- if (ah->regulatory.current_rd == 0x64 ||
- ah->regulatory.current_rd == 0x65)
- ah->regulatory.current_rd += 5;
- else if (ah->regulatory.current_rd == 0x41)
- ah->regulatory.current_rd = 0x43;
+ if (regulatory->current_rd == 0x64 ||
+ regulatory->current_rd == 0x65)
+ regulatory->current_rd += 5;
+ else if (regulatory->current_rd == 0x41)
+ regulatory->current_rd = 0x43;
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "regdomain mapped to 0x%x\n", ah->regulatory.current_rd);
+ "regdomain mapped to 0x%x\n", regulatory->current_rd);
}
eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
@@ -3305,7 +3554,6 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
}
if (eeval & AR5416_OPFLAGS_11G) {
- set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
if (ah->config.ht_enable) {
if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
@@ -3321,10 +3569,17 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
}
pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK);
+ /*
+ * For AR9271 we will temporarilly uses the rx chainmax as read from
+ * the EEPROM.
+ */
if ((ah->hw_version.devid == AR5416_DEVID_PCI) &&
- !(eeval & AR5416_OPFLAGS_11A))
+ !(eeval & AR5416_OPFLAGS_11A) &&
+ !(AR_SREV_9271(ah)))
+ /* CB71: GPIO 0 is pulled down to indicate 3 rx chains */
pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7;
else
+ /* Use rx_chainmask from EEPROM. */
pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK);
if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0)))
@@ -3412,7 +3667,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
else
pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
- if (ah->regulatory.current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) {
+ if (regulatory->current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) {
pCap->reg_cap =
AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
@@ -3431,16 +3686,26 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->num_antcfg_2ghz =
ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
- if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) {
- pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX;
- ah->btactive_gpio = 6;
- ah->wlanactive_gpio = 5;
+ if (AR_SREV_9280_10_OR_LATER(ah) &&
+ ath_btcoex_supported(ah->hw_version.subsysid)) {
+ btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO;
+ btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
+
+ if (AR_SREV_9285(ah)) {
+ btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_3WIRE;
+ btcoex_info->btpriority_gpio = ATH_BTPRIORITY_GPIO;
+ } else {
+ btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_2WIRE;
+ }
+ } else {
+ btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_NONE;
}
}
bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
u32 capability, u32 *result)
{
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
switch (type) {
case ATH9K_CAP_CIPHER:
switch (capability) {
@@ -3489,13 +3754,13 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
case 0:
return 0;
case 1:
- *result = ah->regulatory.power_limit;
+ *result = regulatory->power_limit;
return 0;
case 2:
- *result = ah->regulatory.max_power_level;
+ *result = regulatory->max_power_level;
return 0;
case 3:
- *result = ah->regulatory.tp_scale;
+ *result = regulatory->tp_scale;
return 0;
}
return false;
@@ -3595,7 +3860,9 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
if (gpio >= ah->caps.num_gpio_pins)
return 0xffffffff;
- if (AR_SREV_9285_10_OR_LATER(ah))
+ if (AR_SREV_9287_10_OR_LATER(ah))
+ return MS_REG_READ(AR9287, gpio) != 0;
+ else if (AR_SREV_9285_10_OR_LATER(ah))
return MS_REG_READ(AR9285, gpio) != 0;
else if (AR_SREV_9280_10_OR_LATER(ah))
return MS_REG_READ(AR928X, gpio) != 0;
@@ -3673,7 +3940,7 @@ bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
break;
}
} else {
- ah->diversity_control = settings;
+ ah->config.diversity_control = settings;
}
return true;
@@ -3700,7 +3967,8 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
{
u32 phybits;
- REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR);
+ REG_WRITE(ah, AR_RX_FILTER, bits);
+
phybits = 0;
if (bits & ATH9K_RX_FILTER_PHYRADAR)
phybits |= AR_PHY_ERR_RADAR;
@@ -3731,17 +3999,18 @@ bool ath9k_hw_disable(struct ath_hw *ah)
void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
{
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ath9k_channel *chan = ah->curchan;
struct ieee80211_channel *channel = chan->chan;
- ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER);
+ regulatory->power_limit = min(limit, (u32) MAX_RATE_POWER);
ah->eep_ops->set_txpower(ah, chan,
- ath9k_regd_get_ctl(&ah->regulatory, chan),
+ ath9k_regd_get_ctl(regulatory, chan),
channel->max_antenna_gain * 2,
channel->max_power * 2,
min((u32) MAX_RATE_POWER,
- (u32) ah->regulatory.power_limit));
+ (u32) regulatory->power_limit));
}
void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac)
@@ -3791,29 +4060,22 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64)
void ath9k_hw_reset_tsf(struct ath_hw *ah)
{
- int count;
+ ath9k_ps_wakeup(ah->ah_sc);
+ if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0,
+ AH_TSF_WRITE_TIMEOUT))
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
- count = 0;
- while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
- count++;
- if (count > 10) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
- break;
- }
- udelay(10);
- }
REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
+ ath9k_ps_restore(ah->ah_sc);
}
-bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
+void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
{
if (setting)
ah->misc_mode |= AR_PCU_TX_ADD_TSF;
else
ah->misc_mode &= ~AR_PCU_TX_ADD_TSF;
-
- return true;
}
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
@@ -3842,29 +4104,210 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode)
REG_WRITE(ah, AR_2040_MODE, macmode);
}
-/***************************/
-/* Bluetooth Coexistence */
-/***************************/
+/* HW Generic timers configuration */
-void ath9k_hw_btcoex_enable(struct ath_hw *ah)
+static const struct ath_gen_timer_configuration gen_tmr_configuration[] =
+{
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP2_TIMER, AR_NDP2_PERIOD, AR_NDP2_TIMER_MODE, 0x0001},
+ {AR_NEXT_NDP2_TIMER + 1*4, AR_NDP2_PERIOD + 1*4,
+ AR_NDP2_TIMER_MODE, 0x0002},
+ {AR_NEXT_NDP2_TIMER + 2*4, AR_NDP2_PERIOD + 2*4,
+ AR_NDP2_TIMER_MODE, 0x0004},
+ {AR_NEXT_NDP2_TIMER + 3*4, AR_NDP2_PERIOD + 3*4,
+ AR_NDP2_TIMER_MODE, 0x0008},
+ {AR_NEXT_NDP2_TIMER + 4*4, AR_NDP2_PERIOD + 4*4,
+ AR_NDP2_TIMER_MODE, 0x0010},
+ {AR_NEXT_NDP2_TIMER + 5*4, AR_NDP2_PERIOD + 5*4,
+ AR_NDP2_TIMER_MODE, 0x0020},
+ {AR_NEXT_NDP2_TIMER + 6*4, AR_NDP2_PERIOD + 6*4,
+ AR_NDP2_TIMER_MODE, 0x0040},
+ {AR_NEXT_NDP2_TIMER + 7*4, AR_NDP2_PERIOD + 7*4,
+ AR_NDP2_TIMER_MODE, 0x0080}
+};
+
+/* HW generic timer primitives */
+
+/* compute and clear index of rightmost 1 */
+static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask)
{
- /* connect bt_active to baseband */
- REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
- AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
+ u32 b;
- REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
+ b = *mask;
+ b &= (0-b);
+ *mask &= ~b;
+ b *= debruijn32;
+ b >>= 27;
+
+ return timer_table->gen_timer_index[b];
+}
+
+u32 ath9k_hw_gettsf32(struct ath_hw *ah)
+{
+ return REG_READ(ah, AR_TSF_L32);
+}
+
+struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
+ void (*trigger)(void *),
+ void (*overflow)(void *),
+ void *arg,
+ u8 timer_index)
+{
+ struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+ struct ath_gen_timer *timer;
+
+ timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL);
+
+ if (timer == NULL) {
+ printk(KERN_DEBUG "Failed to allocate memory"
+ "for hw timer[%d]\n", timer_index);
+ return NULL;
+ }
+
+ /* allocate a hardware generic timer slot */
+ timer_table->timers[timer_index] = timer;
+ timer->index = timer_index;
+ timer->trigger = trigger;
+ timer->overflow = overflow;
+ timer->arg = arg;
- /* Set input mux for bt_active to gpio pin */
- REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
- AR_GPIO_INPUT_MUX1_BT_ACTIVE,
- ah->btactive_gpio);
+ return timer;
+}
+
+void ath_gen_timer_start(struct ath_hw *ah,
+ struct ath_gen_timer *timer,
+ u32 timer_next, u32 timer_period)
+{
+ struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+ u32 tsf;
+
+ BUG_ON(!timer_period);
+
+ set_bit(timer->index, &timer_table->timer_mask.timer_bits);
+
+ tsf = ath9k_hw_gettsf32(ah);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, "curent tsf %x period %x"
+ "timer_next %x\n", tsf, timer_period, timer_next);
+
+ /*
+ * Pull timer_next forward if the current TSF already passed it
+ * because of software latency
+ */
+ if (timer_next < tsf)
+ timer_next = tsf + timer_period;
+
+ /*
+ * Program generic timer registers
+ */
+ REG_WRITE(ah, gen_tmr_configuration[timer->index].next_addr,
+ timer_next);
+ REG_WRITE(ah, gen_tmr_configuration[timer->index].period_addr,
+ timer_period);
+ REG_SET_BIT(ah, gen_tmr_configuration[timer->index].mode_addr,
+ gen_tmr_configuration[timer->index].mode_mask);
+
+ /* Enable both trigger and thresh interrupt masks */
+ REG_SET_BIT(ah, AR_IMR_S5,
+ (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
+ SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
+
+ if ((ah->ah_sc->imask & ATH9K_INT_GENTIMER) == 0) {
+ ath9k_hw_set_interrupts(ah, 0);
+ ah->ah_sc->imask |= ATH9K_INT_GENTIMER;
+ ath9k_hw_set_interrupts(ah, ah->ah_sc->imask);
+ }
+}
+
+void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
+{
+ struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+
+ if ((timer->index < AR_FIRST_NDP_TIMER) ||
+ (timer->index >= ATH_MAX_GEN_TIMER)) {
+ return;
+ }
+
+ /* Clear generic timer enable bits. */
+ REG_CLR_BIT(ah, gen_tmr_configuration[timer->index].mode_addr,
+ gen_tmr_configuration[timer->index].mode_mask);
- /* Configure the desired gpio port for input */
- ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio);
+ /* Disable both trigger and thresh interrupt masks */
+ REG_CLR_BIT(ah, AR_IMR_S5,
+ (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
+ SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
+
+ clear_bit(timer->index, &timer_table->timer_mask.timer_bits);
+
+ /* if no timer is enabled, turn off interrupt mask */
+ if (timer_table->timer_mask.val == 0) {
+ ath9k_hw_set_interrupts(ah, 0);
+ ah->ah_sc->imask &= ~ATH9K_INT_GENTIMER;
+ ath9k_hw_set_interrupts(ah, ah->ah_sc->imask);
+ }
+}
+
+void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer)
+{
+ struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+
+ /* free the hardware generic timer slot */
+ timer_table->timers[timer->index] = NULL;
+ kfree(timer);
+}
+
+/*
+ * Generic Timer Interrupts handling
+ */
+void ath_gen_timer_isr(struct ath_hw *ah)
+{
+ struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+ struct ath_gen_timer *timer;
+ u32 trigger_mask, thresh_mask, index;
+
+ /* get hardware generic timer interrupt status */
+ trigger_mask = ah->intr_gen_timer_trigger;
+ thresh_mask = ah->intr_gen_timer_thresh;
+ trigger_mask &= timer_table->timer_mask.val;
+ thresh_mask &= timer_table->timer_mask.val;
+
+ trigger_mask &= ~thresh_mask;
+
+ while (thresh_mask) {
+ index = rightmost_index(timer_table, &thresh_mask);
+ timer = timer_table->timers[index];
+ BUG_ON(!timer);
+ DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER,
+ "TSF overflow for Gen timer %d\n", index);
+ timer->overflow(timer->arg);
+ }
+
+ while (trigger_mask) {
+ index = rightmost_index(timer_table, &trigger_mask);
+ timer = timer_table->timers[index];
+ BUG_ON(!timer);
+ DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER,
+ "Gen timer[%d] trigger\n", index);
+ timer->trigger(timer->arg);
+ }
+}
+
+/*
+ * Primitive to disable ASPM
+ */
+void ath_pcie_aspm_disable(struct ath_softc *sc)
+{
+ struct pci_dev *pdev = to_pci_dev(sc->dev);
+ u8 aspm;
- /* Configure the desired GPIO port for TX_FRAME output */
- ath9k_hw_cfg_output(ah, ah->wlanactive_gpio,
- AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
+ pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm);
+ aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1);
+ pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm);
}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 9d0b31ad4603..9106a0b537dd 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -42,6 +42,13 @@
#define AR_SUBVENDOR_ID_NEW_A 0x7065
#define AR5416_MAGIC 0x19641014
+#define AR5416_DEVID_AR9287_PCI 0x002D
+#define AR5416_DEVID_AR9287_PCIE 0x002E
+
+#define AR9280_COEX2WIRE_SUBSYSID 0x309b
+#define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa
+#define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab
+
/* Register read/write primitives */
#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val))
#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg))
@@ -76,6 +83,7 @@
#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2
#define AR_GPIO_OUTPUT_MUX_AS_TX_FRAME 3
+#define AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL 4
#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5
#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6
@@ -95,6 +103,7 @@
#define MAX_RATE_POWER 63
#define AH_WAIT_TIMEOUT 100000 /* (us) */
+#define AH_TSF_WRITE_TIMEOUT 100 /* (us) */
#define AH_TIME_QUANTUM 10
#define AR_KEYTABLE_SIZE 128
#define POWER_UP_TIME 200000
@@ -113,15 +122,20 @@
enum wireless_mode {
ATH9K_MODE_11A = 0,
- ATH9K_MODE_11B = 2,
- ATH9K_MODE_11G = 3,
- ATH9K_MODE_11NA_HT20 = 6,
- ATH9K_MODE_11NG_HT20 = 7,
- ATH9K_MODE_11NA_HT40PLUS = 8,
- ATH9K_MODE_11NA_HT40MINUS = 9,
- ATH9K_MODE_11NG_HT40PLUS = 10,
- ATH9K_MODE_11NG_HT40MINUS = 11,
- ATH9K_MODE_MAX
+ ATH9K_MODE_11G,
+ ATH9K_MODE_11NA_HT20,
+ ATH9K_MODE_11NG_HT20,
+ ATH9K_MODE_11NA_HT40PLUS,
+ ATH9K_MODE_11NA_HT40MINUS,
+ ATH9K_MODE_11NG_HT40PLUS,
+ ATH9K_MODE_11NG_HT40MINUS,
+ ATH9K_MODE_MAX,
+};
+
+enum ath9k_ant_setting {
+ ATH9K_ANT_VARIABLE = 0,
+ ATH9K_ANT_FIXED_A,
+ ATH9K_ANT_FIXED_B
};
enum ath9k_hw_caps {
@@ -142,7 +156,6 @@ enum ath9k_hw_caps {
ATH9K_HW_CAP_ENHANCEDPM = BIT(14),
ATH9K_HW_CAP_AUTOSLEEP = BIT(15),
ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16),
- ATH9K_HW_CAP_BT_COEX = BIT(17)
};
enum ath9k_capability_type {
@@ -188,7 +201,7 @@ struct ath9k_ops_config {
u32 cck_trig_high;
u32 cck_trig_low;
u32 enable_ani;
- u16 diversity_control;
+ enum ath9k_ant_setting diversity_control;
u16 antenna_switch_swap;
int serialize_regmode;
bool intr_mitigation;
@@ -229,6 +242,7 @@ enum ath9k_int {
ATH9K_INT_GPIO = 0x01000000,
ATH9K_INT_CABEND = 0x02000000,
ATH9K_INT_TSFOOR = 0x04000000,
+ ATH9K_INT_GENTIMER = 0x08000000,
ATH9K_INT_CST = 0x10000000,
ATH9K_INT_GTT = 0x20000000,
ATH9K_INT_FATAL = 0x40000000,
@@ -327,12 +341,6 @@ enum ath9k_power_mode {
ATH9K_PM_UNDEFINED
};
-enum ath9k_ant_setting {
- ATH9K_ANT_VARIABLE = 0,
- ATH9K_ANT_FIXED_A,
- ATH9K_ANT_FIXED_B
-};
-
enum ath9k_tp_scale {
ATH9K_TP_SCALE_MAX = 0,
ATH9K_TP_SCALE_50,
@@ -386,6 +394,42 @@ struct ath9k_hw_version {
u16 phyRev;
u16 analog5GhzRev;
u16 analog2GhzRev;
+ u16 subsysid;
+};
+
+/* Generic TSF timer definitions */
+
+#define ATH_MAX_GEN_TIMER 16
+
+#define AR_GENTMR_BIT(_index) (1 << (_index))
+
+/*
+ * Using de Bruijin sequence to to look up 1's index in a 32 bit number
+ * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001
+ */
+#define debruijn32 0x077CB531UL
+
+struct ath_gen_timer_configuration {
+ u32 next_addr;
+ u32 period_addr;
+ u32 mode_addr;
+ u32 mode_mask;
+};
+
+struct ath_gen_timer {
+ void (*trigger)(void *arg);
+ void (*overflow)(void *arg);
+ void *arg;
+ u8 index;
+};
+
+struct ath_gen_timer_table {
+ u32 gen_timer_index[32];
+ struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER];
+ union {
+ unsigned long timer_bits;
+ u16 val;
+ } timer_mask;
};
struct ath_hw {
@@ -393,13 +437,13 @@ struct ath_hw {
struct ath9k_hw_version hw_version;
struct ath9k_ops_config config;
struct ath9k_hw_capabilities caps;
- struct ath_regulatory regulatory;
struct ath9k_channel channels[38];
struct ath9k_channel *curchan;
union {
struct ar5416_eeprom_def def;
struct ar5416_eeprom_4k map4k;
+ struct ar9287_eeprom map9287;
} eeprom;
const struct eeprom_ops *eep_ops;
enum ath9k_eep_map eep_map;
@@ -411,15 +455,15 @@ struct ath_hw {
u16 rfsilent;
u32 rfkill_gpio;
u32 rfkill_polarity;
- u32 btactive_gpio;
- u32 wlanactive_gpio;
u32 ah_flags;
+ bool htc_reset_init;
+
enum nl80211_iftype opmode;
enum ath9k_power_mode power_mode;
- enum ath9k_power_mode restore_mode;
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
+ struct ath9k_pacal_info pacal_info;
struct ar5416Stats stats;
struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
@@ -432,8 +476,6 @@ struct ath_hw {
u32 txurn_interrupt_mask;
bool chip_fullsleep;
u32 atim_window;
- u16 antenna_switch_swap;
- enum ath9k_ant_setting diversity_control;
/* Calibration */
enum ath9k_cal_types supp_cals;
@@ -502,7 +544,6 @@ struct ath_hw {
/* ANI */
u32 proc_phyerr;
- bool has_hw_phycounters;
u32 aniperiod;
struct ar5416AniState *curani;
struct ar5416AniState ani[255];
@@ -520,6 +561,7 @@ struct ath_hw {
u32 originalGain[22];
int initPDADC;
int PDADCdelta;
+ u8 led_pin;
struct ar5416IniArray iniModes;
struct ar5416IniArray iniCommon;
@@ -536,13 +578,17 @@ struct ath_hw {
struct ar5416IniArray iniModesAdditional;
struct ar5416IniArray iniModesRxGain;
struct ar5416IniArray iniModesTxGain;
+
+ u32 intr_gen_timer_trigger;
+ u32 intr_gen_timer_thresh;
+ struct ath_gen_timer_table hw_gen_timers;
};
-/* Attach, Detach, Reset */
+/* Initialization, Detach, Reset */
const char *ath9k_hw_probe(u16 vendorid, u16 devid);
void ath9k_hw_detach(struct ath_hw *ah);
-struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error);
-void ath9k_hw_rfdetach(struct ath_hw *ah);
+int ath9k_hw_init(struct ath_hw *ah);
+void ath9k_hw_rf_free(struct ath_hw *ah);
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
bool bChannelChange);
void ath9k_hw_fill_cap_info(struct ath_hw *ah);
@@ -596,7 +642,7 @@ void ath9k_hw_write_associd(struct ath_softc *sc);
u64 ath9k_hw_gettsf64(struct ath_hw *ah);
void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
void ath9k_hw_reset_tsf(struct ath_hw *ah);
-bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
+void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode);
void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
@@ -609,9 +655,24 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore);
/* Interrupt Handling */
bool ath9k_hw_intrpend(struct ath_hw *ah);
bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked);
-enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah);
enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints);
-void ath9k_hw_btcoex_enable(struct ath_hw *ah);
-
+/* Generic hw timer primitives */
+struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
+ void (*trigger)(void *),
+ void (*overflow)(void *),
+ void *arg,
+ u8 timer_index);
+void ath_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer,
+ u32 timer_next, u32 timer_period);
+void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer);
+void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer);
+void ath_gen_timer_isr(struct ath_hw *hw);
+u32 ath9k_hw_gettsf32(struct ath_hw *ah);
+
+#define ATH_PCIE_CAP_LINK_CTRL 0x70
+#define ATH_PCIE_CAP_LINK_L0S 1
+#define ATH_PCIE_CAP_LINK_L1 2
+
+void ath_pcie_aspm_disable(struct ath_softc *sc);
#endif
diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h
index e2f0a34b79a1..8622265a030a 100644
--- a/drivers/net/wireless/ath/ath9k/initvals.h
+++ b/drivers/net/wireless/ath/ath9k/initvals.h
@@ -2782,7 +2782,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafa68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -3439,7 +3439,7 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
{0x00004044, 0x00000000 },
};
-/* AR9285 */
+/* AR9285 Revsion 10*/
static const u_int32_t ar9285Modes_9285[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -3955,7 +3955,7 @@ static const u_int32_t ar9285Common_9285[][2] = {
{ 0x00008338, 0x00000000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x00010380 },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafe68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -4121,8 +4121,9 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = {
{0x00004044, 0x00000000 },
};
-/* AR9285 v1_2 PCI Register Writes. Created: 03/04/09 */
+/* AR9285 v1_2 PCI Register Writes. Created: 04/13/09 */
static const u_int32_t ar9285Modes_9285_1_2[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
{ 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
@@ -4132,13 +4133,14 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
{ 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
{ 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e },
{ 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
{ 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
{ 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
{ 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
{ 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 },
{ 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
{ 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
{ 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
{ 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
@@ -4156,7 +4158,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
{ 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
{ 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
- { 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 },
+ { 0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f },
{ 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
{ 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
{ 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
@@ -4419,6 +4421,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
{ 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
{ 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
+ { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
{ 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
{ 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
{ 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
@@ -4598,7 +4601,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00008258, 0x00000000 },
{ 0x0000825c, 0x400000ff },
{ 0x00008260, 0x00080922 },
- { 0x00008264, 0xa8a00010 },
+ { 0x00008264, 0x88a00010 },
{ 0x00008270, 0x00000000 },
{ 0x00008274, 0x40000000 },
{ 0x00008278, 0x003e4180 },
@@ -4618,7 +4621,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x00010380 },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafe68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -4647,7 +4650,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00009954, 0x5f3ca3de },
{ 0x00009958, 0x2108ecff },
{ 0x00009968, 0x000003ce },
- { 0x00009970, 0x192bb515 },
+ { 0x00009970, 0x192bb514 },
{ 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 },
{ 0x0000997c, 0x00000000 },
@@ -4725,7 +4728,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00007800, 0x00140000 },
{ 0x00007804, 0x0e4548d8 },
{ 0x00007808, 0x54214514 },
- { 0x0000780c, 0x02025820 },
+ { 0x0000780c, 0x02025830 },
{ 0x00007810, 0x71c0d388 },
{ 0x00007814, 0x924934a8 },
{ 0x0000781c, 0x00000000 },
@@ -4752,18 +4755,18 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
/* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
{ 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00000000, 0x00000000, 0x00005200, 0x00005200, 0x00000000 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 },
+ { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 },
+ { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 },
{ 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 },
{ 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 },
- { 0x0000a314, 0x00000000, 0x00000000, 0x0000f440, 0x0000f440, 0x00000000 },
- { 0x0000a318, 0x00000000, 0x00000000, 0x00014640, 0x00014640, 0x00000000 },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x00018680, 0x00018680, 0x00000000 },
- { 0x0000a320, 0x00000000, 0x00000000, 0x00019841, 0x00019841, 0x00000000 },
- { 0x0000a324, 0x00000000, 0x00000000, 0x0001ca40, 0x0001ca40, 0x00000000 },
- { 0x0000a328, 0x00000000, 0x00000000, 0x0001fa80, 0x0001fa80, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x00023ac0, 0x00023ac0, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
+ { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 },
+ { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 },
+ { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 },
+ { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 },
+ { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 },
+ { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 },
{ 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 },
{ 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
{ 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
@@ -4776,13 +4779,13 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
{ 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 },
{ 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
{ 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
- { 0x0000a278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
- { 0x0000a394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
- { 0x0000a3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a3e0, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
+ { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
+ { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+ { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 },
+ { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+ { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
+ { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+ { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
};
static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = {
@@ -4846,3 +4849,2185 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
{0x00004040, 0x00043007 },
{0x00004044, 0x00000000 },
};
+
+/* AR9287 Revision 10 */
+static const u_int32_t ar9287Modes_9287_1_0[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
+ { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 },
+ { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 },
+ { 0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180 },
+ { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
+ { 0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0 },
+ { 0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f },
+ { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
+ { 0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a },
+ { 0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880 },
+ { 0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303 },
+ { 0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200 },
+ { 0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e },
+ { 0x00009828, 0x00000000, 0x00000000, 0x0a020001, 0x0a020001, 0x0a020001 },
+ { 0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007 },
+ { 0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e },
+ { 0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0 },
+ { 0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
+ { 0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+ { 0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e },
+ { 0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18 },
+ { 0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
+ { 0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881 },
+ { 0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0 },
+ { 0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
+ { 0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010 },
+ { 0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
+ { 0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
+ { 0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210 },
+ { 0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce },
+ { 0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c },
+ { 0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00 },
+ { 0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+ { 0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444 },
+ { 0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000 },
+ { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+ { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+};
+
+static const u_int32_t ar9287Common_9287_1_0[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000030, 0x00020015 },
+ { 0x00000034, 0x00000005 },
+ { 0x00000040, 0x00000000 },
+ { 0x00000044, 0x00000008 },
+ { 0x00000048, 0x00000008 },
+ { 0x0000004c, 0x00000010 },
+ { 0x00000050, 0x00000000 },
+ { 0x00000054, 0x0000001f },
+ { 0x00000800, 0x00000000 },
+ { 0x00000804, 0x00000000 },
+ { 0x00000808, 0x00000000 },
+ { 0x0000080c, 0x00000000 },
+ { 0x00000810, 0x00000000 },
+ { 0x00000814, 0x00000000 },
+ { 0x00000818, 0x00000000 },
+ { 0x0000081c, 0x00000000 },
+ { 0x00000820, 0x00000000 },
+ { 0x00000824, 0x00000000 },
+ { 0x00001040, 0x002ffc0f },
+ { 0x00001044, 0x002ffc0f },
+ { 0x00001048, 0x002ffc0f },
+ { 0x0000104c, 0x002ffc0f },
+ { 0x00001050, 0x002ffc0f },
+ { 0x00001054, 0x002ffc0f },
+ { 0x00001058, 0x002ffc0f },
+ { 0x0000105c, 0x002ffc0f },
+ { 0x00001060, 0x002ffc0f },
+ { 0x00001064, 0x002ffc0f },
+ { 0x00001230, 0x00000000 },
+ { 0x00001270, 0x00000000 },
+ { 0x00001038, 0x00000000 },
+ { 0x00001078, 0x00000000 },
+ { 0x000010b8, 0x00000000 },
+ { 0x000010f8, 0x00000000 },
+ { 0x00001138, 0x00000000 },
+ { 0x00001178, 0x00000000 },
+ { 0x000011b8, 0x00000000 },
+ { 0x000011f8, 0x00000000 },
+ { 0x00001238, 0x00000000 },
+ { 0x00001278, 0x00000000 },
+ { 0x000012b8, 0x00000000 },
+ { 0x000012f8, 0x00000000 },
+ { 0x00001338, 0x00000000 },
+ { 0x00001378, 0x00000000 },
+ { 0x000013b8, 0x00000000 },
+ { 0x000013f8, 0x00000000 },
+ { 0x00001438, 0x00000000 },
+ { 0x00001478, 0x00000000 },
+ { 0x000014b8, 0x00000000 },
+ { 0x000014f8, 0x00000000 },
+ { 0x00001538, 0x00000000 },
+ { 0x00001578, 0x00000000 },
+ { 0x000015b8, 0x00000000 },
+ { 0x000015f8, 0x00000000 },
+ { 0x00001638, 0x00000000 },
+ { 0x00001678, 0x00000000 },
+ { 0x000016b8, 0x00000000 },
+ { 0x000016f8, 0x00000000 },
+ { 0x00001738, 0x00000000 },
+ { 0x00001778, 0x00000000 },
+ { 0x000017b8, 0x00000000 },
+ { 0x000017f8, 0x00000000 },
+ { 0x0000103c, 0x00000000 },
+ { 0x0000107c, 0x00000000 },
+ { 0x000010bc, 0x00000000 },
+ { 0x000010fc, 0x00000000 },
+ { 0x0000113c, 0x00000000 },
+ { 0x0000117c, 0x00000000 },
+ { 0x000011bc, 0x00000000 },
+ { 0x000011fc, 0x00000000 },
+ { 0x0000123c, 0x00000000 },
+ { 0x0000127c, 0x00000000 },
+ { 0x000012bc, 0x00000000 },
+ { 0x000012fc, 0x00000000 },
+ { 0x0000133c, 0x00000000 },
+ { 0x0000137c, 0x00000000 },
+ { 0x000013bc, 0x00000000 },
+ { 0x000013fc, 0x00000000 },
+ { 0x0000143c, 0x00000000 },
+ { 0x0000147c, 0x00000000 },
+ { 0x00004030, 0x00000002 },
+ { 0x0000403c, 0x00000002 },
+ { 0x00004024, 0x0000001f },
+ { 0x00004060, 0x00000000 },
+ { 0x00004064, 0x00000000 },
+ { 0x00007010, 0x00000033 },
+ { 0x00007020, 0x00000000 },
+ { 0x00007034, 0x00000002 },
+ { 0x00007038, 0x000004c2 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000700 },
+ { 0x00008020, 0x00000000 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008048, 0x40000000 },
+ { 0x00008054, 0x00000000 },
+ { 0x00008058, 0x00000000 },
+ { 0x0000805c, 0x000fc78f },
+ { 0x00008060, 0x0000000f },
+ { 0x00008064, 0x00000000 },
+ { 0x00008070, 0x00000000 },
+ { 0x000080c0, 0x2a80001a },
+ { 0x000080c4, 0x05dc01e0 },
+ { 0x000080c8, 0x1f402710 },
+ { 0x000080cc, 0x01f40000 },
+ { 0x000080d0, 0x00001e00 },
+ { 0x000080d4, 0x00000000 },
+ { 0x000080d8, 0x00400000 },
+ { 0x000080e0, 0xffffffff },
+ { 0x000080e4, 0x0000ffff },
+ { 0x000080e8, 0x003f3f3f },
+ { 0x000080ec, 0x00000000 },
+ { 0x000080f0, 0x00000000 },
+ { 0x000080f4, 0x00000000 },
+ { 0x000080f8, 0x00000000 },
+ { 0x000080fc, 0x00020000 },
+ { 0x00008100, 0x00020000 },
+ { 0x00008104, 0x00000001 },
+ { 0x00008108, 0x00000052 },
+ { 0x0000810c, 0x00000000 },
+ { 0x00008110, 0x00000168 },
+ { 0x00008118, 0x000100aa },
+ { 0x0000811c, 0x00003210 },
+ { 0x00008124, 0x00000000 },
+ { 0x00008128, 0x00000000 },
+ { 0x0000812c, 0x00000000 },
+ { 0x00008130, 0x00000000 },
+ { 0x00008134, 0x00000000 },
+ { 0x00008138, 0x00000000 },
+ { 0x0000813c, 0x00000000 },
+ { 0x00008144, 0xffffffff },
+ { 0x00008168, 0x00000000 },
+ { 0x0000816c, 0x00000000 },
+ { 0x00008170, 0x18487320 },
+ { 0x00008174, 0xfaa4fa50 },
+ { 0x00008178, 0x00000100 },
+ { 0x0000817c, 0x00000000 },
+ { 0x000081c0, 0x00000000 },
+ { 0x000081c4, 0x00000000 },
+ { 0x000081d4, 0x00000000 },
+ { 0x000081ec, 0x00000000 },
+ { 0x000081f0, 0x00000000 },
+ { 0x000081f4, 0x00000000 },
+ { 0x000081f8, 0x00000000 },
+ { 0x000081fc, 0x00000000 },
+ { 0x00008200, 0x00000000 },
+ { 0x00008204, 0x00000000 },
+ { 0x00008208, 0x00000000 },
+ { 0x0000820c, 0x00000000 },
+ { 0x00008210, 0x00000000 },
+ { 0x00008214, 0x00000000 },
+ { 0x00008218, 0x00000000 },
+ { 0x0000821c, 0x00000000 },
+ { 0x00008220, 0x00000000 },
+ { 0x00008224, 0x00000000 },
+ { 0x00008228, 0x00000000 },
+ { 0x0000822c, 0x00000000 },
+ { 0x00008230, 0x00000000 },
+ { 0x00008234, 0x00000000 },
+ { 0x00008238, 0x00000000 },
+ { 0x0000823c, 0x00000000 },
+ { 0x00008240, 0x00100000 },
+ { 0x00008244, 0x0010f400 },
+ { 0x00008248, 0x00000100 },
+ { 0x0000824c, 0x0001e800 },
+ { 0x00008250, 0x00000000 },
+ { 0x00008254, 0x00000000 },
+ { 0x00008258, 0x00000000 },
+ { 0x0000825c, 0x400000ff },
+ { 0x00008260, 0x00080922 },
+ { 0x00008264, 0xa8a00010 },
+ { 0x00008270, 0x00000000 },
+ { 0x00008274, 0x40000000 },
+ { 0x00008278, 0x003e4180 },
+ { 0x0000827c, 0x00000000 },
+ { 0x00008284, 0x0000002c },
+ { 0x00008288, 0x0000002c },
+ { 0x0000828c, 0x000000ff },
+ { 0x00008294, 0x00000000 },
+ { 0x00008298, 0x00000000 },
+ { 0x0000829c, 0x00000000 },
+ { 0x00008300, 0x00000040 },
+ { 0x00008314, 0x00000000 },
+ { 0x00008328, 0x00000000 },
+ { 0x0000832c, 0x00000007 },
+ { 0x00008330, 0x00000302 },
+ { 0x00008334, 0x00000e00 },
+ { 0x00008338, 0x00ff0000 },
+ { 0x0000833c, 0x00000000 },
+ { 0x00008340, 0x000107ff },
+ { 0x00008344, 0x01c81043 },
+ { 0x00008360, 0xffffffff },
+ { 0x00008364, 0xffffffff },
+ { 0x00008368, 0x00000000 },
+ { 0x00008370, 0x00000000 },
+ { 0x00008374, 0x000000ff },
+ { 0x00008378, 0x00000000 },
+ { 0x0000837c, 0x00000000 },
+ { 0x00008380, 0xffffffff },
+ { 0x00008384, 0xffffffff },
+ { 0x00008390, 0x0fffffff },
+ { 0x00008394, 0x0fffffff },
+ { 0x00008398, 0x00000000 },
+ { 0x0000839c, 0x00000000 },
+ { 0x000083a0, 0x00000000 },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0xafe68e30 },
+ { 0x00009810, 0xfd14e000 },
+ { 0x00009814, 0x9c0a9f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x0000a000 },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00200400 },
+ { 0x0000984c, 0x0040233c },
+ { 0x0000a84c, 0x0040233c },
+ { 0x00009854, 0x00000044 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00000000 },
+ { 0x00009910, 0x10002310 },
+ { 0x0000991c, 0x10000fff },
+ { 0x00009920, 0x04900000 },
+ { 0x0000a920, 0x04900000 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000004 },
+ { 0x00009930, 0x00000000 },
+ { 0x0000a930, 0x00000000 },
+ { 0x00009934, 0x1e1f2022 },
+ { 0x00009938, 0x0a0b0c0d },
+ { 0x0000993c, 0x00000000 },
+ { 0x00009948, 0x9280c00a },
+ { 0x0000994c, 0x00020028 },
+ { 0x00009954, 0x5f3ca3de },
+ { 0x00009958, 0x0108ecff },
+ { 0x00009940, 0x14750604 },
+ { 0x0000c95c, 0x004b6a8e },
+ { 0x00009970, 0x990bb515 },
+ { 0x00009974, 0x00000000 },
+ { 0x00009978, 0x00000001 },
+ { 0x0000997c, 0x00000000 },
+ { 0x000099a0, 0x00000000 },
+ { 0x000099a4, 0x00000001 },
+ { 0x000099a8, 0x201fff00 },
+ { 0x000099ac, 0x0c6f0000 },
+ { 0x000099b0, 0x03051000 },
+ { 0x000099b4, 0x00000820 },
+ { 0x000099c4, 0x06336f77 },
+ { 0x000099c8, 0x6af65329 },
+ { 0x000099cc, 0x08f186c8 },
+ { 0x000099d0, 0x00046384 },
+ { 0x000099dc, 0x00000000 },
+ { 0x000099e0, 0x00000000 },
+ { 0x000099e4, 0xaaaaaaaa },
+ { 0x000099e8, 0x3c466478 },
+ { 0x000099ec, 0x0cc80caa },
+ { 0x000099f0, 0x00000000 },
+ { 0x000099fc, 0x00001042 },
+ { 0x0000a1f4, 0x00fffeff },
+ { 0x0000a1f8, 0x00f5f9ff },
+ { 0x0000a1fc, 0xb79f6427 },
+ { 0x0000a208, 0x803e4788 },
+ { 0x0000a210, 0x4080a333 },
+ { 0x0000a214, 0x40206c10 },
+ { 0x0000a218, 0x009c4060 },
+ { 0x0000a220, 0x01834061 },
+ { 0x0000a224, 0x00000400 },
+ { 0x0000a228, 0x000003b5 },
+ { 0x0000a22c, 0x233f7180 },
+ { 0x0000a234, 0x20202020 },
+ { 0x0000a238, 0x20202020 },
+ { 0x0000a23c, 0x13c889af },
+ { 0x0000a240, 0x38490a20 },
+ { 0x0000a244, 0x00000000 },
+ { 0x0000a248, 0xfffffffc },
+ { 0x0000a24c, 0x00000000 },
+ { 0x0000a254, 0x00000000 },
+ { 0x0000a258, 0x0cdbd380 },
+ { 0x0000a25c, 0x0f0f0f01 },
+ { 0x0000a260, 0xdfa91f01 },
+ { 0x0000a264, 0x00418a11 },
+ { 0x0000b264, 0x00418a11 },
+ { 0x0000a268, 0x00000000 },
+ { 0x0000a26c, 0x0e79e5c6 },
+ { 0x0000b26c, 0x0e79e5c6 },
+ { 0x0000d270, 0x00820820 },
+ { 0x0000a278, 0x1ce739ce },
+ { 0x0000a27c, 0x050701ce },
+ { 0x0000d35c, 0x07ffffef },
+ { 0x0000d360, 0x0fffffe7 },
+ { 0x0000d364, 0x17ffffe5 },
+ { 0x0000d368, 0x1fffffe4 },
+ { 0x0000d36c, 0x37ffffe3 },
+ { 0x0000d370, 0x3fffffe3 },
+ { 0x0000d374, 0x57ffffe3 },
+ { 0x0000d378, 0x5fffffe2 },
+ { 0x0000d37c, 0x7fffffe2 },
+ { 0x0000d380, 0x7f3c7bba },
+ { 0x0000d384, 0xf3307ff0 },
+ { 0x0000a388, 0x0c000000 },
+ { 0x0000a38c, 0x20202020 },
+ { 0x0000a390, 0x20202020 },
+ { 0x0000a394, 0x1ce739ce },
+ { 0x0000a398, 0x000001ce },
+ { 0x0000b398, 0x000001ce },
+ { 0x0000a39c, 0x00000001 },
+ { 0x0000a3c8, 0x00000246 },
+ { 0x0000a3cc, 0x20202020 },
+ { 0x0000a3d0, 0x20202020 },
+ { 0x0000a3d4, 0x20202020 },
+ { 0x0000a3dc, 0x1ce739ce },
+ { 0x0000a3e0, 0x000001ce },
+ { 0x0000a3e4, 0x00000000 },
+ { 0x0000a3e8, 0x18c43433 },
+ { 0x0000a3ec, 0x00f70081 },
+ { 0x0000a3f0, 0x01036a1e },
+ { 0x0000a3f4, 0x00000000 },
+ { 0x0000b3f4, 0x00000000 },
+ { 0x0000a7d8, 0x00000001 },
+ { 0x00007800, 0x00000800 },
+ { 0x00007804, 0x6c35ffb0 },
+ { 0x00007808, 0x6db6c000 },
+ { 0x0000780c, 0x6db6cb30 },
+ { 0x00007810, 0x6db6cb6c },
+ { 0x00007814, 0x0501e200 },
+ { 0x00007818, 0x0094128d },
+ { 0x0000781c, 0x976ee392 },
+ { 0x00007820, 0xf75ff6fc },
+ { 0x00007824, 0x00040000 },
+ { 0x00007828, 0xdb003012 },
+ { 0x0000782c, 0x04924914 },
+ { 0x00007830, 0x21084210 },
+ { 0x00007834, 0x00140000 },
+ { 0x00007838, 0x0e4548d8 },
+ { 0x0000783c, 0x54214514 },
+ { 0x00007840, 0x02025820 },
+ { 0x00007844, 0x71c0d388 },
+ { 0x00007848, 0x934934a8 },
+ { 0x00007850, 0x00000000 },
+ { 0x00007854, 0x00000800 },
+ { 0x00007858, 0x6c35ffb0 },
+ { 0x0000785c, 0x6db6c000 },
+ { 0x00007860, 0x6db6cb2c },
+ { 0x00007864, 0x6db6cb6c },
+ { 0x00007868, 0x0501e200 },
+ { 0x0000786c, 0x0094128d },
+ { 0x00007870, 0x976ee392 },
+ { 0x00007874, 0xf75ff6fc },
+ { 0x00007878, 0x00040000 },
+ { 0x0000787c, 0xdb003012 },
+ { 0x00007880, 0x04924914 },
+ { 0x00007884, 0x21084210 },
+ { 0x00007888, 0x001b6db0 },
+ { 0x0000788c, 0x00376b63 },
+ { 0x00007890, 0x06db6db6 },
+ { 0x00007894, 0x006d8000 },
+ { 0x00007898, 0x48100000 },
+ { 0x0000789c, 0x00000000 },
+ { 0x000078a0, 0x08000000 },
+ { 0x000078a4, 0x0007ffd8 },
+ { 0x000078a8, 0x0007ffd8 },
+ { 0x000078ac, 0x001c0020 },
+ { 0x000078b0, 0x000611eb },
+ { 0x000078b4, 0x40008080 },
+ { 0x000078b8, 0x2a850160 },
+};
+
+static const u_int32_t ar9287Modes_tx_gain_9287_1_0[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
+ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 },
+ { 0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004 },
+ { 0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a },
+ { 0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c },
+ { 0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b },
+ { 0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a },
+ { 0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a },
+ { 0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a },
+ { 0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a },
+ { 0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a },
+ { 0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a },
+ { 0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c },
+ { 0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc },
+ { 0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4 },
+ { 0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc },
+ { 0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede },
+ { 0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e },
+ { 0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e },
+ { 0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e },
+ { 0x0000a780, 0x00000000, 0x00000000, 0x00000060, 0x00000060, 0x00000060 },
+ { 0x0000a784, 0x00000000, 0x00000000, 0x00004062, 0x00004062, 0x00004062 },
+ { 0x0000a788, 0x00000000, 0x00000000, 0x00008064, 0x00008064, 0x00008064 },
+ { 0x0000a78c, 0x00000000, 0x00000000, 0x0000c0a4, 0x0000c0a4, 0x0000c0a4 },
+ { 0x0000a790, 0x00000000, 0x00000000, 0x000100b0, 0x000100b0, 0x000100b0 },
+ { 0x0000a794, 0x00000000, 0x00000000, 0x000140b2, 0x000140b2, 0x000140b2 },
+ { 0x0000a798, 0x00000000, 0x00000000, 0x000180b4, 0x000180b4, 0x000180b4 },
+ { 0x0000a79c, 0x00000000, 0x00000000, 0x0001c0f4, 0x0001c0f4, 0x0001c0f4 },
+ { 0x0000a7a0, 0x00000000, 0x00000000, 0x00020134, 0x00020134, 0x00020134 },
+ { 0x0000a7a4, 0x00000000, 0x00000000, 0x000240fe, 0x000240fe, 0x000240fe },
+ { 0x0000a7a8, 0x00000000, 0x00000000, 0x0002813e, 0x0002813e, 0x0002813e },
+ { 0x0000a7ac, 0x00000000, 0x00000000, 0x0002c17e, 0x0002c17e, 0x0002c17e },
+ { 0x0000a7b0, 0x00000000, 0x00000000, 0x000301be, 0x000301be, 0x000301be },
+ { 0x0000a7b4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7b8, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7bc, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7c0, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7c4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7c8, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7cc, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7d0, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7d4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 },
+};
+
+
+static const u_int32_t ar9287Modes_rx_gain_9287_1_0[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
+ { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
+ { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
+ { 0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
+ { 0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
+ { 0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
+ { 0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
+ { 0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
+ { 0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
+ { 0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
+ { 0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
+ { 0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
+ { 0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
+ { 0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
+ { 0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
+ { 0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
+ { 0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
+ { 0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
+ { 0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
+ { 0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
+ { 0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
+ { 0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
+ { 0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
+ { 0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
+ { 0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
+ { 0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
+ { 0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
+ { 0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
+ { 0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
+ { 0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
+ { 0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
+ { 0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
+ { 0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
+ { 0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
+ { 0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
+ { 0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
+ { 0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
+ { 0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
+ { 0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
+ { 0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
+ { 0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
+ { 0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
+ { 0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
+ { 0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
+ { 0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
+ { 0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
+ { 0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
+ { 0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
+ { 0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
+ { 0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
+ { 0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
+ { 0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
+ { 0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
+ { 0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
+ { 0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
+ { 0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
+ { 0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
+ { 0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
+ { 0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
+ { 0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
+ { 0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
+ { 0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
+ { 0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
+ { 0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
+ { 0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
+ { 0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
+ { 0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
+ { 0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
+ { 0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
+ { 0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
+ { 0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
+ { 0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
+ { 0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
+ { 0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
+ { 0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
+ { 0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
+ { 0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
+ { 0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
+ { 0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
+ { 0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
+ { 0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
+ { 0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
+ { 0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
+ { 0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
+ { 0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
+ { 0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
+ { 0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
+ { 0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
+ { 0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
+ { 0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
+ { 0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
+ { 0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
+ { 0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
+ { 0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
+ { 0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
+ { 0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
+ { 0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
+ { 0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
+ { 0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
+ { 0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
+ { 0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
+ { 0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
+ { 0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
+ { 0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
+ { 0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
+ { 0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
+ { 0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
+ { 0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
+ { 0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
+ { 0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
+ { 0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
+ { 0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
+ { 0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
+ { 0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
+ { 0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
+ { 0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
+ { 0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
+ { 0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
+ { 0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
+ { 0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
+ { 0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
+ { 0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
+ { 0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
+ { 0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
+ { 0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
+ { 0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
+ { 0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
+ { 0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
+ { 0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
+ { 0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
+ { 0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
+ { 0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
+ { 0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
+ { 0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
+ { 0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
+ { 0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
+ { 0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
+ { 0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
+ { 0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
+ { 0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
+ { 0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
+ { 0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
+ { 0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
+ { 0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
+ { 0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
+ { 0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
+ { 0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
+ { 0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
+ { 0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
+ { 0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
+ { 0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
+ { 0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
+ { 0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
+ { 0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
+ { 0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
+ { 0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
+ { 0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
+ { 0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
+ { 0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
+ { 0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
+ { 0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
+ { 0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
+ { 0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
+ { 0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
+ { 0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
+ { 0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
+ { 0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
+ { 0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
+ { 0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
+ { 0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
+ { 0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
+ { 0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
+ { 0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
+ { 0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
+ { 0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
+ { 0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
+ { 0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
+ { 0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
+ { 0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
+ { 0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
+ { 0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
+ { 0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
+ { 0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
+ { 0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
+ { 0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
+ { 0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
+ { 0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
+ { 0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
+ { 0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
+ { 0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
+ { 0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
+ { 0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
+ { 0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
+ { 0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
+ { 0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
+ { 0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
+ { 0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
+ { 0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
+ { 0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
+ { 0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
+ { 0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
+ { 0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
+ { 0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
+ { 0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
+ { 0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
+ { 0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
+ { 0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
+ { 0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
+ { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
+};
+
+static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_0[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0xc01dcffd },
+ {0x00004040, 0x1aaabe41 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
+};
+
+static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_0[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0xc01dcffc },
+ {0x00004040, 0x1aaabe41 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
+};
+
+/* AR9287 Revision 11 */
+
+static const u_int32_t ar9287Modes_9287_1_1[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
+ { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 },
+ { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 },
+ { 0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180 },
+ { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
+ { 0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0 },
+ { 0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f },
+ { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
+ { 0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a },
+ { 0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880 },
+ { 0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303 },
+ { 0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200 },
+ { 0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e },
+ { 0x00009828, 0x00000000, 0x00000000, 0x3a020001, 0x3a020001, 0x3a020001 },
+ { 0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007 },
+ { 0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e },
+ { 0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0 },
+ { 0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
+ { 0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+ { 0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e },
+ { 0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18 },
+ { 0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
+ { 0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881 },
+ { 0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0 },
+ { 0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
+ { 0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010 },
+ { 0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
+ { 0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
+ { 0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210 },
+ { 0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce },
+ { 0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c },
+ { 0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00 },
+ { 0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+ { 0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444 },
+ { 0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000 },
+ { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+ { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+};
+
+static const u_int32_t ar9287Common_9287_1_1[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000030, 0x00020015 },
+ { 0x00000034, 0x00000005 },
+ { 0x00000040, 0x00000000 },
+ { 0x00000044, 0x00000008 },
+ { 0x00000048, 0x00000008 },
+ { 0x0000004c, 0x00000010 },
+ { 0x00000050, 0x00000000 },
+ { 0x00000054, 0x0000001f },
+ { 0x00000800, 0x00000000 },
+ { 0x00000804, 0x00000000 },
+ { 0x00000808, 0x00000000 },
+ { 0x0000080c, 0x00000000 },
+ { 0x00000810, 0x00000000 },
+ { 0x00000814, 0x00000000 },
+ { 0x00000818, 0x00000000 },
+ { 0x0000081c, 0x00000000 },
+ { 0x00000820, 0x00000000 },
+ { 0x00000824, 0x00000000 },
+ { 0x00001040, 0x002ffc0f },
+ { 0x00001044, 0x002ffc0f },
+ { 0x00001048, 0x002ffc0f },
+ { 0x0000104c, 0x002ffc0f },
+ { 0x00001050, 0x002ffc0f },
+ { 0x00001054, 0x002ffc0f },
+ { 0x00001058, 0x002ffc0f },
+ { 0x0000105c, 0x002ffc0f },
+ { 0x00001060, 0x002ffc0f },
+ { 0x00001064, 0x002ffc0f },
+ { 0x00001230, 0x00000000 },
+ { 0x00001270, 0x00000000 },
+ { 0x00001038, 0x00000000 },
+ { 0x00001078, 0x00000000 },
+ { 0x000010b8, 0x00000000 },
+ { 0x000010f8, 0x00000000 },
+ { 0x00001138, 0x00000000 },
+ { 0x00001178, 0x00000000 },
+ { 0x000011b8, 0x00000000 },
+ { 0x000011f8, 0x00000000 },
+ { 0x00001238, 0x00000000 },
+ { 0x00001278, 0x00000000 },
+ { 0x000012b8, 0x00000000 },
+ { 0x000012f8, 0x00000000 },
+ { 0x00001338, 0x00000000 },
+ { 0x00001378, 0x00000000 },
+ { 0x000013b8, 0x00000000 },
+ { 0x000013f8, 0x00000000 },
+ { 0x00001438, 0x00000000 },
+ { 0x00001478, 0x00000000 },
+ { 0x000014b8, 0x00000000 },
+ { 0x000014f8, 0x00000000 },
+ { 0x00001538, 0x00000000 },
+ { 0x00001578, 0x00000000 },
+ { 0x000015b8, 0x00000000 },
+ { 0x000015f8, 0x00000000 },
+ { 0x00001638, 0x00000000 },
+ { 0x00001678, 0x00000000 },
+ { 0x000016b8, 0x00000000 },
+ { 0x000016f8, 0x00000000 },
+ { 0x00001738, 0x00000000 },
+ { 0x00001778, 0x00000000 },
+ { 0x000017b8, 0x00000000 },
+ { 0x000017f8, 0x00000000 },
+ { 0x0000103c, 0x00000000 },
+ { 0x0000107c, 0x00000000 },
+ { 0x000010bc, 0x00000000 },
+ { 0x000010fc, 0x00000000 },
+ { 0x0000113c, 0x00000000 },
+ { 0x0000117c, 0x00000000 },
+ { 0x000011bc, 0x00000000 },
+ { 0x000011fc, 0x00000000 },
+ { 0x0000123c, 0x00000000 },
+ { 0x0000127c, 0x00000000 },
+ { 0x000012bc, 0x00000000 },
+ { 0x000012fc, 0x00000000 },
+ { 0x0000133c, 0x00000000 },
+ { 0x0000137c, 0x00000000 },
+ { 0x000013bc, 0x00000000 },
+ { 0x000013fc, 0x00000000 },
+ { 0x0000143c, 0x00000000 },
+ { 0x0000147c, 0x00000000 },
+ { 0x00004030, 0x00000002 },
+ { 0x0000403c, 0x00000002 },
+ { 0x00004024, 0x0000001f },
+ { 0x00004060, 0x00000000 },
+ { 0x00004064, 0x00000000 },
+ { 0x00007010, 0x00000033 },
+ { 0x00007020, 0x00000000 },
+ { 0x00007034, 0x00000002 },
+ { 0x00007038, 0x000004c2 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000700 },
+ { 0x00008020, 0x00000000 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008048, 0x40000000 },
+ { 0x00008054, 0x00000000 },
+ { 0x00008058, 0x00000000 },
+ { 0x0000805c, 0x000fc78f },
+ { 0x00008060, 0x0000000f },
+ { 0x00008064, 0x00000000 },
+ { 0x00008070, 0x00000000 },
+ { 0x000080c0, 0x2a80001a },
+ { 0x000080c4, 0x05dc01e0 },
+ { 0x000080c8, 0x1f402710 },
+ { 0x000080cc, 0x01f40000 },
+ { 0x000080d0, 0x00001e00 },
+ { 0x000080d4, 0x00000000 },
+ { 0x000080d8, 0x00400000 },
+ { 0x000080e0, 0xffffffff },
+ { 0x000080e4, 0x0000ffff },
+ { 0x000080e8, 0x003f3f3f },
+ { 0x000080ec, 0x00000000 },
+ { 0x000080f0, 0x00000000 },
+ { 0x000080f4, 0x00000000 },
+ { 0x000080f8, 0x00000000 },
+ { 0x000080fc, 0x00020000 },
+ { 0x00008100, 0x00020000 },
+ { 0x00008104, 0x00000001 },
+ { 0x00008108, 0x00000052 },
+ { 0x0000810c, 0x00000000 },
+ { 0x00008110, 0x00000168 },
+ { 0x00008118, 0x000100aa },
+ { 0x0000811c, 0x00003210 },
+ { 0x00008124, 0x00000000 },
+ { 0x00008128, 0x00000000 },
+ { 0x0000812c, 0x00000000 },
+ { 0x00008130, 0x00000000 },
+ { 0x00008134, 0x00000000 },
+ { 0x00008138, 0x00000000 },
+ { 0x0000813c, 0x00000000 },
+ { 0x00008144, 0xffffffff },
+ { 0x00008168, 0x00000000 },
+ { 0x0000816c, 0x00000000 },
+ { 0x00008170, 0x18487320 },
+ { 0x00008174, 0xfaa4fa50 },
+ { 0x00008178, 0x00000100 },
+ { 0x0000817c, 0x00000000 },
+ { 0x000081c0, 0x00000000 },
+ { 0x000081c4, 0x00000000 },
+ { 0x000081d4, 0x00000000 },
+ { 0x000081ec, 0x00000000 },
+ { 0x000081f0, 0x00000000 },
+ { 0x000081f4, 0x00000000 },
+ { 0x000081f8, 0x00000000 },
+ { 0x000081fc, 0x00000000 },
+ { 0x00008200, 0x00000000 },
+ { 0x00008204, 0x00000000 },
+ { 0x00008208, 0x00000000 },
+ { 0x0000820c, 0x00000000 },
+ { 0x00008210, 0x00000000 },
+ { 0x00008214, 0x00000000 },
+ { 0x00008218, 0x00000000 },
+ { 0x0000821c, 0x00000000 },
+ { 0x00008220, 0x00000000 },
+ { 0x00008224, 0x00000000 },
+ { 0x00008228, 0x00000000 },
+ { 0x0000822c, 0x00000000 },
+ { 0x00008230, 0x00000000 },
+ { 0x00008234, 0x00000000 },
+ { 0x00008238, 0x00000000 },
+ { 0x0000823c, 0x00000000 },
+ { 0x00008240, 0x00100000 },
+ { 0x00008244, 0x0010f400 },
+ { 0x00008248, 0x00000100 },
+ { 0x0000824c, 0x0001e800 },
+ { 0x00008250, 0x00000000 },
+ { 0x00008254, 0x00000000 },
+ { 0x00008258, 0x00000000 },
+ { 0x0000825c, 0x400000ff },
+ { 0x00008260, 0x00080922 },
+ { 0x00008264, 0x88a00010 },
+ { 0x00008270, 0x00000000 },
+ { 0x00008274, 0x40000000 },
+ { 0x00008278, 0x003e4180 },
+ { 0x0000827c, 0x00000000 },
+ { 0x00008284, 0x0000002c },
+ { 0x00008288, 0x0000002c },
+ { 0x0000828c, 0x000000ff },
+ { 0x00008294, 0x00000000 },
+ { 0x00008298, 0x00000000 },
+ { 0x0000829c, 0x00000000 },
+ { 0x00008300, 0x00000040 },
+ { 0x00008314, 0x00000000 },
+ { 0x00008328, 0x00000000 },
+ { 0x0000832c, 0x00000007 },
+ { 0x00008330, 0x00000302 },
+ { 0x00008334, 0x00000e00 },
+ { 0x00008338, 0x00ff0000 },
+ { 0x0000833c, 0x00000000 },
+ { 0x00008340, 0x000107ff },
+ { 0x00008344, 0x01c81043 },
+ { 0x00008360, 0xffffffff },
+ { 0x00008364, 0xffffffff },
+ { 0x00008368, 0x00000000 },
+ { 0x00008370, 0x00000000 },
+ { 0x00008374, 0x000000ff },
+ { 0x00008378, 0x00000000 },
+ { 0x0000837c, 0x00000000 },
+ { 0x00008380, 0xffffffff },
+ { 0x00008384, 0xffffffff },
+ { 0x00008390, 0x0fffffff },
+ { 0x00008394, 0x0fffffff },
+ { 0x00008398, 0x00000000 },
+ { 0x0000839c, 0x00000000 },
+ { 0x000083a0, 0x00000000 },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0xafe68e30 },
+ { 0x00009810, 0xfd14e000 },
+ { 0x00009814, 0x9c0a9f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x0000a000 },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00200400 },
+ { 0x0000984c, 0x0040233c },
+ { 0x0000a84c, 0x0040233c },
+ { 0x00009854, 0x00000044 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00000000 },
+ { 0x00009910, 0x10002310 },
+ { 0x0000991c, 0x10000fff },
+ { 0x00009920, 0x04900000 },
+ { 0x0000a920, 0x04900000 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000004 },
+ { 0x00009930, 0x00000000 },
+ { 0x0000a930, 0x00000000 },
+ { 0x00009934, 0x1e1f2022 },
+ { 0x00009938, 0x0a0b0c0d },
+ { 0x0000993c, 0x00000000 },
+ { 0x00009948, 0x9280c00a },
+ { 0x0000994c, 0x00020028 },
+ { 0x00009954, 0x5f3ca3de },
+ { 0x00009958, 0x0108ecff },
+ { 0x00009940, 0x14750604 },
+ { 0x0000c95c, 0x004b6a8e },
+ { 0x00009970, 0x990bb514 },
+ { 0x00009974, 0x00000000 },
+ { 0x00009978, 0x00000001 },
+ { 0x0000997c, 0x00000000 },
+ { 0x000099a0, 0x00000000 },
+ { 0x000099a4, 0x00000001 },
+ { 0x000099a8, 0x201fff00 },
+ { 0x000099ac, 0x0c6f0000 },
+ { 0x000099b0, 0x03051000 },
+ { 0x000099b4, 0x00000820 },
+ { 0x000099c4, 0x06336f77 },
+ { 0x000099c8, 0x6af6532f },
+ { 0x000099cc, 0x08f186c8 },
+ { 0x000099d0, 0x00046384 },
+ { 0x000099dc, 0x00000000 },
+ { 0x000099e0, 0x00000000 },
+ { 0x000099e4, 0xaaaaaaaa },
+ { 0x000099e8, 0x3c466478 },
+ { 0x000099ec, 0x0cc80caa },
+ { 0x000099f0, 0x00000000 },
+ { 0x000099fc, 0x00001042 },
+ { 0x0000a1f4, 0x00fffeff },
+ { 0x0000a1f8, 0x00f5f9ff },
+ { 0x0000a1fc, 0xb79f6427 },
+ { 0x0000a208, 0x803e4788 },
+ { 0x0000a210, 0x4080a333 },
+ { 0x0000a214, 0x40206c10 },
+ { 0x0000a218, 0x009c4060 },
+ { 0x0000a220, 0x01834061 },
+ { 0x0000a224, 0x00000400 },
+ { 0x0000a228, 0x000003b5 },
+ { 0x0000a22c, 0x233f7180 },
+ { 0x0000a234, 0x20202020 },
+ { 0x0000a238, 0x20202020 },
+ { 0x0000a23c, 0x13c889af },
+ { 0x0000a240, 0x38490a20 },
+ { 0x0000a244, 0x00000000 },
+ { 0x0000a248, 0xfffffffc },
+ { 0x0000a24c, 0x00000000 },
+ { 0x0000a254, 0x00000000 },
+ { 0x0000a258, 0x0cdbd380 },
+ { 0x0000a25c, 0x0f0f0f01 },
+ { 0x0000a260, 0xdfa91f01 },
+ { 0x0000a264, 0x00418a11 },
+ { 0x0000b264, 0x00418a11 },
+ { 0x0000a268, 0x00000000 },
+ { 0x0000a26c, 0x0e79e5c6 },
+ { 0x0000b26c, 0x0e79e5c6 },
+ { 0x0000d270, 0x00820820 },
+ { 0x0000a278, 0x1ce739ce },
+ { 0x0000a27c, 0x050701ce },
+ { 0x0000d35c, 0x07ffffef },
+ { 0x0000d360, 0x0fffffe7 },
+ { 0x0000d364, 0x17ffffe5 },
+ { 0x0000d368, 0x1fffffe4 },
+ { 0x0000d36c, 0x37ffffe3 },
+ { 0x0000d370, 0x3fffffe3 },
+ { 0x0000d374, 0x57ffffe3 },
+ { 0x0000d378, 0x5fffffe2 },
+ { 0x0000d37c, 0x7fffffe2 },
+ { 0x0000d380, 0x7f3c7bba },
+ { 0x0000d384, 0xf3307ff0 },
+ { 0x0000a388, 0x0c000000 },
+ { 0x0000a38c, 0x20202020 },
+ { 0x0000a390, 0x20202020 },
+ { 0x0000a394, 0x1ce739ce },
+ { 0x0000a398, 0x000001ce },
+ { 0x0000b398, 0x000001ce },
+ { 0x0000a39c, 0x00000001 },
+ { 0x0000a3c8, 0x00000246 },
+ { 0x0000a3cc, 0x20202020 },
+ { 0x0000a3d0, 0x20202020 },
+ { 0x0000a3d4, 0x20202020 },
+ { 0x0000a3dc, 0x1ce739ce },
+ { 0x0000a3e0, 0x000001ce },
+ { 0x0000a3e4, 0x00000000 },
+ { 0x0000a3e8, 0x18c43433 },
+ { 0x0000a3ec, 0x00f70081 },
+ { 0x0000a3f0, 0x01036a1e },
+ { 0x0000a3f4, 0x00000000 },
+ { 0x0000b3f4, 0x00000000 },
+ { 0x0000a7d8, 0x000003f1 },
+ { 0x00007800, 0x00000800 },
+ { 0x00007804, 0x6c35ffc2 },
+ { 0x00007808, 0x6db6c000 },
+ { 0x0000780c, 0x6db6cb30 },
+ { 0x00007810, 0x6db6cb6c },
+ { 0x00007814, 0x0501e200 },
+ { 0x00007818, 0x0094128d },
+ { 0x0000781c, 0x976ee392 },
+ { 0x00007820, 0xf75ff6fc },
+ { 0x00007824, 0x00040000 },
+ { 0x00007828, 0xdb003012 },
+ { 0x0000782c, 0x04924914 },
+ { 0x00007830, 0x21084210 },
+ { 0x00007834, 0x00140000 },
+ { 0x00007838, 0x0e4548d8 },
+ { 0x0000783c, 0x54214514 },
+ { 0x00007840, 0x02025830 },
+ { 0x00007844, 0x71c0d388 },
+ { 0x00007848, 0x934934a8 },
+ { 0x00007850, 0x00000000 },
+ { 0x00007854, 0x00000800 },
+ { 0x00007858, 0x6c35ffc2 },
+ { 0x0000785c, 0x6db6c000 },
+ { 0x00007860, 0x6db6cb30 },
+ { 0x00007864, 0x6db6cb6c },
+ { 0x00007868, 0x0501e200 },
+ { 0x0000786c, 0x0094128d },
+ { 0x00007870, 0x976ee392 },
+ { 0x00007874, 0xf75ff6fc },
+ { 0x00007878, 0x00040000 },
+ { 0x0000787c, 0xdb003012 },
+ { 0x00007880, 0x04924914 },
+ { 0x00007884, 0x21084210 },
+ { 0x00007888, 0x001b6db0 },
+ { 0x0000788c, 0x00376b63 },
+ { 0x00007890, 0x06db6db6 },
+ { 0x00007894, 0x006d8000 },
+ { 0x00007898, 0x48100000 },
+ { 0x0000789c, 0x00000000 },
+ { 0x000078a0, 0x08000000 },
+ { 0x000078a4, 0x0007ffd8 },
+ { 0x000078a8, 0x0007ffd8 },
+ { 0x000078ac, 0x001c0020 },
+ { 0x000078b0, 0x00060aeb },
+ { 0x000078b4, 0x40008080 },
+ { 0x000078b8, 0x2a850160 },
+};
+
+static const u_int32_t ar9287Modes_tx_gain_9287_1_1[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
+ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 },
+ { 0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004 },
+ { 0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a },
+ { 0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c },
+ { 0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b },
+ { 0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a },
+ { 0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a },
+ { 0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a },
+ { 0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a },
+ { 0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a },
+ { 0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a },
+ { 0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c },
+ { 0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc },
+ { 0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4 },
+ { 0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc },
+ { 0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede },
+ { 0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e },
+ { 0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e },
+ { 0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e },
+ { 0x0000a780, 0x00000000, 0x00000000, 0x00000062, 0x00000062, 0x00000062 },
+ { 0x0000a784, 0x00000000, 0x00000000, 0x00004064, 0x00004064, 0x00004064 },
+ { 0x0000a788, 0x00000000, 0x00000000, 0x000080a4, 0x000080a4, 0x000080a4 },
+ { 0x0000a78c, 0x00000000, 0x00000000, 0x0000c0aa, 0x0000c0aa, 0x0000c0aa },
+ { 0x0000a790, 0x00000000, 0x00000000, 0x000100ac, 0x000100ac, 0x000100ac },
+ { 0x0000a794, 0x00000000, 0x00000000, 0x000140b4, 0x000140b4, 0x000140b4 },
+ { 0x0000a798, 0x00000000, 0x00000000, 0x000180f4, 0x000180f4, 0x000180f4 },
+ { 0x0000a79c, 0x00000000, 0x00000000, 0x0001c134, 0x0001c134, 0x0001c134 },
+ { 0x0000a7a0, 0x00000000, 0x00000000, 0x00020174, 0x00020174, 0x00020174 },
+ { 0x0000a7a4, 0x00000000, 0x00000000, 0x0002417c, 0x0002417c, 0x0002417c },
+ { 0x0000a7a8, 0x00000000, 0x00000000, 0x0002817e, 0x0002817e, 0x0002817e },
+ { 0x0000a7ac, 0x00000000, 0x00000000, 0x0002c1be, 0x0002c1be, 0x0002c1be },
+ { 0x0000a7b0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7b4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7b8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7bc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7c0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7c4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7c8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7cc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7d0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7d4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 },
+};
+
+static const u_int32_t ar9287Modes_rx_gain_9287_1_1[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
+ { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
+ { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
+ { 0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
+ { 0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
+ { 0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
+ { 0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
+ { 0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
+ { 0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
+ { 0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
+ { 0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
+ { 0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
+ { 0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
+ { 0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
+ { 0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
+ { 0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
+ { 0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
+ { 0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
+ { 0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
+ { 0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
+ { 0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
+ { 0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
+ { 0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
+ { 0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
+ { 0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
+ { 0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
+ { 0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
+ { 0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
+ { 0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
+ { 0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
+ { 0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
+ { 0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
+ { 0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
+ { 0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
+ { 0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
+ { 0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
+ { 0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
+ { 0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
+ { 0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
+ { 0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
+ { 0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
+ { 0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
+ { 0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
+ { 0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
+ { 0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
+ { 0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
+ { 0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
+ { 0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
+ { 0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
+ { 0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
+ { 0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
+ { 0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
+ { 0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
+ { 0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
+ { 0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
+ { 0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
+ { 0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
+ { 0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
+ { 0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
+ { 0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
+ { 0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
+ { 0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
+ { 0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
+ { 0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
+ { 0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
+ { 0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
+ { 0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
+ { 0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
+ { 0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
+ { 0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
+ { 0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
+ { 0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
+ { 0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
+ { 0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
+ { 0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
+ { 0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
+ { 0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
+ { 0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
+ { 0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
+ { 0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
+ { 0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
+ { 0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
+ { 0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
+ { 0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
+ { 0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
+ { 0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
+ { 0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
+ { 0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
+ { 0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
+ { 0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
+ { 0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
+ { 0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
+ { 0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
+ { 0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
+ { 0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
+ { 0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
+ { 0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
+ { 0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
+ { 0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
+ { 0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
+ { 0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
+ { 0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
+ { 0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
+ { 0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
+ { 0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
+ { 0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
+ { 0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
+ { 0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
+ { 0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
+ { 0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
+ { 0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
+ { 0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
+ { 0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
+ { 0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
+ { 0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
+ { 0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
+ { 0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
+ { 0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
+ { 0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
+ { 0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
+ { 0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
+ { 0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
+ { 0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
+ { 0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
+ { 0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
+ { 0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
+ { 0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
+ { 0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
+ { 0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
+ { 0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
+ { 0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
+ { 0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
+ { 0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
+ { 0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
+ { 0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
+ { 0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
+ { 0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
+ { 0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
+ { 0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
+ { 0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
+ { 0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
+ { 0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
+ { 0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
+ { 0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
+ { 0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
+ { 0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
+ { 0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
+ { 0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
+ { 0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
+ { 0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
+ { 0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
+ { 0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
+ { 0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
+ { 0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
+ { 0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
+ { 0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
+ { 0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
+ { 0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
+ { 0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
+ { 0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
+ { 0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
+ { 0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
+ { 0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
+ { 0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
+ { 0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
+ { 0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
+ { 0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
+ { 0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
+ { 0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
+ { 0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
+ { 0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
+ { 0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
+ { 0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
+ { 0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
+ { 0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
+ { 0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
+ { 0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
+ { 0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
+ { 0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
+ { 0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
+ { 0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
+ { 0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
+ { 0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
+ { 0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
+ { 0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
+ { 0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
+ { 0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
+ { 0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
+ { 0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
+ { 0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
+ { 0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
+ { 0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
+ { 0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
+ { 0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
+ { 0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
+ { 0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
+ { 0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
+ { 0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
+ { 0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
+ { 0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
+ { 0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
+ { 0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
+ { 0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
+ { 0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
+ { 0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
+ { 0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
+ { 0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
+ { 0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
+ { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
+};
+
+static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0xc01dcffd },
+ {0x00004040, 0x1aaabe41 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
+};
+
+static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0xc01dcffc },
+ {0x00004040, 0x1aaabe41 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
+};
+
+
+/* AR9271 initialization values automaticaly created: 03/23/09 */
+static const u_int32_t ar9271Modes_9271_1_0[][6] = {
+ { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
+ { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
+ { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
+ { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
+ { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
+ { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f },
+ { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
+ { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
+ { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
+ { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
+ { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
+ { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
+ { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 },
+ { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
+ { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
+ { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+ { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
+ { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18 },
+ { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
+ { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
+ { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
+ { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d },
+ { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010 },
+ { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c },
+ { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
+ { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+ { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+ { 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 },
+ { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
+ { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
+ { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 },
+ { 0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 },
+ { 0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 },
+ { 0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 },
+ { 0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 },
+ { 0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 },
+ { 0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 },
+ { 0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 },
+ { 0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 },
+ { 0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 },
+ { 0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 },
+ { 0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 },
+ { 0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 },
+ { 0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 },
+ { 0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 },
+ { 0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 },
+ { 0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 },
+ { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
+ { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
+ { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
+ { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 },
+ { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
+ { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
+ { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
+ { 0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 },
+ { 0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 },
+ { 0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 },
+ { 0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 },
+ { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
+ { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
+ { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
+ { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
+ { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
+ { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
+ { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
+ { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+ { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+ { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
+ { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
+ { 0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 },
+ { 0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 },
+ { 0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 },
+ { 0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 },
+ { 0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 },
+ { 0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 },
+ { 0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 },
+ { 0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 },
+ { 0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 },
+ { 0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 },
+ { 0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 },
+ { 0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 },
+ { 0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 },
+ { 0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 },
+ { 0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 },
+ { 0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 },
+ { 0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 },
+ { 0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 },
+ { 0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 },
+ { 0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 },
+ { 0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 },
+ { 0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 },
+ { 0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 },
+ { 0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 },
+ { 0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 },
+ { 0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 },
+ { 0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 },
+ { 0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 },
+ { 0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 },
+ { 0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 },
+ { 0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 },
+ { 0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 },
+ { 0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 },
+ { 0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 },
+ { 0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 },
+ { 0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 },
+ { 0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 },
+ { 0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 },
+ { 0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 },
+ { 0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 },
+ { 0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 },
+ { 0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 },
+ { 0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 },
+ { 0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 },
+ { 0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 },
+ { 0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 },
+ { 0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 },
+ { 0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 },
+ { 0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 },
+ { 0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 },
+ { 0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 },
+ { 0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 },
+ { 0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 },
+ { 0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 },
+ { 0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 },
+ { 0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 },
+ { 0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 },
+ { 0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 },
+ { 0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 },
+ { 0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 },
+ { 0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 },
+ { 0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 },
+ { 0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 },
+ { 0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 },
+ { 0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 },
+ { 0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 },
+ { 0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 },
+ { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
+ { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
+ { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
+ { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 },
+ { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
+ { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
+ { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
+ { 0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 },
+ { 0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 },
+ { 0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 },
+ { 0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 },
+ { 0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
+ { 0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
+ { 0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
+ { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
+ { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
+ { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
+ { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
+ { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+ { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+ { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
+ { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
+ { 0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 },
+ { 0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 },
+ { 0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 },
+ { 0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 },
+ { 0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 },
+ { 0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 },
+ { 0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 },
+ { 0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 },
+ { 0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 },
+ { 0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 },
+ { 0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 },
+ { 0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 },
+ { 0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 },
+ { 0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 },
+ { 0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 },
+ { 0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 },
+ { 0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 },
+ { 0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 },
+ { 0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 },
+ { 0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 },
+ { 0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 },
+ { 0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 },
+ { 0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 },
+ { 0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 },
+ { 0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 },
+ { 0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 },
+ { 0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 },
+ { 0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 },
+ { 0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 },
+ { 0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 },
+ { 0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 },
+ { 0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 },
+ { 0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 },
+ { 0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 },
+ { 0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 },
+ { 0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 },
+ { 0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 },
+ { 0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 },
+ { 0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 },
+ { 0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 },
+ { 0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 },
+ { 0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 },
+ { 0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 },
+ { 0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 },
+ { 0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 },
+ { 0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 },
+ { 0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 },
+ { 0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 },
+ { 0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 },
+ { 0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 },
+ { 0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
+ { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
+ { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
+ { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
+ { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652 },
+ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
+ { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 },
+ { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 },
+ { 0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000 },
+ { 0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000 },
+ { 0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000 },
+ { 0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000 },
+ { 0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000 },
+ { 0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000 },
+ { 0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000 },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000 },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000 },
+ { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 },
+ { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
+ { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
+ { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+ { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+ { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+};
+
+static const u_int32_t ar9271Common_9271_1_0[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000030, 0x00020045 },
+ { 0x00000034, 0x00000005 },
+ { 0x00000040, 0x00000000 },
+ { 0x00000044, 0x00000008 },
+ { 0x00000048, 0x00000008 },
+ { 0x0000004c, 0x00000010 },
+ { 0x00000050, 0x00000000 },
+ { 0x00000054, 0x0000001f },
+ { 0x00000800, 0x00000000 },
+ { 0x00000804, 0x00000000 },
+ { 0x00000808, 0x00000000 },
+ { 0x0000080c, 0x00000000 },
+ { 0x00000810, 0x00000000 },
+ { 0x00000814, 0x00000000 },
+ { 0x00000818, 0x00000000 },
+ { 0x0000081c, 0x00000000 },
+ { 0x00000820, 0x00000000 },
+ { 0x00000824, 0x00000000 },
+ { 0x00001040, 0x002ffc0f },
+ { 0x00001044, 0x002ffc0f },
+ { 0x00001048, 0x002ffc0f },
+ { 0x0000104c, 0x002ffc0f },
+ { 0x00001050, 0x002ffc0f },
+ { 0x00001054, 0x002ffc0f },
+ { 0x00001058, 0x002ffc0f },
+ { 0x0000105c, 0x002ffc0f },
+ { 0x00001060, 0x002ffc0f },
+ { 0x00001064, 0x002ffc0f },
+ { 0x00001230, 0x00000000 },
+ { 0x00001270, 0x00000000 },
+ { 0x00001038, 0x00000000 },
+ { 0x00001078, 0x00000000 },
+ { 0x000010b8, 0x00000000 },
+ { 0x000010f8, 0x00000000 },
+ { 0x00001138, 0x00000000 },
+ { 0x00001178, 0x00000000 },
+ { 0x000011b8, 0x00000000 },
+ { 0x000011f8, 0x00000000 },
+ { 0x00001238, 0x00000000 },
+ { 0x00001278, 0x00000000 },
+ { 0x000012b8, 0x00000000 },
+ { 0x000012f8, 0x00000000 },
+ { 0x00001338, 0x00000000 },
+ { 0x00001378, 0x00000000 },
+ { 0x000013b8, 0x00000000 },
+ { 0x000013f8, 0x00000000 },
+ { 0x00001438, 0x00000000 },
+ { 0x00001478, 0x00000000 },
+ { 0x000014b8, 0x00000000 },
+ { 0x000014f8, 0x00000000 },
+ { 0x00001538, 0x00000000 },
+ { 0x00001578, 0x00000000 },
+ { 0x000015b8, 0x00000000 },
+ { 0x000015f8, 0x00000000 },
+ { 0x00001638, 0x00000000 },
+ { 0x00001678, 0x00000000 },
+ { 0x000016b8, 0x00000000 },
+ { 0x000016f8, 0x00000000 },
+ { 0x00001738, 0x00000000 },
+ { 0x00001778, 0x00000000 },
+ { 0x000017b8, 0x00000000 },
+ { 0x000017f8, 0x00000000 },
+ { 0x0000103c, 0x00000000 },
+ { 0x0000107c, 0x00000000 },
+ { 0x000010bc, 0x00000000 },
+ { 0x000010fc, 0x00000000 },
+ { 0x0000113c, 0x00000000 },
+ { 0x0000117c, 0x00000000 },
+ { 0x000011bc, 0x00000000 },
+ { 0x000011fc, 0x00000000 },
+ { 0x0000123c, 0x00000000 },
+ { 0x0000127c, 0x00000000 },
+ { 0x000012bc, 0x00000000 },
+ { 0x000012fc, 0x00000000 },
+ { 0x0000133c, 0x00000000 },
+ { 0x0000137c, 0x00000000 },
+ { 0x000013bc, 0x00000000 },
+ { 0x000013fc, 0x00000000 },
+ { 0x0000143c, 0x00000000 },
+ { 0x0000147c, 0x00000000 },
+ { 0x00004030, 0x00000002 },
+ { 0x0000403c, 0x00000002 },
+ { 0x00004024, 0x0000001f },
+ { 0x00004060, 0x00000000 },
+ { 0x00004064, 0x00000000 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000700 },
+ { 0x00008020, 0x00000000 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008048, 0x00000000 },
+ { 0x00008054, 0x00000000 },
+ { 0x00008058, 0x02000000 },
+ { 0x0000805c, 0x000fc78f },
+ { 0x00008060, 0x0000000f },
+ { 0x00008064, 0x00000000 },
+ { 0x00008070, 0x00000000 },
+ { 0x000080b0, 0x00000000 },
+ { 0x000080b4, 0x00000000 },
+ { 0x000080b8, 0x00000000 },
+ { 0x000080bc, 0x00000000 },
+ { 0x000080c0, 0x2a80001a },
+ { 0x000080c4, 0x05dc01e0 },
+ { 0x000080c8, 0x1f402710 },
+ { 0x000080cc, 0x01f40000 },
+ { 0x000080d0, 0x00001e00 },
+ { 0x000080d4, 0x00000000 },
+ { 0x000080d8, 0x00400000 },
+ { 0x000080e0, 0xffffffff },
+ { 0x000080e4, 0x0000ffff },
+ { 0x000080e8, 0x003f3f3f },
+ { 0x000080ec, 0x00000000 },
+ { 0x000080f0, 0x00000000 },
+ { 0x000080f4, 0x00000000 },
+ { 0x000080f8, 0x00000000 },
+ { 0x000080fc, 0x00020000 },
+ { 0x00008100, 0x00020000 },
+ { 0x00008104, 0x00000001 },
+ { 0x00008108, 0x00000052 },
+ { 0x0000810c, 0x00000000 },
+ { 0x00008110, 0x00000168 },
+ { 0x00008118, 0x000100aa },
+ { 0x0000811c, 0x00003210 },
+ { 0x00008120, 0x08f04814 },
+ { 0x00008124, 0x00000000 },
+ { 0x00008128, 0x00000000 },
+ { 0x0000812c, 0x00000000 },
+ { 0x00008130, 0x00000000 },
+ { 0x00008134, 0x00000000 },
+ { 0x00008138, 0x00000000 },
+ { 0x0000813c, 0x00000000 },
+ { 0x00008144, 0xffffffff },
+ { 0x00008168, 0x00000000 },
+ { 0x0000816c, 0x00000000 },
+ { 0x00008170, 0x32143320 },
+ { 0x00008174, 0xfaa4fa50 },
+ { 0x00008178, 0x00000100 },
+ { 0x0000817c, 0x00000000 },
+ { 0x000081c0, 0x00000000 },
+ { 0x000081d0, 0x0000320a },
+ { 0x000081ec, 0x00000000 },
+ { 0x000081f0, 0x00000000 },
+ { 0x000081f4, 0x00000000 },
+ { 0x000081f8, 0x00000000 },
+ { 0x000081fc, 0x00000000 },
+ { 0x00008200, 0x00000000 },
+ { 0x00008204, 0x00000000 },
+ { 0x00008208, 0x00000000 },
+ { 0x0000820c, 0x00000000 },
+ { 0x00008210, 0x00000000 },
+ { 0x00008214, 0x00000000 },
+ { 0x00008218, 0x00000000 },
+ { 0x0000821c, 0x00000000 },
+ { 0x00008220, 0x00000000 },
+ { 0x00008224, 0x00000000 },
+ { 0x00008228, 0x00000000 },
+ { 0x0000822c, 0x00000000 },
+ { 0x00008230, 0x00000000 },
+ { 0x00008234, 0x00000000 },
+ { 0x00008238, 0x00000000 },
+ { 0x0000823c, 0x00000000 },
+ { 0x00008240, 0x00100000 },
+ { 0x00008244, 0x0010f400 },
+ { 0x00008248, 0x00000100 },
+ { 0x0000824c, 0x0001e800 },
+ { 0x00008250, 0x00000000 },
+ { 0x00008254, 0x00000000 },
+ { 0x00008258, 0x00000000 },
+ { 0x0000825c, 0x400000ff },
+ { 0x00008260, 0x00080922 },
+ { 0x00008264, 0xa8a00010 },
+ { 0x00008270, 0x00000000 },
+ { 0x00008274, 0x40000000 },
+ { 0x00008278, 0x003e4180 },
+ { 0x0000827c, 0x00000000 },
+ { 0x00008284, 0x0000002c },
+ { 0x00008288, 0x0000002c },
+ { 0x0000828c, 0x00000000 },
+ { 0x00008294, 0x00000000 },
+ { 0x00008298, 0x00000000 },
+ { 0x0000829c, 0x00000000 },
+ { 0x00008300, 0x00000040 },
+ { 0x00008314, 0x00000000 },
+ { 0x00008328, 0x00000000 },
+ { 0x0000832c, 0x00000001 },
+ { 0x00008330, 0x00000302 },
+ { 0x00008334, 0x00000e00 },
+ { 0x00008338, 0x00ff0000 },
+ { 0x0000833c, 0x00000000 },
+ { 0x00008340, 0x00010380 },
+ { 0x00008344, 0x00581043 },
+ { 0x00007010, 0x00000030 },
+ { 0x00007034, 0x00000002 },
+ { 0x00007038, 0x000004c2 },
+ { 0x00007800, 0x00140000 },
+ { 0x00007804, 0x0e4548d8 },
+ { 0x00007808, 0x54214514 },
+ { 0x0000780c, 0x02025820 },
+ { 0x00007810, 0x71c0d388 },
+ { 0x00007814, 0x924934a8 },
+ { 0x0000781c, 0x00000000 },
+ { 0x00007820, 0x00000c04 },
+ { 0x00007824, 0x00d86bff },
+ { 0x00007828, 0x66964300 },
+ { 0x0000782c, 0x8db6d961 },
+ { 0x00007830, 0x8db6d96c },
+ { 0x00007834, 0x6140008b },
+ { 0x00007838, 0x00000029 },
+ { 0x0000783c, 0x72ee0a72 },
+ { 0x00007840, 0xbbfffffc },
+ { 0x00007844, 0x000c0db6 },
+ { 0x00007848, 0x6db61b6f },
+ { 0x0000784c, 0x6d9b66db },
+ { 0x00007850, 0x6d8c6dba },
+ { 0x00007854, 0x00040000 },
+ { 0x00007858, 0xdb003012 },
+ { 0x0000785c, 0x04924914 },
+ { 0x00007860, 0x21084210 },
+ { 0x00007864, 0xf7d7ffde },
+ { 0x00007868, 0xc2034080 },
+ { 0x0000786c, 0x48609eb4 },
+ { 0x00007870, 0x10142c00 },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0xafe68e30 },
+ { 0x00009810, 0xfd14e000 },
+ { 0x00009814, 0x9c0a9f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x0000a000 },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00200400 },
+ { 0x0000984c, 0x0040233c },
+ { 0x00009854, 0x00000044 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00000000 },
+ { 0x00009910, 0x30002310 },
+ { 0x0000991c, 0x10000fff },
+ { 0x00009920, 0x04900000 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000004 },
+ { 0x00009934, 0x1e1f2022 },
+ { 0x00009938, 0x0a0b0c0d },
+ { 0x0000993c, 0x00000000 },
+ { 0x00009940, 0x14750604 },
+ { 0x00009948, 0x9280c00a },
+ { 0x0000994c, 0x00020028 },
+ { 0x00009954, 0x5f3ca3de },
+ { 0x00009958, 0x0108ecff },
+ { 0x00009968, 0x000003ce },
+ { 0x00009970, 0x192bb515 },
+ { 0x00009974, 0x00000000 },
+ { 0x00009978, 0x00000001 },
+ { 0x0000997c, 0x00000000 },
+ { 0x00009980, 0x00000000 },
+ { 0x00009984, 0x00000000 },
+ { 0x00009988, 0x00000000 },
+ { 0x0000998c, 0x00000000 },
+ { 0x00009990, 0x00000000 },
+ { 0x00009994, 0x00000000 },
+ { 0x00009998, 0x00000000 },
+ { 0x0000999c, 0x00000000 },
+ { 0x000099a0, 0x00000000 },
+ { 0x000099a4, 0x00000001 },
+ { 0x000099a8, 0x201fff00 },
+ { 0x000099ac, 0x2def0400 },
+ { 0x000099b0, 0x03051000 },
+ { 0x000099b4, 0x00000820 },
+ { 0x000099dc, 0x00000000 },
+ { 0x000099e0, 0x00000000 },
+ { 0x000099e4, 0xaaaaaaaa },
+ { 0x000099e8, 0x3c466478 },
+ { 0x000099ec, 0x0cc80caa },
+ { 0x000099f0, 0x00000000 },
+ { 0x0000a1f4, 0x00000000 },
+ { 0x0000a1f8, 0x71733d01 },
+ { 0x0000a1fc, 0xd0ad5c12 },
+ { 0x0000a208, 0x803e68c8 },
+ { 0x0000a210, 0x4080a333 },
+ { 0x0000a214, 0x00206c10 },
+ { 0x0000a218, 0x009c4060 },
+ { 0x0000a220, 0x01834061 },
+ { 0x0000a224, 0x00000400 },
+ { 0x0000a228, 0x000003b5 },
+ { 0x0000a22c, 0x00000000 },
+ { 0x0000a234, 0x20202020 },
+ { 0x0000a238, 0x20202020 },
+ { 0x0000a244, 0x00000000 },
+ { 0x0000a248, 0xfffffffc },
+ { 0x0000a24c, 0x00000000 },
+ { 0x0000a254, 0x00000000 },
+ { 0x0000a258, 0x0ccb5380 },
+ { 0x0000a25c, 0x15151501 },
+ { 0x0000a260, 0xdfa90f01 },
+ { 0x0000a268, 0x00000000 },
+ { 0x0000a26c, 0x0ebae9e6 },
+ { 0x0000a278, 0x3bdef7bd },
+ { 0x0000a27c, 0x050e83bd },
+ { 0x0000a388, 0x0c000000 },
+ { 0x0000a38c, 0x20202020 },
+ { 0x0000a390, 0x20202020 },
+ { 0x0000a394, 0x3bdef7bd },
+ { 0x0000a398, 0x000003bd },
+ { 0x0000a39c, 0x00000001 },
+ { 0x0000a3a0, 0x00000000 },
+ { 0x0000a3a4, 0x00000000 },
+ { 0x0000a3a8, 0x00000000 },
+ { 0x0000a3ac, 0x00000000 },
+ { 0x0000a3b0, 0x00000000 },
+ { 0x0000a3b4, 0x00000000 },
+ { 0x0000a3b8, 0x00000000 },
+ { 0x0000a3bc, 0x00000000 },
+ { 0x0000a3c0, 0x00000000 },
+ { 0x0000a3c4, 0x00000000 },
+ { 0x0000a3cc, 0x20202020 },
+ { 0x0000a3d0, 0x20202020 },
+ { 0x0000a3d4, 0x20202020 },
+ { 0x0000a3dc, 0x3bdef7bd },
+ { 0x0000a3e0, 0x000003bd },
+ { 0x0000a3e4, 0x00000000 },
+ { 0x0000a3e8, 0x18c43433 },
+ { 0x0000a3ec, 0x00f70081 },
+ { 0x0000a3f0, 0x01036a2f },
+ { 0x0000a3f4, 0x00000000 },
+ { 0x0000d270, 0x0d820820 },
+ { 0x0000d35c, 0x07ffffef },
+ { 0x0000d360, 0x0fffffe7 },
+ { 0x0000d364, 0x17ffffe5 },
+ { 0x0000d368, 0x1fffffe4 },
+ { 0x0000d36c, 0x37ffffe3 },
+ { 0x0000d370, 0x3fffffe3 },
+ { 0x0000d374, 0x57ffffe3 },
+ { 0x0000d378, 0x5fffffe2 },
+ { 0x0000d37c, 0x7fffffe2 },
+ { 0x0000d380, 0x7f3c7bba },
+ { 0x0000d384, 0xf3307ff0 },
+};
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 8ae4ec21667b..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)
return REG_READ(ah, AR_QTXDP(q));
}
-bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
+void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
{
REG_WRITE(ah, AR_QTXDP(q), txdp);
-
- return true;
}
-bool ath9k_hw_txstart(struct ath_hw *ah, u32 q)
+void ath9k_hw_txstart(struct ath_hw *ah, u32 q)
{
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q);
-
REG_WRITE(ah, AR_Q_TXE, 1 << q);
-
- return true;
}
u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
@@ -178,7 +173,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
#undef ATH9K_TIME_QUANTUM
}
-bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
+void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 segLen, bool firstSeg,
bool lastSeg, const struct ath_desc *ds0)
{
@@ -202,8 +197,6 @@ bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
-
- return true;
}
void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
@@ -825,13 +818,29 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
- ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
- ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
- ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
- ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
- ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
- ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
- ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
+ if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
+ ds->ds_rxstat.rs_rssi = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ctl0 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ctl1 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ctl2 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ext0 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ext1 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ext2 = ATH9K_RSSI_BAD;
+ } else {
+ ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+ ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt00);
+ ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt01);
+ ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt02);
+ ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt10);
+ ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt11);
+ ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt12);
+ }
if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
else
@@ -872,7 +881,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
return 0;
}
-bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
+void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 size, u32 flags)
{
struct ar5416_desc *ads = AR5416DESC(ds);
@@ -885,8 +894,6 @@ bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
ads->ds_rxstatus8 &= ~AR_RxDone;
if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
memset(&(ads->u), 0, sizeof(ads->u));
-
- return true;
}
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..f56e77da6c3e 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -568,6 +568,7 @@ enum ath9k_rx_filter {
ATH9K_RX_FILTER_PROBEREQ = 0x00000080,
ATH9K_RX_FILTER_PHYERR = 0x00000100,
ATH9K_RX_FILTER_MYBEACON = 0x00000200,
+ ATH9K_RX_FILTER_COMP_BAR = 0x00000400,
ATH9K_RX_FILTER_PSPOLL = 0x00004000,
ATH9K_RX_FILTER_PHYRADAR = 0x00002000,
ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000,
@@ -628,12 +629,12 @@ struct ath9k_channel;
struct ath_rate_table;
u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q);
-bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp);
-bool ath9k_hw_txstart(struct ath_hw *ah, u32 q);
+void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp);
+void ath9k_hw_txstart(struct ath_hw *ah, u32 q);
u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q);
bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel);
bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q);
-bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
+void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 segLen, bool firstSeg,
bool lastSeg, const struct ath_desc *ds0);
void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds);
@@ -668,7 +669,7 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q);
bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q);
int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 pa, struct ath_desc *nds, u64 tsf);
-bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
+void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 size, u32 flags);
bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
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 66a6c1f5022a..3dc7b5a13e64 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -17,8 +17,6 @@
#include <linux/nl80211.h>
#include "ath9k.h"
-#define ATH_PCI_VERSION "0.1"
-
static char *dev_info = "ath9k";
MODULE_AUTHOR("Atheros Communications");
@@ -342,6 +340,7 @@ static void ath_ani_calibrate(unsigned long data)
* don't calibrate when we're scanning.
* we are most likely not on our home channel.
*/
+ spin_lock(&sc->ani_lock);
if (sc->sc_flags & SC_OP_SCANNING)
goto set_timer;
@@ -385,7 +384,7 @@ static void ath_ani_calibrate(unsigned long data)
if (longcal || shortcal || aniflag) {
/* Call ANI routine if necessary */
if (aniflag)
- ath9k_hw_ani_monitor(ah, &sc->nodestats, ah->curchan);
+ ath9k_hw_ani_monitor(ah, ah->curchan);
/* Perform calibration if necessary */
if (longcal || shortcal) {
@@ -405,6 +404,7 @@ static void ath_ani_calibrate(unsigned long data)
ath9k_ps_restore(sc);
set_timer:
+ spin_unlock(&sc->ani_lock);
/*
* Set timer interval based on previous results.
* The interval must be the shortest necessary to satisfy ANI,
@@ -439,8 +439,8 @@ static void ath_start_ani(struct ath_softc *sc)
*/
void ath_update_chainmask(struct ath_softc *sc, int is_ht)
{
- if (is_ht ||
- (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) {
+ if ((sc->sc_flags & SC_OP_SCANNING) || is_ht ||
+ (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE)) {
sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
} else {
@@ -460,9 +460,10 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
if (sc->sc_flags & SC_OP_TXAGGR) {
ath_tx_node_init(sc, an);
- an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
+ an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
sta->ht_cap.ampdu_factor);
an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
+ an->last_rssi = ATH_RSSI_DUMMY_MARKER;
}
}
@@ -496,8 +497,7 @@ static void ath9k_tasklet(unsigned long data)
if (status & ATH9K_INT_TX)
ath_tx_tasklet(sc);
- if ((status & ATH9K_INT_TSFOOR) &&
- (sc->hw->conf.flags & IEEE80211_CONF_PS)) {
+ if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
/*
* TSF sync does not look correct; remain awake to sync with
* the next Beacon.
@@ -506,6 +506,10 @@ static void ath9k_tasklet(unsigned long data)
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC;
}
+ if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ if (status & ATH9K_INT_GENTIMER)
+ ath_gen_timer_isr(sc->sc_ah);
+
/* re-enable hardware interrupt */
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
ath9k_ps_restore(sc);
@@ -521,7 +525,8 @@ irqreturn_t ath_isr(int irq, void *dev)
ATH9K_INT_TX | \
ATH9K_INT_BMISS | \
ATH9K_INT_CST | \
- ATH9K_INT_TSFOOR)
+ ATH9K_INT_TSFOOR | \
+ ATH9K_INT_GENTIMER)
struct ath_softc *sc = dev;
struct ath_hw *ah = sc->sc_ah;
@@ -589,7 +594,7 @@ irqreturn_t ath_isr(int irq, void *dev)
* it will clear whatever condition caused
* the interrupt.
*/
- ath9k_hw_procmibevent(ah, &sc->nodestats);
+ ath9k_hw_procmibevent(ah);
ath9k_hw_set_interrupts(ah, sc->imask);
}
@@ -885,8 +890,7 @@ static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
static void setup_ht_cap(struct ath_softc *sc,
struct ieee80211_sta_ht_cap *ht_info)
{
-#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */
-#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */
+ u8 tx_streams, rx_streams;
ht_info->ht_supported = true;
ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
@@ -894,64 +898,61 @@ static void setup_ht_cap(struct ath_softc *sc,
IEEE80211_HT_CAP_SGI_40 |
IEEE80211_HT_CAP_DSSSCCK40;
- ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536;
- ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8;
+ ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
/* set up supported mcs set */
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+ tx_streams = !(sc->tx_chainmask & (sc->tx_chainmask - 1)) ? 1 : 2;
+ rx_streams = !(sc->rx_chainmask & (sc->rx_chainmask - 1)) ? 1 : 2;
- switch(sc->rx_chainmask) {
- case 1:
- ht_info->mcs.rx_mask[0] = 0xff;
- break;
- case 3:
- case 5:
- case 7:
- default:
- ht_info->mcs.rx_mask[0] = 0xff;
- ht_info->mcs.rx_mask[1] = 0xff;
- break;
+ if (tx_streams != rx_streams) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n",
+ tx_streams, rx_streams);
+ ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+ ht_info->mcs.tx_params |= ((tx_streams - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
}
- ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+ ht_info->mcs.rx_mask[0] = 0xff;
+ if (rx_streams >= 2)
+ ht_info->mcs.rx_mask[1] = 0xff;
+
+ ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
}
static void ath9k_bss_assoc_info(struct ath_softc *sc,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
{
- struct ath_vif *avp = (void *)vif->drv_priv;
if (bss_conf->assoc) {
DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
bss_conf->aid, sc->curbssid);
/* New association, store aid */
- if (avp->av_opmode == NL80211_IFTYPE_STATION) {
- sc->curaid = bss_conf->aid;
- ath9k_hw_write_associd(sc);
+ sc->curaid = bss_conf->aid;
+ ath9k_hw_write_associd(sc);
- /*
- * Request a re-configuration of Beacon related timers
- * on the receipt of the first Beacon frame (i.e.,
- * after time sync with the AP).
- */
- sc->sc_flags |= SC_OP_BEACON_SYNC;
- }
+ /*
+ * Request a re-configuration of Beacon related timers
+ * on the receipt of the first Beacon frame (i.e.,
+ * after time sync with the AP).
+ */
+ sc->sc_flags |= SC_OP_BEACON_SYNC;
/* Configure the beacon */
ath_beacon_config(sc, vif);
/* Reset rssi stats */
- sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
- sc->nodestats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
- sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
- sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
+ sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
ath_start_ani(sc);
} else {
DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
sc->curaid = 0;
+ /* Stop ANI */
+ del_timer_sync(&sc->ani.timer);
}
}
@@ -969,15 +970,16 @@ static void ath_led_blink_work(struct work_struct *work)
if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
(sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
else
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
(sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
- queue_delayed_work(sc->hw->workqueue, &sc->ath_led_blink_work,
- (sc->sc_flags & SC_OP_LED_ON) ?
- msecs_to_jiffies(sc->led_off_duration) :
- msecs_to_jiffies(sc->led_on_duration));
+ ieee80211_queue_delayed_work(sc->hw,
+ &sc->ath_led_blink_work,
+ (sc->sc_flags & SC_OP_LED_ON) ?
+ msecs_to_jiffies(sc->led_off_duration) :
+ msecs_to_jiffies(sc->led_on_duration));
sc->led_on_duration = sc->led_on_cnt ?
max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) :
@@ -1002,7 +1004,7 @@ static void ath_led_brightness(struct led_classdev *led_cdev,
case LED_OFF:
if (led->led_type == ATH_LED_ASSOC ||
led->led_type == ATH_LED_RADIO) {
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
(led->led_type == ATH_LED_RADIO));
sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
if (led->led_type == ATH_LED_RADIO)
@@ -1014,10 +1016,10 @@ static void ath_led_brightness(struct led_classdev *led_cdev,
case LED_FULL:
if (led->led_type == ATH_LED_ASSOC) {
sc->sc_flags |= SC_OP_LED_ASSOCIATED;
- queue_delayed_work(sc->hw->workqueue,
- &sc->ath_led_blink_work, 0);
+ ieee80211_queue_delayed_work(sc->hw,
+ &sc->ath_led_blink_work, 0);
} else if (led->led_type == ATH_LED_RADIO) {
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
sc->sc_flags |= SC_OP_LED_ON;
} else {
sc->led_on_cnt++;
@@ -1057,13 +1059,12 @@ static void ath_unregister_led(struct ath_led *led)
static void ath_deinit_leds(struct ath_softc *sc)
{
- cancel_delayed_work_sync(&sc->ath_led_blink_work);
ath_unregister_led(&sc->assoc_led);
sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
ath_unregister_led(&sc->tx_led);
ath_unregister_led(&sc->rx_led);
ath_unregister_led(&sc->radio_led);
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
}
static void ath_init_leds(struct ath_softc *sc)
@@ -1071,11 +1072,16 @@ static void ath_init_leds(struct ath_softc *sc)
char *trigger;
int ret;
+ if (AR_SREV_9287(sc->sc_ah))
+ sc->sc_ah->led_pin = ATH_LED_PIN_9287;
+ else
+ sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
+
/* Configure gpio 1 for output */
- ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
+ ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
/* LED off, active low */
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
@@ -1114,6 +1120,7 @@ static void ath_init_leds(struct ath_softc *sc)
return;
fail:
+ cancel_delayed_work_sync(&sc->ath_led_blink_work);
ath_deinit_leds(sc);
}
@@ -1153,9 +1160,9 @@ void ath_radio_enable(struct ath_softc *sc)
ath9k_hw_set_interrupts(ah, sc->imask);
/* Enable LED */
- ath9k_hw_cfg_output(ah, ATH_LED_PIN,
+ ath9k_hw_cfg_output(ah, ah->led_pin,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
- ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0);
+ ath9k_hw_set_gpio(ah, ah->led_pin, 0);
ieee80211_wake_queues(sc->hw);
ath9k_ps_restore(sc);
@@ -1171,8 +1178,8 @@ void ath_radio_disable(struct ath_softc *sc)
ieee80211_stop_queues(sc->hw);
/* Disable LED */
- ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1);
- ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN);
+ ath9k_hw_set_gpio(ah, ah->led_pin, 1);
+ ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
/* Disable interrupts */
ath9k_hw_set_interrupts(ah, 0);
@@ -1253,8 +1260,6 @@ void ath_detach(struct ath_softc *sc)
DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n");
ath_deinit_leds(sc);
- cancel_work_sync(&sc->chan_work);
- cancel_delayed_work_sync(&sc->wiphy_work);
for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
@@ -1279,9 +1284,13 @@ void ath_detach(struct ath_softc *sc)
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+ if ((sc->btcoex_info.no_stomp_timer) &&
+ sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath_gen_timer_free(sc->sc_ah, sc->btcoex_info.no_stomp_timer);
+
ath9k_hw_detach(sc->sc_ah);
+ sc->sc_ah = NULL;
ath9k_exit_debug(sc);
- ath9k_ps_restore(sc);
}
static int ath9k_reg_notifier(struct wiphy *wiphy,
@@ -1290,16 +1299,21 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
- struct ath_regulatory *reg = &sc->sc_ah->regulatory;
+ struct ath_regulatory *reg = &sc->common.regulatory;
return ath_reg_notifier_apply(wiphy, request, reg);
}
-static int ath_init(u16 devid, struct ath_softc *sc)
+/*
+ * Initialize and fill ath_softc, ath_sofct is the
+ * "Software Carrier" struct. Historically it has existed
+ * to allow the separation between hardware specific
+ * variables (now in ath_hw) and driver specific variables.
+ */
+static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
{
struct ath_hw *ah = NULL;
- int status;
- int error = 0, i;
+ int r = 0, i;
int csz = 0;
/* XXX: hardware will not be ready until ath_open() being called */
@@ -1311,6 +1325,8 @@ static int ath_init(u16 devid, struct ath_softc *sc)
spin_lock_init(&sc->wiphy_lock);
spin_lock_init(&sc->sc_resetlock);
spin_lock_init(&sc->sc_serial_rw);
+ spin_lock_init(&sc->ani_lock);
+ spin_lock_init(&sc->sc_pm_lock);
mutex_init(&sc->mutex);
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
@@ -1322,16 +1338,26 @@ static int ath_init(u16 devid, struct ath_softc *sc)
*/
ath_read_cachesize(sc, &csz);
/* XXX assert csz is non-zero */
- sc->cachelsz = csz << 2; /* convert to bytes */
+ sc->common.cachelsz = csz << 2; /* convert to bytes */
+
+ ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
+ if (!ah) {
+ r = -ENOMEM;
+ goto bad_no_ah;
+ }
+
+ ah->ah_sc = sc;
+ ah->hw_version.devid = devid;
+ ah->hw_version.subsysid = subsysid;
+ sc->sc_ah = ah;
- ah = ath9k_hw_attach(devid, sc, &status);
- if (ah == NULL) {
+ r = ath9k_hw_init(ah);
+ if (r) {
DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to attach hardware; HAL status %d\n", status);
- error = -ENXIO;
+ "Unable to initialize hardware; "
+ "initialization status: %d\n", r);
goto bad;
}
- sc->sc_ah = ah;
/* Get the hardware key cache size. */
sc->keymax = ah->caps.keycache_size;
@@ -1349,9 +1375,6 @@ static int ath_init(u16 devid, struct ath_softc *sc)
for (i = 0; i < sc->keymax; i++)
ath9k_hw_keyreset(ah, (u16) i);
- if (error)
- goto bad;
-
/* default to MONITOR mode */
sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR;
@@ -1371,14 +1394,14 @@ static int ath_init(u16 devid, struct ath_softc *sc)
if (sc->beacon.beaconq == -1) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to setup a beacon xmit queue\n");
- error = -EIO;
+ r = -EIO;
goto bad2;
}
sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
if (sc->beacon.cabq == NULL) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to setup CAB xmit queue\n");
- error = -EIO;
+ r = -EIO;
goto bad2;
}
@@ -1393,26 +1416,26 @@ static int ath_init(u16 devid, struct ath_softc *sc)
if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to setup xmit queue for BK traffic\n");
- error = -EIO;
+ r = -EIO;
goto bad2;
}
if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to setup xmit queue for BE traffic\n");
- error = -EIO;
+ r = -EIO;
goto bad2;
}
if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to setup xmit queue for VI traffic\n");
- error = -EIO;
+ r = -EIO;
goto bad2;
}
if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to setup xmit queue for VO traffic\n");
- error = -EIO;
+ r = -EIO;
goto bad2;
}
@@ -1496,8 +1519,11 @@ static int ath_init(u16 devid, struct ath_softc *sc)
ARRAY_SIZE(ath9k_5ghz_chantable);
}
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)
- ath9k_hw_btcoex_enable(sc->sc_ah);
+ if (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) {
+ r = ath9k_hw_btcoex_init(ah);
+ if (r)
+ goto bad2;
+ }
return 0;
bad2:
@@ -1506,11 +1532,12 @@ bad2:
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
bad:
- if (ah)
- ath9k_hw_detach(ah);
+ ath9k_hw_detach(ah);
+ sc->sc_ah = NULL;
+bad_no_ah:
ath9k_exit_debug(sc);
- return error;
+ return r;
}
void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
@@ -1536,7 +1563,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->max_rates = 4;
hw->channel_change_time = 5000;
hw->max_listen_interval = 10;
- hw->max_rate_tries = ATH_11N_TXMAXTRY;
+ /* Hardware supports 10 but we use 4 */
+ hw->max_rate_tries = 4;
hw->sta_data_size = sizeof(struct ath_node);
hw->vif_data_size = sizeof(struct ath_vif);
@@ -1549,7 +1577,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
&sc->sbands[IEEE80211_BAND_5GHZ];
}
-int ath_attach(u16 devid, struct ath_softc *sc)
+/* Device driver core initialization */
+int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid)
{
struct ieee80211_hw *hw = sc->hw;
int error = 0, i;
@@ -1557,7 +1586,7 @@ int ath_attach(u16 devid, struct ath_softc *sc)
DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n");
- error = ath_init(devid, sc);
+ error = ath_init_softc(devid, sc, subsysid);
if (error != 0)
return error;
@@ -1567,12 +1596,12 @@ int ath_attach(u16 devid, struct ath_softc *sc)
ath_set_hw_capab(sc, hw);
- error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy,
+ error = ath_regd_init(&sc->common.regulatory, sc->hw->wiphy,
ath9k_reg_notifier);
if (error)
return error;
- reg = &sc->sc_ah->regulatory;
+ reg = &sc->common.regulatory;
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
@@ -1615,6 +1644,7 @@ error_attach:
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
ath9k_hw_detach(sc->sc_ah);
+ sc->sc_ah = NULL;
ath9k_exit_debug(sc);
return error;
@@ -1850,7 +1880,7 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
if (chan->band == IEEE80211_BAND_2GHZ) {
ichan->chanmode = CHANNEL_G;
- ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM;
+ ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G;
} else {
ichan->chanmode = CHANNEL_A;
ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
@@ -1973,6 +2003,19 @@ static int ath9k_start(struct ieee80211_hw *hw)
ieee80211_wake_queues(hw);
+ ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
+
+ if ((sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) &&
+ !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) {
+ ath_btcoex_set_weight(&sc->btcoex_info, AR_BT_COEX_WGHT,
+ AR_STOMP_LOW_WLAN_WGHT);
+ ath9k_hw_btcoex_enable(sc->sc_ah);
+
+ ath_pcie_aspm_disable(sc);
+ if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath_btcoex_timer_resume(sc, &sc->btcoex_info);
+ }
+
mutex_unlock:
mutex_unlock(&sc->mutex);
@@ -1994,7 +2037,7 @@ static int ath9k_tx(struct ieee80211_hw *hw,
goto exit;
}
- if (sc->hw->conf.flags & IEEE80211_CONF_PS) {
+ if (sc->ps_enabled) {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
/*
* mac80211 does not set PM field for normal data frames, so we
@@ -2083,22 +2126,35 @@ static void ath9k_stop(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ mutex_lock(&sc->mutex);
+
aphy->state = ATH_WIPHY_INACTIVE;
+ cancel_delayed_work_sync(&sc->ath_led_blink_work);
+ cancel_delayed_work_sync(&sc->tx_complete_work);
+
+ if (!sc->num_sec_wiphy) {
+ cancel_delayed_work_sync(&sc->wiphy_work);
+ cancel_work_sync(&sc->chan_work);
+ }
+
if (sc->sc_flags & SC_OP_INVALID) {
DPRINTF(sc, ATH_DBG_ANY, "Device not present\n");
+ mutex_unlock(&sc->mutex);
return;
}
- mutex_lock(&sc->mutex);
-
- ieee80211_stop_queues(hw);
-
if (ath9k_wiphy_started(sc)) {
mutex_unlock(&sc->mutex);
return; /* another wiphy still in use */
}
+ if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) {
+ ath9k_hw_btcoex_disable(sc->sc_ah);
+ if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath_btcoex_timer_pause(sc, &sc->btcoex_info);
+ }
+
/* make sure h/w will not generate any interrupt
* before setting the invalid flag. */
ath9k_hw_set_interrupts(sc->sc_ah, 0);
@@ -2115,6 +2171,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
/* disable HAL and put h/w to sleep */
ath9k_hw_disable(sc->sc_ah);
ath9k_hw_configpcipowersave(sc->sc_ah, 1);
+ ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
sc->sc_flags |= SC_OP_INVALID;
@@ -2189,14 +2246,15 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
if ((conf->type == NL80211_IFTYPE_STATION) ||
(conf->type == NL80211_IFTYPE_ADHOC) ||
(conf->type == NL80211_IFTYPE_MESH_POINT)) {
- if (ath9k_hw_phycounters(sc->sc_ah))
- sc->imask |= ATH9K_INT_MIB;
+ sc->imask |= ATH9K_INT_MIB;
sc->imask |= ATH9K_INT_TSFOOR;
}
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
- if (conf->type == NL80211_IFTYPE_AP)
+ if (conf->type == NL80211_IFTYPE_AP ||
+ conf->type == NL80211_IFTYPE_ADHOC ||
+ conf->type == NL80211_IFTYPE_MONITOR)
ath_start_ani(sc);
out:
@@ -2249,9 +2307,28 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
struct ath_softc *sc = aphy->sc;
struct ieee80211_conf *conf = &hw->conf;
struct ath_hw *ah = sc->sc_ah;
+ bool all_wiphys_idle = false, disable_radio = false;
mutex_lock(&sc->mutex);
+ /* Leave this as the first check */
+ if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+
+ spin_lock_bh(&sc->wiphy_lock);
+ all_wiphys_idle = ath9k_all_wiphys_idle(sc);
+ spin_unlock_bh(&sc->wiphy_lock);
+
+ if (conf->flags & IEEE80211_CONF_IDLE){
+ if (all_wiphys_idle)
+ disable_radio = true;
+ }
+ else if (all_wiphys_idle) {
+ ath_radio_enable(sc);
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "not-idle: enabling radio\n");
+ }
+ }
+
if (changed & IEEE80211_CONF_CHANGE_PS) {
if (conf->flags & IEEE80211_CONF_PS) {
if (!(ah->caps.hw_caps &
@@ -2263,8 +2340,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
ath9k_hw_setrxabort(sc->sc_ah, 1);
}
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
+ sc->ps_enabled = true;
} else {
+ sc->ps_enabled = false;
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) {
@@ -2319,6 +2397,11 @@ skip_chan_change:
if (changed & IEEE80211_CONF_CHANGE_POWER)
sc->config.txpowlimit = 2 * conf->power_level;
+ if (disable_radio) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "idle: disabling radio\n");
+ ath_radio_disable(sc);
+ }
+
mutex_unlock(&sc->mutex);
return 0;
@@ -2328,6 +2411,7 @@ skip_chan_change:
(FIF_PROMISC_IN_BSS | \
FIF_ALLMULTI | \
FIF_CONTROL | \
+ FIF_PSPOLL | \
FIF_OTHER_BSS | \
FIF_BCN_PRBRESP_PROMISC | \
FIF_FCSFAIL)
@@ -2336,8 +2420,7 @@ skip_chan_change:
static void ath9k_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
- int mc_count,
- struct dev_mc_list *mclist)
+ u64 multicast)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
@@ -2352,7 +2435,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
ath9k_ps_restore(sc);
- DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter);
+ DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", rfilt);
}
static void ath9k_sta_notify(struct ieee80211_hw *hw,
@@ -2638,19 +2721,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_RX_STOP:
break;
case IEEE80211_AMPDU_TX_START:
- ret = ath_tx_aggr_start(sc, sta, tid, ssn);
- if (ret < 0)
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to start TX aggregation\n");
- else
- ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+ ath_tx_aggr_start(sc, sta, tid, ssn);
+ ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP:
- ret = ath_tx_aggr_stop(sc, sta, tid);
- if (ret < 0)
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to stop TX aggregation\n");
-
+ ath_tx_aggr_stop(sc, sta, tid);
ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
@@ -2668,6 +2743,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ mutex_lock(&sc->mutex);
if (ath9k_wiphy_scanning(sc)) {
printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the "
"same time\n");
@@ -2675,14 +2751,16 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
* Do not allow the concurrent scanning state for now. This
* could be improved with scanning control moved into ath9k.
*/
+ mutex_unlock(&sc->mutex);
return;
}
aphy->state = ATH_WIPHY_SCAN;
ath9k_wiphy_pause_all_forced(sc, aphy);
- mutex_lock(&sc->mutex);
+ spin_lock_bh(&sc->ani_lock);
sc->sc_flags |= SC_OP_SCANNING;
+ spin_unlock_bh(&sc->ani_lock);
mutex_unlock(&sc->mutex);
}
@@ -2692,9 +2770,12 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
struct ath_softc *sc = aphy->sc;
mutex_lock(&sc->mutex);
+ spin_lock_bh(&sc->ani_lock);
aphy->state = ATH_WIPHY_ACTIVE;
sc->sc_flags &= ~SC_OP_SCANNING;
sc->sc_flags |= SC_OP_FULL_RESET;
+ spin_unlock_bh(&sc->ani_lock);
+ ath_beacon_config(sc, NULL);
mutex_unlock(&sc->mutex);
}
@@ -2728,7 +2809,8 @@ static struct {
{ AR_SREV_VERSION_9100, "9100" },
{ AR_SREV_VERSION_9160, "9160" },
{ AR_SREV_VERSION_9280, "9280" },
- { AR_SREV_VERSION_9285, "9285" }
+ { AR_SREV_VERSION_9285, "9285" },
+ { AR_SREV_VERSION_9287, "9287" }
};
static struct {
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 170c5b32e49b..903dd8ad9d43 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -25,6 +25,8 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = {
{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
{ PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
+ { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */
+ { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
{ 0 }
};
@@ -33,8 +35,7 @@ static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz)
{
u8 u8tmp;
- pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE,
- (u8 *)&u8tmp);
+ pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp);
*csz = (int)u8tmp;
/*
@@ -87,6 +88,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct ath_softc *sc;
struct ieee80211_hw *hw;
u8 csz;
+ u16 subsysid;
u32 val;
int ret = 0;
struct ath_hw *ah;
@@ -158,8 +160,9 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) +
sizeof(struct ath_softc), &ath9k_ops);
- if (hw == NULL) {
- printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n");
+ if (!hw) {
+ dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
+ ret = -ENOMEM;
goto bad2;
}
@@ -176,17 +179,18 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sc->mem = mem;
sc->bus_ops = &ath_pci_bus_ops;
- if (ath_attach(id->device, sc) != 0) {
- ret = -ENODEV;
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid);
+ ret = ath_init_device(id->device, sc, subsysid);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize device\n");
goto bad3;
}
/* setup interrupt service routine */
- if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) {
- printk(KERN_ERR "%s: request_irq failed\n",
- wiphy_name(hw->wiphy));
- ret = -EIO;
+ ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq failed\n");
goto bad4;
}
@@ -234,7 +238,7 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
pci_save_state(pdev);
pci_disable_device(pdev);
@@ -251,10 +255,12 @@ static int ath_pci_resume(struct pci_dev *pdev)
u32 val;
int err;
+ pci_restore_state(pdev);
+
err = pci_enable_device(pdev);
if (err)
return err;
- pci_restore_state(pdev);
+
/*
* Suspend/Resume resets the PCI configuration space, so we have to
* re-disable the RETRY_TIMEOUT register (0x41) to keep
@@ -265,9 +271,9 @@ static int ath_pci_resume(struct pci_dev *pdev)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
/* Enable LED */
- ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
+ ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c
index aaa941561c36..63bf9a307c6a 100644
--- a/drivers/net/wireless/ath/ath9k/phy.c
+++ b/drivers/net/wireless/ath/ath9k/phy.c
@@ -264,44 +264,23 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan,
}
void
-ath9k_hw_rfdetach(struct ath_hw *ah)
+ath9k_hw_rf_free(struct ath_hw *ah)
{
- if (ah->analogBank0Data != NULL) {
- kfree(ah->analogBank0Data);
- ah->analogBank0Data = NULL;
- }
- if (ah->analogBank1Data != NULL) {
- kfree(ah->analogBank1Data);
- ah->analogBank1Data = NULL;
- }
- if (ah->analogBank2Data != NULL) {
- kfree(ah->analogBank2Data);
- ah->analogBank2Data = NULL;
- }
- if (ah->analogBank3Data != NULL) {
- kfree(ah->analogBank3Data);
- ah->analogBank3Data = NULL;
- }
- if (ah->analogBank6Data != NULL) {
- kfree(ah->analogBank6Data);
- ah->analogBank6Data = NULL;
- }
- if (ah->analogBank6TPCData != NULL) {
- kfree(ah->analogBank6TPCData);
- ah->analogBank6TPCData = NULL;
- }
- if (ah->analogBank7Data != NULL) {
- kfree(ah->analogBank7Data);
- ah->analogBank7Data = NULL;
- }
- if (ah->addac5416_21 != NULL) {
- kfree(ah->addac5416_21);
- ah->addac5416_21 = NULL;
- }
- if (ah->bank6Temp != NULL) {
- kfree(ah->bank6Temp);
- ah->bank6Temp = NULL;
- }
+#define ATH_FREE_BANK(bank) do { \
+ kfree(bank); \
+ bank = NULL; \
+ } while (0);
+
+ ATH_FREE_BANK(ah->analogBank0Data);
+ ATH_FREE_BANK(ah->analogBank1Data);
+ ATH_FREE_BANK(ah->analogBank2Data);
+ ATH_FREE_BANK(ah->analogBank3Data);
+ ATH_FREE_BANK(ah->analogBank6Data);
+ ATH_FREE_BANK(ah->analogBank6TPCData);
+ ATH_FREE_BANK(ah->analogBank7Data);
+ ATH_FREE_BANK(ah->addac5416_21);
+ ATH_FREE_BANK(ah->bank6Temp);
+#undef ATH_FREE_BANK
}
bool ath9k_hw_init_rf(struct ath_hw *ah, int *status)
@@ -374,18 +353,16 @@ ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan)
u32 bank6SelMask;
u32 *bank6Temp = ah->bank6Temp;
- switch (ah->diversity_control) {
+ switch (ah->config.diversity_control) {
case ATH9K_ANT_FIXED_A:
bank6SelMask =
- (ah->
- antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_0 :
- REDUCE_CHAIN_1;
+ (ah->config.antenna_switch_swap & ANTSWAP_AB) ?
+ REDUCE_CHAIN_0 : REDUCE_CHAIN_1;
break;
case ATH9K_ANT_FIXED_B:
bank6SelMask =
- (ah->
- antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_1 :
- REDUCE_CHAIN_0;
+ (ah->config.antenna_switch_swap & ANTSWAP_AB) ?
+ REDUCE_CHAIN_1 : REDUCE_CHAIN_0;
break;
case ATH9K_ANT_VARIABLE:
return;
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index c70f530642f6..dfda6f444648 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -185,6 +185,9 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
#define AR_PHY_PLL_CTL_44_2133 0xeb
#define AR_PHY_PLL_CTL_40_2133 0xea
+#define AR_PHY_SPECTRAL_SCAN 0x9912
+#define AR_PHY_SPECTRAL_SCAN_ENABLE 0x1
+
#define AR_PHY_RX_DELAY 0x9914
#define AR_PHY_SEARCH_START_DELAY 0x9918
#define AR_PHY_RX_DELAY_DELAY 0x00003FFF
@@ -309,7 +312,25 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12))
#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000
#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
-#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac
+
+#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac
+#define AR_PHY_9285_ANT_DIV_CTL_ALL 0x7f000000
+#define AR_PHY_9285_ANT_DIV_CTL 0x01000000
+#define AR_PHY_9285_ANT_DIV_CTL_S 24
+#define AR_PHY_9285_ANT_DIV_ALT_LNACONF 0x06000000
+#define AR_PHY_9285_ANT_DIV_ALT_LNACONF_S 25
+#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF 0x18000000
+#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S 27
+#define AR_PHY_9285_ANT_DIV_ALT_GAINTB 0x20000000
+#define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S 29
+#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB 0x40000000
+#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S 30
+#define AR_PHY_9285_ANT_DIV_LNA1 2
+#define AR_PHY_9285_ANT_DIV_LNA2 1
+#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2 3
+#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0
+#define AR_PHY_9285_ANT_DIV_GAINTB_0 0
+#define AR_PHY_9285_ANT_DIV_GAINTB_1 1
#define AR_PHY_EXT_CCA0 0x99b8
#define AR_PHY_EXT_CCA0_THRESH62 0x000000FF
@@ -375,6 +396,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
#define AR_PHY_CHAN_INFO_GAIN 0x9CFC
#define AR_PHY_MODE 0xA200
+#define AR_PHY_MODE_ASYNCFIFO 0x80
#define AR_PHY_MODE_AR2133 0x08
#define AR_PHY_MODE_AR5111 0x00
#define AR_PHY_MODE_AR5112 0x08
@@ -397,6 +419,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0
#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6
#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000
+#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S 13
#define AR_PHY_GAIN_2GHZ 0xA20C
#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00FC0000
@@ -467,11 +490,18 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
#define AR_PHY_TX_PWRCTRL9 0xa27C
#define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00
#define AR_PHY_TX_DESIRED_SCALE_CCK_S 10
+#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000
+#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31
#define AR_PHY_TX_GAIN_TBL1 0xa300
#define AR_PHY_TX_GAIN 0x0007F000
#define AR_PHY_TX_GAIN_S 12
+#define AR_PHY_CH0_TX_PWRCTRL11 0xa398
+#define AR_PHY_CH1_TX_PWRCTRL11 0xb398
+#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP 0x0000FC00
+#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10
+
#define AR_PHY_VIT_MASK2_M_46_61 0xa3a0
#define AR_PHY_MASK2_M_31_45 0xa3a4
#define AR_PHY_MASK2_M_16_30 0xa3a8
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index ba06e78b2f50..16a271787b85 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -22,133 +22,132 @@ static const struct ath_rate_table ar5416_11na_ratetable = {
{
{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
- 0, 2, 1, 0, 0, 0, 0, 0 },
+ 0, 0, 0, 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 0, 3, 1, 1, 1, 1, 1, 0 },
+ 0, 1, 1, 1, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
- 2, 4, 2, 2, 2, 2, 2, 0 },
+ 2, 2, 2, 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
- 2, 6, 2, 3, 3, 3, 3, 0 },
+ 2, 3, 3, 3, 3, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
- 4, 10, 3, 4, 4, 4, 4, 0 },
+ 4, 4, 4, 4, 4, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
- 4, 14, 3, 5, 5, 5, 5, 0 },
+ 4, 5, 5, 5, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 4, 20, 3, 6, 6, 6, 6, 0 },
+ 4, 6, 6, 6, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
- 4, 23, 3, 7, 7, 7, 7, 0 },
- { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
+ 4, 7, 7, 7, 7, 0 },
+ { VALID_2040, VALID_2040, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
- 0, 2, 3, 8, 24, 8, 24, 3216 },
+ 0, 8, 24, 8, 24, 3216 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
- 2, 4, 3, 9, 25, 9, 25, 6434 },
+ 2, 9, 25, 9, 25, 6434 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
- 2, 6, 3, 10, 26, 10, 26, 9650 },
+ 2, 10, 26, 10, 26, 9650 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
- 4, 10, 3, 11, 27, 11, 27, 12868 },
+ 4, 11, 27, 11, 27, 12868 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
- 4, 14, 3, 12, 28, 12, 28, 19304 },
+ 4, 12, 28, 12, 28, 19304 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
- 4, 20, 3, 13, 29, 13, 29, 25740 },
+ 4, 13, 29, 13, 29, 25740 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
- 4, 23, 3, 14, 30, 14, 30, 28956 },
+ 4, 14, 30, 14, 30, 28956 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
- 4, 25, 3, 15, 31, 15, 32, 32180 },
+ 4, 15, 31, 15, 32, 32180 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00,
- 8, 0, 2, 3, 16, 33, 16, 33, 6430 },
+ 8, 3, 16, 33, 16, 33, 6430 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
- 2, 4, 3, 17, 34, 17, 34, 12860 },
+ 2, 17, 34, 17, 34, 12860 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
- 2, 6, 3, 18, 35, 18, 35, 19300 },
+ 2, 18, 35, 18, 35, 19300 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
- 4, 10, 3, 19, 36, 19, 36, 25736 },
+ 4, 19, 36, 19, 36, 25736 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
- 4, 14, 3, 20, 37, 20, 37, 38600 },
+ 4, 20, 37, 20, 37, 38600 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
- 4, 20, 3, 21, 38, 21, 38, 51472 },
+ 4, 21, 38, 21, 38, 51472 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
- 4, 23, 3, 22, 39, 22, 39, 57890 },
+ 4, 22, 39, 22, 39, 57890 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
- 4, 25, 3, 23, 40, 23, 41, 64320 },
+ 4, 23, 40, 23, 41, 64320 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
- 0, 2, 3, 8, 24, 24, 24, 6684 },
+ 0, 8, 24, 24, 24, 6684 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
- 2, 4, 3, 9, 25, 25, 25, 13368 },
+ 2, 9, 25, 25, 25, 13368 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
- 2, 6, 3, 10, 26, 26, 26, 20052 },
+ 2, 10, 26, 26, 26, 20052 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
- 4, 10, 3, 11, 27, 27, 27, 26738 },
+ 4, 11, 27, 27, 27, 26738 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
- 4, 14, 3, 12, 28, 28, 28, 40104 },
+ 4, 12, 28, 28, 28, 40104 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
- 4, 20, 3, 13, 29, 29, 29, 53476 },
+ 4, 13, 29, 29, 29, 53476 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
- 4, 23, 3, 14, 30, 30, 30, 60156 },
+ 4, 14, 30, 30, 30, 60156 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
- 4, 25, 3, 15, 31, 32, 32, 66840 },
+ 4, 15, 31, 32, 32, 66840 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
- 4, 25, 3, 15, 31, 32, 32, 74200 },
+ 4, 15, 31, 32, 32, 74200 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
- 0, 2, 3, 16, 33, 33, 33, 13360 },
+ 0, 16, 33, 33, 33, 13360 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
- 2, 4, 3, 17, 34, 34, 34, 26720 },
+ 2, 17, 34, 34, 34, 26720 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
- 2, 6, 3, 18, 35, 35, 35, 40080 },
+ 2, 18, 35, 35, 35, 40080 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
- 4, 10, 3, 19, 36, 36, 36, 53440 },
+ 4, 19, 36, 36, 36, 53440 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
- 4, 14, 3, 20, 37, 37, 37, 80160 },
+ 4, 20, 37, 37, 37, 80160 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
- 4, 20, 3, 21, 38, 38, 38, 106880 },
+ 4, 21, 38, 38, 38, 106880 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
- 4, 23, 3, 22, 39, 39, 39, 120240 },
+ 4, 22, 39, 39, 39, 120240 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
- 4, 25, 3, 23, 40, 41, 41, 133600 },
+ 4, 23, 40, 41, 41, 133600 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
- 4, 25, 3, 23, 40, 41, 41, 148400 },
+ 4, 23, 40, 41, 41, 148400 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
};
@@ -160,145 +159,144 @@ static const struct ath_rate_table ar5416_11ng_ratetable = {
{
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
- 0, 0, 1, 0, 0, 0, 0, 0 },
+ 0, 0, 0, 0, 0, 0 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
- 1, 1, 1, 1, 1, 1, 1, 0 },
+ 1, 1, 1, 1, 1, 0 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
- 2, 2, 2, 2, 2, 2, 2, 0 },
+ 2, 2, 2, 2, 2, 0 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
- 3, 3, 2, 3, 3, 3, 3, 0 },
+ 3, 3, 3, 3, 3, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
- 4, 2, 1, 4, 4, 4, 4, 0 },
+ 4, 4, 4, 4, 4, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 4, 3, 1, 5, 5, 5, 5, 0 },
+ 4, 5, 5, 5, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10100, 0x0a, 0x00, 24,
- 6, 4, 1, 6, 6, 6, 6, 0 },
+ 6, 6, 6, 6, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
14100, 0x0e, 0x00, 36,
- 6, 6, 2, 7, 7, 7, 7, 0 },
+ 6, 7, 7, 7, 7, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17700, 0x09, 0x00, 48,
- 8, 10, 3, 8, 8, 8, 8, 0 },
+ 8, 8, 8, 8, 8, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23700, 0x0d, 0x00, 72,
- 8, 14, 3, 9, 9, 9, 9, 0 },
+ 8, 9, 9, 9, 9, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 8, 20, 3, 10, 10, 10, 10, 0 },
+ 8, 10, 10, 10, 10, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
30900, 0x0c, 0x00, 108,
- 8, 23, 3, 11, 11, 11, 11, 0 },
+ 8, 11, 11, 11, 11, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
- 4, 2, 3, 12, 28, 12, 28, 3216 },
+ 4, 12, 28, 12, 28, 3216 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
- 6, 4, 3, 13, 29, 13, 29, 6434 },
+ 6, 13, 29, 13, 29, 6434 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
- 6, 6, 3, 14, 30, 14, 30, 9650 },
+ 6, 14, 30, 14, 30, 9650 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
- 8, 10, 3, 15, 31, 15, 31, 12868 },
+ 8, 15, 31, 15, 31, 12868 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
- 8, 14, 3, 16, 32, 16, 32, 19304 },
+ 8, 16, 32, 16, 32, 19304 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
- 8, 20, 3, 17, 33, 17, 33, 25740 },
+ 8, 17, 33, 17, 33, 25740 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
- 8, 23, 3, 18, 34, 18, 34, 28956 },
+ 8, 18, 34, 18, 34, 28956 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
- 8, 25, 3, 19, 35, 19, 36, 32180 },
+ 8, 19, 35, 19, 36, 32180 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00, 8,
- 4, 2, 3, 20, 37, 20, 37, 6430 },
+ 4, 20, 37, 20, 37, 6430 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
- 6, 4, 3, 21, 38, 21, 38, 12860 },
+ 6, 21, 38, 21, 38, 12860 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
- 6, 6, 3, 22, 39, 22, 39, 19300 },
+ 6, 22, 39, 22, 39, 19300 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
- 8, 10, 3, 23, 40, 23, 40, 25736 },
+ 8, 23, 40, 23, 40, 25736 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
- 8, 14, 3, 24, 41, 24, 41, 38600 },
+ 8, 24, 41, 24, 41, 38600 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
- 8, 20, 3, 25, 42, 25, 42, 51472 },
+ 8, 25, 42, 25, 42, 51472 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
- 8, 23, 3, 26, 43, 26, 44, 57890 },
+ 8, 26, 43, 26, 44, 57890 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
- 8, 25, 3, 27, 44, 27, 45, 64320 },
+ 8, 27, 44, 27, 45, 64320 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
- 8, 2, 3, 12, 28, 28, 28, 6684 },
+ 8, 12, 28, 28, 28, 6684 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
- 8, 4, 3, 13, 29, 29, 29, 13368 },
+ 8, 13, 29, 29, 29, 13368 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
- 8, 6, 3, 14, 30, 30, 30, 20052 },
+ 8, 14, 30, 30, 30, 20052 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
- 8, 10, 3, 15, 31, 31, 31, 26738 },
+ 8, 15, 31, 31, 31, 26738 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
- 8, 14, 3, 16, 32, 32, 32, 40104 },
+ 8, 16, 32, 32, 32, 40104 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
- 8, 20, 3, 17, 33, 33, 33, 53476 },
+ 8, 17, 33, 33, 33, 53476 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
- 8, 23, 3, 18, 34, 34, 34, 60156 },
+ 8, 18, 34, 34, 34, 60156 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
- 8, 23, 3, 19, 35, 36, 36, 66840 },
+ 8, 19, 35, 36, 36, 66840 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
- 8, 25, 3, 19, 35, 36, 36, 74200 },
+ 8, 19, 35, 36, 36, 74200 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
- 8, 2, 3, 20, 37, 37, 37, 13360 },
+ 8, 20, 37, 37, 37, 13360 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
- 8, 4, 3, 21, 38, 38, 38, 26720 },
+ 8, 21, 38, 38, 38, 26720 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
- 8, 6, 3, 22, 39, 39, 39, 40080 },
+ 8, 22, 39, 39, 39, 40080 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
- 8, 10, 3, 23, 40, 40, 40, 53440 },
+ 8, 23, 40, 40, 40, 53440 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
- 8, 14, 3, 24, 41, 41, 41, 80160 },
+ 8, 24, 41, 41, 41, 80160 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
- 8, 20, 3, 25, 42, 42, 42, 106880 },
+ 8, 25, 42, 42, 42, 106880 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
- 8, 23, 3, 26, 43, 43, 43, 120240 },
+ 8, 26, 43, 43, 43, 120240 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
- 8, 23, 3, 27, 44, 45, 45, 133600 },
+ 8, 27, 44, 45, 45, 133600 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
- 8, 25, 3, 27, 44, 45, 45, 148400 },
+ 8, 27, 44, 45, 45, 148400 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
};
@@ -307,31 +305,30 @@ static const struct ath_rate_table ar5416_11a_ratetable = {
{
{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, (0x80|12),
- 0, 2, 1, 0, 0 },
+ 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 0, 3, 1, 1, 0 },
+ 0, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, (0x80|24),
- 2, 4, 2, 2, 0 },
+ 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
- 2, 6, 2, 3, 0 },
+ 2, 3, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, (0x80|48),
- 4, 10, 3, 4, 0 },
+ 4, 4, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
- 4, 14, 3, 5, 0 },
+ 4, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 4, 19, 3, 6, 0 },
+ 4, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
- 4, 23, 3, 7, 0 },
+ 4, 7, 0 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
0, /* Phy rates allowed initially */
};
@@ -340,64 +337,42 @@ static const struct ath_rate_table ar5416_11g_ratetable = {
{
{ VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
- 0, 0, 1, 0, 0 },
+ 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
- 1, 1, 1, 1, 0 },
+ 1, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
- 2, 2, 2, 2, 0 },
+ 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
- 3, 3, 2, 3, 0 },
+ 3, 3, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
- 4, 2, 1, 4, 0 },
+ 4, 4, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 4, 3, 1, 5, 0 },
+ 4, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
- 6, 4, 1, 6, 0 },
+ 6, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
- 6, 6, 2, 7, 0 },
+ 6, 7, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
- 8, 10, 3, 8, 0 },
+ 8, 8, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
- 8, 14, 3, 9, 0 },
+ 8, 9, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 8, 19, 3, 10, 0 },
+ 8, 10, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
- 8, 23, 3, 11, 0 },
+ 8, 11, 0 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
- 0, /* Phy rates allowed initially */
-};
-
-static const struct ath_rate_table ar5416_11b_ratetable = {
- 4,
- {
- { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
- 900, 0x1b, 0x00, (0x80|2),
- 0, 0, 1, 0, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
- 1800, 0x1a, 0x04, (0x80|4),
- 1, 1, 1, 1, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
- 4300, 0x19, 0x04, (0x80|11),
- 1, 2, 2, 2, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
- 7100, 0x18, 0x04, (0x80|22),
- 1, 4, 100, 3, 0 },
- },
- 100, /* probe interval */
- 100, /* rssi reduce interval */
0, /* Phy rates allowed initially */
};
@@ -454,13 +429,6 @@ static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv,
ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0;
}
-static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv,
- u8 index)
-{
- ASSERT(index <= ath_rc_priv->rate_table_size);
- return ath_rc_priv->valid_rate_index[index];
-}
-
static inline
int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
struct ath_rate_priv *ath_rc_priv,
@@ -495,15 +463,13 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
if (!ignore_cw && WLAN_RC_PHY_HT(phy))
if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG))
return 0;
- if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG))
- return 0;
return 1;
}
static inline int
-ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table,
- struct ath_rate_priv *ath_rc_priv,
- u8 cur_valid_txrate, u8 *next_idx)
+ath_rc_get_lower_rix(const struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
+ u8 cur_valid_txrate, u8 *next_idx)
{
int8_t i;
@@ -629,52 +595,20 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
return hi;
}
-static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- int *is_probing)
+/* Finds the highest rate index we can use */
+static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
+ struct ath_rate_priv *ath_rc_priv,
+ const struct ath_rate_table *rate_table,
+ int *is_probing)
{
- u32 dt, best_thruput, this_thruput, now_msec;
+ u32 best_thruput, this_thruput, now_msec;
u8 rate, next_rate, best_rate, maxindex, minindex;
- int8_t rssi_last, rssi_reduce = 0, index = 0;
-
- *is_probing = 0;
-
- rssi_last = median(ath_rc_priv->rssi_last,
- ath_rc_priv->rssi_last_prev,
- ath_rc_priv->rssi_last_prev2);
-
- /*
- * Age (reduce) last ack rssi based on how old it is.
- * The bizarre numbers are so the delta is 160msec,
- * meaning we divide by 16.
- * 0msec <= dt <= 25msec: don't derate
- * 25msec <= dt <= 185msec: derate linearly from 0 to 10dB
- * 185msec <= dt: derate by 10dB
- */
+ int8_t index = 0;
now_msec = jiffies_to_msecs(jiffies);
- dt = now_msec - ath_rc_priv->rssi_time;
-
- if (dt >= 185)
- rssi_reduce = 10;
- else if (dt >= 25)
- rssi_reduce = (u8)((dt - 25) >> 4);
-
- /* Now reduce rssi_last by rssi_reduce */
- if (rssi_last < rssi_reduce)
- rssi_last = 0;
- else
- rssi_last -= rssi_reduce;
-
- /*
- * Now look up the rate in the rssi table and return it.
- * If no rates match then we return 0 (lowest rate)
- */
-
+ *is_probing = 0;
best_thruput = 0;
maxindex = ath_rc_priv->max_valid_rate-1;
-
minindex = 0;
best_rate = minindex;
@@ -700,7 +634,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
* 10-15 and we would be worse off then staying
* at the current rate.
*/
- per_thres = ath_rc_priv->state[rate].per;
+ per_thres = ath_rc_priv->per[rate];
if (per_thres < 12)
per_thres = 12;
@@ -714,7 +648,6 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
}
rate = best_rate;
- ath_rc_priv->rssi_last_lookup = rssi_last;
/*
* Must check the actual rate (ratekbps) to account for
@@ -741,10 +674,18 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
if (rate > (ath_rc_priv->rate_table_size - 1))
rate = ath_rc_priv->rate_table_size - 1;
- ASSERT((rate_table->info[rate].valid &&
- (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) ||
- (rate_table->info[rate].valid_single_stream &&
- !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)));
+ if (rate_table->info[rate].valid &&
+ (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))
+ return rate;
+
+ if (rate_table->info[rate].valid_single_stream &&
+ !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG));
+ return rate;
+
+ /* This should not happen */
+ WARN_ON(1);
+
+ rate = ath_rc_priv->valid_rate_index[0];
return rate;
}
@@ -796,7 +737,6 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
* just CTS. Note that this is only done for OFDM/HT unicast frames.
*/
if ((sc->sc_flags & SC_OP_PROTECT_ENABLE) &&
- !(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) &&
(rate_table->info[rix].phy == WLAN_RC_PHY_OFDM ||
WLAN_RC_PHY_HT(rate_table->info[rix].phy))) {
rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT;
@@ -806,50 +746,37 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
tx_info->control.rts_cts_rate_idx = cix;
}
-static u8 ath_rc_rate_getidx(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- u8 rix, u16 stepdown,
- u16 min_rate)
-{
- u32 j;
- u8 nextindex = 0;
-
- if (min_rate) {
- for (j = RATE_TABLE_SIZE; j > 0; j--) {
- if (ath_rc_get_nextlowervalid_txrate(rate_table,
- ath_rc_priv, rix, &nextindex))
- rix = nextindex;
- else
- break;
- }
- } else {
- for (j = stepdown; j > 0; j--) {
- if (ath_rc_get_nextlowervalid_txrate(rate_table,
- ath_rc_priv, rix, &nextindex))
- rix = nextindex;
- else
- break;
- }
- }
- return rix;
-}
-
-static void ath_rc_ratefind(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- struct ieee80211_tx_rate_control *txrc)
+static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc)
{
+ struct ath_softc *sc = priv;
+ struct ath_rate_priv *ath_rc_priv = priv_sta;
const struct ath_rate_table *rate_table;
struct sk_buff *skb = txrc->skb;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rates = tx_info->control.rates;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
- u8 try_per_rate = 0, i = 0, rix, nrix;
+ u8 try_per_rate, i = 0, rix, nrix;
int is_probe = 0;
+ if (rate_control_send_low(sta, priv_sta, txrc))
+ return;
+
+ /*
+ * For Multi Rate Retry we use a different number of
+ * retry attempt counts. This ends up looking like this:
+ *
+ * MRR[0] = 2
+ * MRR[1] = 2
+ * MRR[2] = 2
+ * MRR[3] = 4
+ *
+ */
+ try_per_rate = sc->hw->max_rate_tries;
+
rate_table = sc->cur_rate_table;
- rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, &is_probe);
+ rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
nrix = rix;
if (is_probe) {
@@ -858,18 +785,15 @@ static void ath_rc_ratefind(struct ath_softc *sc,
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
1, nrix, 0);
- try_per_rate = (ATH_11N_TXMAXTRY/4);
/* Get the next tried/allowed rate. No RTS for the next series
* after the probe rate
*/
- nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
- rate_table, nrix, 1, 0);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
try_per_rate, nrix, 0);
tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
} else {
- try_per_rate = (ATH_11N_TXMAXTRY/4);
/* Set the choosen rate. No RTS for first series entry. */
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
try_per_rate, nrix, 0);
@@ -877,18 +801,14 @@ static void ath_rc_ratefind(struct ath_softc *sc,
/* Fill in the other rates for multirate retry */
for ( ; i < 4; i++) {
- u8 try_num;
- u8 min_rate;
+ /* Use twice the number of tries for the last MRR segment. */
+ if (i + 1 == 4)
+ try_per_rate = 4;
- try_num = ((i + 1) == 4) ?
- ATH_11N_TXMAXTRY - (try_per_rate * i) : try_per_rate ;
- min_rate = (((i + 1) == 4) && 0);
-
- nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
- rate_table, nrix, 1, min_rate);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
/* All other rates in the series have RTS enabled */
ath_rc_rate_set_series(rate_table, &rates[i], txrc,
- try_num, nrix, 1);
+ try_per_rate, nrix, 1);
}
/*
@@ -925,9 +845,8 @@ static void ath_rc_ratefind(struct ath_softc *sc,
*
* FIXME: Fix duration
*/
- if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) &&
- (ieee80211_has_morefrags(fc) ||
- (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG))) {
+ if (ieee80211_has_morefrags(fc) ||
+ (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
rates[1].count = rates[2].count = rates[3].count = 0;
rates[1].idx = rates[2].idx = rates[3].idx = 0;
rates[0].count = ATH_TXMAXTRY;
@@ -960,13 +879,13 @@ static bool ath_rc_update_per(struct ath_softc *sc,
100 * 9 / 10
};
- last_per = ath_rc_priv->state[tx_rate].per;
+ last_per = ath_rc_priv->per[tx_rate];
if (xretries) {
if (xretries == 1) {
- ath_rc_priv->state[tx_rate].per += 30;
- if (ath_rc_priv->state[tx_rate].per > 100)
- ath_rc_priv->state[tx_rate].per = 100;
+ ath_rc_priv->per[tx_rate] += 30;
+ if (ath_rc_priv->per[tx_rate] > 100)
+ ath_rc_priv->per[tx_rate] = 100;
} else {
/* xretries == 2 */
count = ARRAY_SIZE(nretry_to_per_lookup);
@@ -974,7 +893,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
retries = count - 1;
/* new_PER = 7/8*old_PER + 1/8*(currentPER) */
- ath_rc_priv->state[tx_rate].per =
+ ath_rc_priv->per[tx_rate] =
(u8)(last_per - (last_per >> 3) + (100 >> 3));
}
@@ -1010,18 +929,14 @@ static bool ath_rc_update_per(struct ath_softc *sc,
n_frames = tx_info_priv->n_frames * (retries + 1);
cur_per = (100 * n_bad_frames / n_frames) >> 3;
new_per = (u8)(last_per - (last_per >> 3) + cur_per);
- ath_rc_priv->state[tx_rate].per = new_per;
+ ath_rc_priv->per[tx_rate] = new_per;
}
} else {
- ath_rc_priv->state[tx_rate].per =
+ ath_rc_priv->per[tx_rate] =
(u8)(last_per - (last_per >> 3) +
(nretry_to_per_lookup[retries] >> 3));
}
- ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev;
- ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last;
- ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi;
- ath_rc_priv->rssi_time = now_msec;
/*
* If we got at most one retry then increase the max rate if
@@ -1045,8 +960,8 @@ static bool ath_rc_update_per(struct ath_softc *sc,
ath_rc_priv->probe_rate;
probe_rate = ath_rc_priv->probe_rate;
- if (ath_rc_priv->state[probe_rate].per > 30)
- ath_rc_priv->state[probe_rate].per = 20;
+ if (ath_rc_priv->per[probe_rate] > 30)
+ ath_rc_priv->per[probe_rate] = 20;
ath_rc_priv->probe_rate = 0;
@@ -1065,18 +980,9 @@ static bool ath_rc_update_per(struct ath_softc *sc,
/*
* Don't update anything. We don't know if
* this was because of collisions or poor signal.
- *
- * Later: if rssi_ack is close to
- * ath_rc_priv->state[txRate].rssi_thres and we see lots
- * of retries, then we could increase
- * ath_rc_priv->state[txRate].rssi_thres.
*/
ath_rc_priv->hw_maxretry_pktcnt = 0;
} else {
- int32_t rssi_ackAvg;
- int8_t rssi_thres;
- int8_t rssi_ack_vmin;
-
/*
* It worked with no retries. First ignore bogus (small)
* rssi_ack values.
@@ -1086,43 +992,9 @@ static bool ath_rc_update_per(struct ath_softc *sc,
ath_rc_priv->hw_maxretry_pktcnt++;
}
- if (tx_info_priv->tx.ts_rssi <
- rate_table->info[tx_rate].rssi_ack_validmin)
- goto exit;
-
- /* Average the rssi */
- if (tx_rate != ath_rc_priv->rssi_sum_rate) {
- ath_rc_priv->rssi_sum_rate = tx_rate;
- ath_rc_priv->rssi_sum =
- ath_rc_priv->rssi_sum_cnt = 0;
- }
-
- ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi;
- ath_rc_priv->rssi_sum_cnt++;
-
- if (ath_rc_priv->rssi_sum_cnt < 4)
- goto exit;
-
- rssi_ackAvg =
- (ath_rc_priv->rssi_sum + 2) / 4;
- rssi_thres =
- ath_rc_priv->state[tx_rate].rssi_thres;
- rssi_ack_vmin =
- rate_table->info[tx_rate].rssi_ack_validmin;
-
- ath_rc_priv->rssi_sum =
- ath_rc_priv->rssi_sum_cnt = 0;
-
- /* Now reduce the current rssi threshold */
- if ((rssi_ackAvg < rssi_thres + 2) &&
- (rssi_thres > rssi_ack_vmin)) {
- ath_rc_priv->state[tx_rate].rssi_thres--;
- }
-
- state_change = true;
}
}
-exit:
+
return state_change;
}
@@ -1134,11 +1006,6 @@ static void ath_rc_update_ht(struct ath_softc *sc,
struct ath_tx_info_priv *tx_info_priv,
int tx_rate, int xretries, int retries)
{
-#define CHK_RSSI(rate) \
- ((ath_rc_priv->state[(rate)].rssi_thres + \
- rate_table->info[(rate)].rssi_ack_deltamin) > \
- ath_rc_priv->state[(rate)+1].rssi_thres)
-
u32 now_msec = jiffies_to_msecs(jiffies);
int rate;
u8 last_per;
@@ -1149,14 +1016,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt))
return;
- /* To compensate for some imbalance between ctrl and ext. channel */
-
- if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy))
- tx_info_priv->tx.ts_rssi =
- tx_info_priv->tx.ts_rssi < 3 ? 0 :
- tx_info_priv->tx.ts_rssi - 3;
-
- last_per = ath_rc_priv->state[tx_rate].per;
+ last_per = ath_rc_priv->per[tx_rate];
/* Update PER first */
state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
@@ -1167,114 +1027,52 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* If this rate looks bad (high PER) then stop using it for
* a while (except if we are probing).
*/
- if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 &&
+ if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 &&
rate_table->info[tx_rate].ratekbps <=
rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) {
- ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv,
- (u8)tx_rate, &ath_rc_priv->rate_max_phy);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv,
+ (u8)tx_rate, &ath_rc_priv->rate_max_phy);
/* Don't probe for a little while. */
ath_rc_priv->probe_time = now_msec;
}
- if (state_change) {
- /*
- * Make sure the rates above this have higher rssi thresholds.
- * (Note: Monotonicity is kept within the OFDM rates and
- * within the CCK rates. However, no adjustment is
- * made to keep the rssi thresholds monotonically
- * increasing between the CCK and OFDM rates.)
- */
- for (rate = tx_rate; rate < size - 1; rate++) {
- if (rate_table->info[rate+1].phy !=
- rate_table->info[tx_rate].phy)
- break;
-
- if (CHK_RSSI(rate)) {
- ath_rc_priv->state[rate+1].rssi_thres =
- ath_rc_priv->state[rate].rssi_thres +
- rate_table->info[rate].rssi_ack_deltamin;
- }
- }
-
- /* Make sure the rates below this have lower rssi thresholds. */
- for (rate = tx_rate - 1; rate >= 0; rate--) {
- if (rate_table->info[rate].phy !=
- rate_table->info[tx_rate].phy)
- break;
-
- if (CHK_RSSI(rate)) {
- if (ath_rc_priv->state[rate+1].rssi_thres <
- rate_table->info[rate].rssi_ack_deltamin)
- ath_rc_priv->state[rate].rssi_thres = 0;
- else {
- ath_rc_priv->state[rate].rssi_thres =
- ath_rc_priv->state[rate+1].rssi_thres -
- rate_table->info[rate].rssi_ack_deltamin;
- }
-
- if (ath_rc_priv->state[rate].rssi_thres <
- rate_table->info[rate].rssi_ack_validmin) {
- ath_rc_priv->state[rate].rssi_thres =
- rate_table->info[rate].rssi_ack_validmin;
- }
- }
- }
- }
-
/* Make sure the rates below this have lower PER */
/* Monotonicity is kept only for rates below the current rate. */
- if (ath_rc_priv->state[tx_rate].per < last_per) {
+ if (ath_rc_priv->per[tx_rate] < last_per) {
for (rate = tx_rate - 1; rate >= 0; rate--) {
- if (rate_table->info[rate].phy !=
- rate_table->info[tx_rate].phy)
- break;
- if (ath_rc_priv->state[rate].per >
- ath_rc_priv->state[rate+1].per) {
- ath_rc_priv->state[rate].per =
- ath_rc_priv->state[rate+1].per;
+ if (ath_rc_priv->per[rate] >
+ ath_rc_priv->per[rate+1]) {
+ ath_rc_priv->per[rate] =
+ ath_rc_priv->per[rate+1];
}
}
}
/* Maintain monotonicity for rates above the current rate */
for (rate = tx_rate; rate < size - 1; rate++) {
- if (ath_rc_priv->state[rate+1].per <
- ath_rc_priv->state[rate].per)
- ath_rc_priv->state[rate+1].per =
- ath_rc_priv->state[rate].per;
- }
-
- /* Every so often, we reduce the thresholds and
- * PER (different for CCK and OFDM). */
- if (now_msec - ath_rc_priv->rssi_down_time >=
- rate_table->rssi_reduce_interval) {
-
- for (rate = 0; rate < size; rate++) {
- if (ath_rc_priv->state[rate].rssi_thres >
- rate_table->info[rate].rssi_ack_validmin)
- ath_rc_priv->state[rate].rssi_thres -= 1;
- }
- ath_rc_priv->rssi_down_time = now_msec;
+ if (ath_rc_priv->per[rate+1] <
+ ath_rc_priv->per[rate])
+ ath_rc_priv->per[rate+1] =
+ ath_rc_priv->per[rate];
}
/* Every so often, we reduce the thresholds
* and PER (different for CCK and OFDM). */
if (now_msec - ath_rc_priv->per_down_time >=
- rate_table->rssi_reduce_interval) {
+ rate_table->probe_interval) {
for (rate = 0; rate < size; rate++) {
- ath_rc_priv->state[rate].per =
- 7 * ath_rc_priv->state[rate].per / 8;
+ ath_rc_priv->per[rate] =
+ 7 * ath_rc_priv->per[rate] / 8;
}
ath_rc_priv->per_down_time = now_msec;
}
ath_debug_stat_retries(sc, tx_rate, xretries, retries,
- ath_rc_priv->state[tx_rate].per);
+ ath_rc_priv->per[tx_rate]);
-#undef CHK_RSSI
}
static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
@@ -1410,9 +1208,7 @@ static void ath_rc_init(struct ath_softc *sc,
/* Initialize thresholds according to the global rate table */
for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) {
- ath_rc_priv->state[i].rssi_thres =
- rate_table->info[i].rssi_ack_validmin;
- ath_rc_priv->state[i].per = 0;
+ ath_rc_priv->per[i] = 0;
}
/* Determine the valid rates */
@@ -1521,7 +1317,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
/*
* If underrun error is seen assume it as an excessive retry only
* if prefetch trigger level have reached the max (0x3f for 5416)
- * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY
+ * Adjust the long retry as if the frame was tried hw->max_rate_tries
* times. This affects how ratectrl updates PER for the failed rate.
*/
if (tx_info_priv->tx.ts_flags &
@@ -1536,7 +1332,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
tx_status = 1;
ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
- (is_underrun) ? ATH_11N_TXMAXTRY :
+ (is_underrun) ? sc->hw->max_rate_tries :
tx_info_priv->tx.ts_longretry);
/* Check if aggregation has to be enabled for this tid */
@@ -1560,31 +1356,6 @@ exit:
kfree(tx_info_priv);
}
-static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
- struct ieee80211_tx_rate_control *txrc)
-{
- struct ieee80211_supported_band *sband = txrc->sband;
- struct sk_buff *skb = txrc->skb;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ath_softc *sc = priv;
- struct ath_rate_priv *ath_rc_priv = priv_sta;
- __le16 fc = hdr->frame_control;
-
- /* lowest rate for management and NO_ACK frames */
- if (!ieee80211_is_data(fc) ||
- tx_info->flags & IEEE80211_TX_CTL_NO_ACK || !sta) {
- tx_info->control.rates[0].idx = rate_lowest_index(sband, sta);
- tx_info->control.rates[0].count =
- (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) ?
- 1 : ATH_MGT_TXMAXTRY;
- return;
- }
-
- /* Find tx rate for unicast frames */
- ath_rc_ratefind(sc, ath_rc_priv, txrc);
-}
-
static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta)
{
@@ -1697,7 +1468,6 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp
return NULL;
}
- rate_priv->rssi_down_time = jiffies_to_msecs(jiffies);
rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max;
return rate_priv;
@@ -1725,8 +1495,6 @@ static struct rate_control_ops ath_rate_ops = {
void ath_rate_attach(struct ath_softc *sc)
{
- sc->hw_rate_table[ATH9K_MODE_11B] =
- &ar5416_11b_ratetable;
sc->hw_rate_table[ATH9K_MODE_11A] =
&ar5416_11a_ratetable;
sc->hw_rate_table[ATH9K_MODE_11G] =
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index e3abd76103fd..fa21a628ddd0 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -112,8 +112,6 @@ struct ath_rate_table {
u8 short_preamble;
u8 dot11rate;
u8 ctrl_rate;
- int8_t rssi_ack_validmin;
- int8_t rssi_ack_deltamin;
u8 base_index;
u8 cw40index;
u8 sgi_index;
@@ -121,15 +119,9 @@ struct ath_rate_table {
u32 max_4ms_framelen;
} info[RATE_TABLE_SIZE];
u32 probe_interval;
- u32 rssi_reduce_interval;
u8 initial_ratemax;
};
-struct ath_tx_ratectrl_state {
- int8_t rssi_thres; /* required rssi for this rate (dB) */
- u8 per; /* recent estimate of packet error rate (%) */
-};
-
struct ath_rateset {
u8 rs_nrates;
u8 rs_rates[ATH_RATE_MAX];
@@ -138,22 +130,14 @@ struct ath_rateset {
/**
* struct ath_rate_priv - Rate Control priv data
* @state: RC state
- * @rssi_last: last ACK rssi
- * @rssi_last_lookup: last ACK rssi used for lookup
- * @rssi_last_prev: previous last ACK rssi
- * @rssi_last_prev2: 2nd previous last ACK rssi
- * @rssi_sum_cnt: count of rssi_sum for averaging
- * @rssi_sum_rate: rate that we are averaging
- * @rssi_sum: running sum of rssi for averaging
* @probe_rate: rate we are probing at
- * @rssi_time: msec timestamp for last ack rssi
- * @rssi_down_time: msec timestamp for last down step
* @probe_time: msec timestamp for last probe
* @hw_maxretry_pktcnt: num of packets since we got HW max retry error
* @max_valid_rate: maximum number of valid rate
* @per_down_time: msec timestamp for last PER down step
* @valid_phy_ratecnt: valid rate count
* @rate_max_phy: phy index for the max rate
+ * @per: PER for every valid rate in %
* @probe_interval: interval for ratectrl to probe for other rates
* @prev_data_rix: rate idx of last data frame
* @ht_cap: HT capabilities
@@ -161,13 +145,6 @@ struct ath_rateset {
* @neg_ht_rates: Negotiated HT rates
*/
struct ath_rate_priv {
- int8_t rssi_last;
- int8_t rssi_last_lookup;
- int8_t rssi_last_prev;
- int8_t rssi_last_prev2;
- int32_t rssi_sum_cnt;
- int32_t rssi_sum_rate;
- int32_t rssi_sum;
u8 rate_table_size;
u8 probe_rate;
u8 hw_maxretry_pktcnt;
@@ -177,14 +154,12 @@ struct ath_rate_priv {
u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE];
u8 rate_max_phy;
- u32 rssi_time;
- u32 rssi_down_time;
+ u8 per[RATE_TABLE_SIZE];
u32 probe_time;
u32 per_down_time;
u32 probe_interval;
u32 prev_data_rix;
u32 tx_triglevel_max;
- struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE];
struct ath_rateset neg_rates;
struct ath_rateset neg_ht_rates;
struct ath_rate_softc *asc;
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index cece1c4c6bda..ec0abf823995 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)
return (tsf & ~0x7fff) | rstamp;
}
-static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len, gfp_t gfp_mask)
-{
- struct sk_buff *skb;
- u32 off;
-
- /*
- * Cache-line-align. This is important (for the
- * 5210 at least) as not doing so causes bogus data
- * in rx'd frames.
- */
-
- /* Note: the kernel can allocate a value greater than
- * what we ask it to give us. We really only need 4 KB as that
- * is this hardware supports and in fact we need at least 3849
- * as that is the MAX AMSDU size this hardware supports.
- * Unfortunately this means we may get 8 KB here from the
- * kernel... and that is actually what is observed on some
- * systems :( */
- skb = __dev_alloc_skb(len + sc->cachelsz - 1, gfp_mask);
- if (skb != NULL) {
- off = ((unsigned long) skb->data) % sc->cachelsz;
- if (off != 0)
- skb_reserve(skb, sc->cachelsz - off);
- } else {
- DPRINTF(sc, ATH_DBG_FATAL,
- "skbuff alloc of size %u failed\n", len);
- return NULL;
- }
-
- return skb;
-}
-
/*
* For Decrypt or Demic errors, we only mark packet status here and always push
* up the frame up to let mac80211 handle the actual error case, be it no
@@ -145,6 +113,10 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
u8 ratecode;
__le16 fc;
struct ieee80211_hw *hw;
+ struct ieee80211_sta *sta;
+ struct ath_node *an;
+ int last_rssi = ATH_RSSI_DUMMY_MARKER;
+
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
@@ -229,17 +201,61 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
}
}
+ rcu_read_lock();
+ sta = ieee80211_find_sta(sc->hw, hdr->addr2);
+ if (sta) {
+ an = (struct ath_node *) sta->drv_priv;
+ if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD &&
+ !ds->ds_rxstat.rs_moreaggr)
+ ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi);
+ last_rssi = an->last_rssi;
+ }
+ rcu_read_unlock();
+
+ if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
+ ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi,
+ ATH_RSSI_EP_MULTIPLIER);
+ if (ds->ds_rxstat.rs_rssi < 0)
+ ds->ds_rxstat.rs_rssi = 0;
+ else if (ds->ds_rxstat.rs_rssi > 127)
+ ds->ds_rxstat.rs_rssi = 127;
+
+ /* Update Beacon RSSI, this is used by ANI. */
+ if (ieee80211_is_beacon(fc))
+ sc->sc_ah->stats.avgbrssi = ds->ds_rxstat.rs_rssi;
+
rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
rx_status->band = hw->conf.channel->band;
rx_status->freq = hw->conf.channel->center_freq;
rx_status->noise = sc->ani.noise_floor;
- rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
+ rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi;
rx_status->antenna = ds->ds_rxstat.rs_antenna;
- /* at 45 you will be able to use MCS 15 reliably. A more elaborate
- * scheme can be used here but it requires tables of SNR/throughput for
- * each possible mode used. */
- rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45;
+ /*
+ * Theory for reporting quality:
+ *
+ * At a hardware RSSI of 45 you will be able to use MCS 7 reliably.
+ * At a hardware RSSI of 45 you will be able to use MCS 15 reliably.
+ * At a hardware RSSI of 35 you should be able use 54 Mbps reliably.
+ *
+ * MCS 7 is the highets MCS index usable by a 1-stream device.
+ * MCS 15 is the highest MCS index usable by a 2-stream device.
+ *
+ * All ath9k devices are either 1-stream or 2-stream.
+ *
+ * How many bars you see is derived from the qual reporting.
+ *
+ * A more elaborate scheme can be used here but it requires tables
+ * of SNR/throughput for each possible mode used. For the MCS table
+ * you can refer to the wireless wiki:
+ *
+ * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
+ *
+ */
+ if (conf_is_ht(&hw->conf))
+ rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45;
+ else
+ rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 35;
/* rssi can be more than 45 though, anything above that
* should be considered at 100% */
@@ -288,10 +304,10 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
spin_lock_init(&sc->rx.rxbuflock);
sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
- min(sc->cachelsz, (u16)64));
+ min(sc->common.cachelsz, (u16)64));
DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
- sc->cachelsz, sc->rx.bufsize);
+ sc->common.cachelsz, sc->rx.bufsize);
/* Initialize rx descriptors */
@@ -304,7 +320,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
}
list_for_each_entry(bf, &sc->rx.rxbuf, list) {
- skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL);
+ skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_KERNEL);
if (skb == NULL) {
error = -ENOMEM;
goto err;
@@ -404,15 +420,18 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
else
rfilt |= ATH9K_RX_FILTER_BEACON;
- /* If in HOSTAP mode, want to enable reception of PSPOLL frames */
- if (sc->sc_ah->opmode == NL80211_IFTYPE_AP)
+ if (sc->rx.rxfilter & FIF_PSPOLL)
rfilt |= ATH9K_RX_FILTER_PSPOLL;
- if (sc->sec_wiphy) {
+ if (conf_is_ht(&sc->hw->conf))
+ rfilt |= ATH9K_RX_FILTER_COMP_BAR;
+
+ if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
/* TODO: only needed if more than one BSSID is in use in
* station/adhoc mode */
- /* TODO: for older chips, may need to add ATH9K_RX_FILTER_PROM
- */
+ /* The following may also be needed for other older chips */
+ if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160)
+ rfilt |= ATH9K_RX_FILTER_PROM;
rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
}
@@ -505,11 +524,6 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
return false;
}
-static void ath_rx_ps_back_to_sleep(struct ath_softc *sc)
-{
- sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
-}
-
static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt;
@@ -521,6 +535,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0)
return; /* not from our current AP */
+ sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
+
if (sc->sc_flags & SC_OP_BEACON_SYNC) {
sc->sc_flags &= ~SC_OP_BEACON_SYNC;
DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on "
@@ -528,14 +544,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
ath_beacon_config(sc, NULL);
}
- if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) {
- /* We are not in PS mode anymore; remain awake */
- DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain "
- "awake\n");
- sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
- return;
- }
-
if (ath_beacon_dtim_pending_cab(skb)) {
/*
* Remain awake waiting for buffered broadcast/multicast
@@ -556,11 +564,9 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
* fails to send a frame indicating that all CAB frames have
* been delivered.
*/
+ sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n");
}
-
- /* No more broadcast/multicast frames to be received at this point. */
- ath_rx_ps_back_to_sleep(sc);
}
static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
@@ -578,13 +584,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
ieee80211_is_action(hdr->frame_control)) &&
is_multicast_ether_addr(hdr->addr1) &&
!ieee80211_has_moredata(hdr->frame_control)) {
- DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
- "sleep\n");
/*
* No more broadcast/multicast frames to be received at this
* point.
*/
- ath_rx_ps_back_to_sleep(sc);
+ sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
+ DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
+ "sleep\n");
} else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) &&
!is_multicast_ether_addr(hdr->addr1) &&
!ieee80211_has_morefrags(hdr->frame_control)) {
@@ -619,13 +625,18 @@ static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
if (aphy == NULL)
continue;
nskb = skb_copy(skb, GFP_ATOMIC);
- if (nskb)
- __ieee80211_rx(aphy->hw, nskb, rx_status);
+ if (nskb) {
+ memcpy(IEEE80211_SKB_RXCB(nskb), rx_status,
+ sizeof(*rx_status));
+ ieee80211_rx(aphy->hw, nskb);
+ }
}
- __ieee80211_rx(sc->hw, skb, rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
+ ieee80211_rx(sc->hw, skb);
} else {
/* Deliver unicast frames based on receiver address */
- __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
+ ieee80211_rx(ath_get_virt_hw(sc, hdr), skb);
}
}
@@ -738,7 +749,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
/* Ensure we always have an skb to requeue once we are done
* processing the current buffer's skb */
- requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_ATOMIC);
+ requeue_skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_ATOMIC);
/* If there is no memory we ignore the current RX'd frame,
* tell hardware it can give us a new frame using the old
@@ -753,7 +764,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
DMA_FROM_DEVICE);
skb_put(skb, ds->ds_rxstat.rs_datalen);
- skb->protocol = cpu_to_be16(ETH_P_CONTROL);
/* see if any padding is done by the hw and remove it */
hdr = (struct ieee80211_hdr *)skb->data;
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 52605246679f..e5c29eb86e80 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -234,7 +234,15 @@
#define AR_IMR_S5 0x00b8
#define AR_IMR_S5_TIM_TIMER 0x00000010
#define AR_IMR_S5_DTIM_TIMER 0x00000020
-
+#define AR_ISR_S5_GENTIMER_TRIG 0x0000FF80
+#define AR_ISR_S5_GENTIMER_TRIG_S 0
+#define AR_ISR_S5_GENTIMER_THRESH 0xFF800000
+#define AR_ISR_S5_GENTIMER_THRESH_S 16
+#define AR_ISR_S5_S 0x00d8
+#define AR_IMR_S5_GENTIMER_TRIG 0x0000FF80
+#define AR_IMR_S5_GENTIMER_TRIG_S 0
+#define AR_IMR_S5_GENTIMER_THRESH 0xFF800000
+#define AR_IMR_S5_GENTIMER_THRESH_S 16
#define AR_IMR 0x00a0
#define AR_IMR_RXOK 0x00000001
@@ -574,6 +582,7 @@
#define AR_D_GBL_IFS_SIFS 0x1030
#define AR_D_GBL_IFS_SIFS_M 0x0000FFFF
+#define AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR 0x000003AB
#define AR_D_GBL_IFS_SIFS_RESV0 0xFFFFFFFF
#define AR_D_TXBLK_BASE 0x1038
@@ -589,10 +598,12 @@
#define AR_D_GBL_IFS_SLOT 0x1070
#define AR_D_GBL_IFS_SLOT_M 0x0000FFFF
#define AR_D_GBL_IFS_SLOT_RESV0 0xFFFF0000
+#define AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR 0x00000420
#define AR_D_GBL_IFS_EIFS 0x10b0
#define AR_D_GBL_IFS_EIFS_M 0x0000FFFF
#define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000
+#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR 0x0000A5EB
#define AR_D_GBL_IFS_MISC 0x10f0
#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007
@@ -738,6 +749,13 @@
#define AR_SREV_REVISION_9285_10 0
#define AR_SREV_REVISION_9285_11 1
#define AR_SREV_REVISION_9285_12 2
+#define AR_SREV_VERSION_9287 0x180
+#define AR_SREV_REVISION_9287_10 0
+#define AR_SREV_REVISION_9287_11 1
+#define AR_SREV_REVISION_9287_12 2
+#define AR_SREV_VERSION_9271 0x140
+#define AR_SREV_REVISION_9271_10 0
+#define AR_SREV_REVISION_9271_11 1
#define AR_SREV_5416(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -794,6 +812,36 @@
(AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \
AR_SREV_REVISION_9285_12)))
+#define AR_SREV_9287(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287))
+#define AR_SREV_9287_10_OR_LATER(_ah) \
+ (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9287))
+#define AR_SREV_9287_10(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_10))
+#define AR_SREV_9287_11(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_11))
+#define AR_SREV_9287_11_OR_LATER(_ah) \
+ (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11)))
+#define AR_SREV_9287_12(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_12))
+#define AR_SREV_9287_12_OR_LATER(_ah) \
+ (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_12)))
+#define AR_SREV_9271(_ah) \
+ (((_ah))->hw_version.macVersion == AR_SREV_VERSION_9271)
+#define AR_SREV_9271_10(_ah) \
+ (AR_SREV_9271(_ah) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_10))
+#define AR_SREV_9271_11(_ah) \
+ (AR_SREV_9271(_ah) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11))
+
#define AR_RADIO_SREV_MAJOR 0xf0
#define AR_RAD5133_SREV_MAJOR 0xc0
#define AR_RAD2133_SREV_MAJOR 0xd0
@@ -809,6 +857,9 @@
#define AR_AHB_PAGE_SIZE_1K 0x00000000
#define AR_AHB_PAGE_SIZE_2K 0x00000008
#define AR_AHB_PAGE_SIZE_4K 0x00000010
+#define AR_AHB_CUSTOM_BURST_EN 0x000000C0
+#define AR_AHB_CUSTOM_BURST_EN_S 6
+#define AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL 3
#define AR_INTR_RTC_IRQ 0x00000001
#define AR_INTR_MAC_IRQ 0x00000002
@@ -885,6 +936,7 @@ enum {
#define AR_NUM_GPIO 14
#define AR928X_NUM_GPIO 10
#define AR9285_NUM_GPIO 12
+#define AR9287_NUM_GPIO 11
#define AR_GPIO_IN_OUT 0x4048
#define AR_GPIO_IN_VAL 0x0FFFC000
@@ -893,6 +945,8 @@ enum {
#define AR928X_GPIO_IN_VAL_S 10
#define AR9285_GPIO_IN_VAL 0x00FFF000
#define AR9285_GPIO_IN_VAL_S 12
+#define AR9287_GPIO_IN_VAL 0x003FF800
+#define AR9287_GPIO_IN_VAL_S 11
#define AR_GPIO_OE_OUT 0x404c
#define AR_GPIO_OE_OUT_DRV 0x3
@@ -916,6 +970,8 @@ enum {
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7
#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000
#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00001000
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 1
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15
#define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000
@@ -924,6 +980,8 @@ enum {
#define AR_GPIO_INPUT_MUX1 0x4058
#define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000
#define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16
+#define AR_GPIO_INPUT_MUX1_BT_PRIORITY 0x00000f00
+#define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S 8
#define AR_GPIO_INPUT_MUX2 0x405c
#define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f
@@ -949,6 +1007,8 @@ enum {
#define AR_OBS 0x4080
+#define AR_GPIO_PDPU 0x4088
+
#define AR_PCIE_MSI 0x4094
#define AR_PCIE_MSI_ENABLE 0x00000001
@@ -1115,12 +1175,32 @@ enum {
#define AR9285_AN_RF2G4_DB2_4 0x00003800
#define AR9285_AN_RF2G4_DB2_4_S 11
+/* AR9271 : 0x7828, 0x782c different setting from AR9285 */
+#define AR9271_AN_RF2G3_OB_cck 0x001C0000
+#define AR9271_AN_RF2G3_OB_cck_S 18
+#define AR9271_AN_RF2G3_OB_psk 0x00038000
+#define AR9271_AN_RF2G3_OB_psk_S 15
+#define AR9271_AN_RF2G3_OB_qam 0x00007000
+#define AR9271_AN_RF2G3_OB_qam_S 12
+
+#define AR9271_AN_RF2G3_DB_1 0x00E00000
+#define AR9271_AN_RF2G3_DB_1_S 21
+
+#define AR9271_AN_RF2G3_CCOMP 0xFFF
+#define AR9271_AN_RF2G3_CCOMP_S 0
+
+#define AR9271_AN_RF2G4_DB_2 0xE0000000
+#define AR9271_AN_RF2G4_DB_2_S 29
+
#define AR9285_AN_RF2G6 0x7834
#define AR9285_AN_RF2G6_CCOMP 0x00007800
#define AR9285_AN_RF2G6_CCOMP_S 11
#define AR9285_AN_RF2G6_OFFS 0x03f00000
#define AR9285_AN_RF2G6_OFFS_S 20
+#define AR9271_AN_RF2G6_OFFS 0x07f00000
+#define AR9271_AN_RF2G6_OFFS_S 20
+
#define AR9285_AN_RF2G7 0x7838
#define AR9285_AN_RF2G7_PWDDB 0x00000002
#define AR9285_AN_RF2G7_PWDDB_S 1
@@ -1154,6 +1234,38 @@ enum {
#define AR9285_AN_TOP4 0x7870
#define AR9285_AN_TOP4_DEFAULT 0x10142c00
+#define AR9287_AN_RF2G3_CH0 0x7808
+#define AR9287_AN_RF2G3_CH1 0x785c
+#define AR9287_AN_RF2G3_DB1 0xE0000000
+#define AR9287_AN_RF2G3_DB1_S 29
+#define AR9287_AN_RF2G3_DB2 0x1C000000
+#define AR9287_AN_RF2G3_DB2_S 26
+#define AR9287_AN_RF2G3_OB_CCK 0x03800000
+#define AR9287_AN_RF2G3_OB_CCK_S 23
+#define AR9287_AN_RF2G3_OB_PSK 0x00700000
+#define AR9287_AN_RF2G3_OB_PSK_S 20
+#define AR9287_AN_RF2G3_OB_QAM 0x000E0000
+#define AR9287_AN_RF2G3_OB_QAM_S 17
+#define AR9287_AN_RF2G3_OB_PAL_OFF 0x0001C000
+#define AR9287_AN_RF2G3_OB_PAL_OFF_S 14
+
+#define AR9287_AN_TXPC0 0x7898
+#define AR9287_AN_TXPC0_TXPCMODE 0x0000C000
+#define AR9287_AN_TXPC0_TXPCMODE_S 14
+#define AR9287_AN_TXPC0_TXPCMODE_NORMAL 0
+#define AR9287_AN_TXPC0_TXPCMODE_TEST 1
+#define AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE 2
+#define AR9287_AN_TXPC0_TXPCMODE_ATBTEST 3
+
+#define AR9287_AN_TOP2 0x78b4
+#define AR9287_AN_TOP2_XPABIAS_LVL 0xC0000000
+#define AR9287_AN_TOP2_XPABIAS_LVL_S 30
+
+/* AR9271 specific stuff */
+#define AR9271_RESET_POWER_DOWN_CONTROL 0x50044
+#define AR9271_RADIO_RF_RST 0x20
+#define AR9271_GATE_MAC_CTL 0x4000
+
#define AR_STA_ID0 0x8000
#define AR_STA_ID1 0x8004
#define AR_STA_ID1_SADH_MASK 0x0000FFFF
@@ -1188,6 +1300,7 @@ enum {
#define AR_TIME_OUT_ACK_S 0
#define AR_TIME_OUT_CTS 0x3FFF0000
#define AR_TIME_OUT_CTS_S 16
+#define AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR 0x16001D56
#define AR_RSSI_THR 0x8018
#define AR_RSSI_THR_MASK 0x000000FF
@@ -1203,6 +1316,7 @@ enum {
#define AR_USEC_TX_LAT_S 14
#define AR_USEC_RX_LAT 0x1F800000
#define AR_USEC_RX_LAT_S 23
+#define AR_USEC_ASYNC_FIFO_DUR 0x12e00074
#define AR_RESET_TSF 0x8020
#define AR_RESET_TSF_ONCE 0x01000000
@@ -1211,7 +1325,6 @@ enum {
#define AR_CFP_VAL 0x0000FFFF
#define AR_RX_FILTER 0x803C
-#define AR_RX_COMPR_BAR 0x00000400
#define AR_MCAST_FIL0 0x8040
#define AR_MCAST_FIL1 0x8044
@@ -1328,6 +1441,7 @@ enum {
#define AR_QUIET1_NEXT_QUIET_M 0x0000ffff
#define AR_QUIET1_QUIET_ENABLE 0x00010000
#define AR_QUIET1_QUIET_ACK_CTS_ENABLE 0x00020000
+#define AR_QUIET1_QUIET_ACK_CTS_ENABLE_S 17
#define AR_QUIET2 0x8100
#define AR_QUIET2_QUIET_PERIOD_S 0
#define AR_QUIET2_QUIET_PERIOD_M 0x0000ffff
@@ -1373,6 +1487,8 @@ enum {
#define AR_PCU_CLEAR_VMF 0x01000000
#define AR_PCU_CLEAR_BA_VALID 0x04000000
+#define AR_PCU_BT_ANT_PREVENT_RX 0x00100000
+#define AR_PCU_BT_ANT_PREVENT_RX_S 20
#define AR_FILT_OFDM 0x8124
#define AR_FILT_OFDM_COUNT 0x00FFFFFF
@@ -1400,6 +1516,46 @@ enum {
#define AR_PHY_ERR_3_COUNT 0x00FFFFFF
#define AR_PHY_ERR_MASK_3 0x816c
+#define AR_BT_COEX_MODE 0x8170
+#define AR_BT_TIME_EXTEND 0x000000ff
+#define AR_BT_TIME_EXTEND_S 0
+#define AR_BT_TXSTATE_EXTEND 0x00000100
+#define AR_BT_TXSTATE_EXTEND_S 8
+#define AR_BT_TX_FRAME_EXTEND 0x00000200
+#define AR_BT_TX_FRAME_EXTEND_S 9
+#define AR_BT_MODE 0x00000c00
+#define AR_BT_MODE_S 10
+#define AR_BT_QUIET 0x00001000
+#define AR_BT_QUIET_S 12
+#define AR_BT_QCU_THRESH 0x0001e000
+#define AR_BT_QCU_THRESH_S 13
+#define AR_BT_RX_CLEAR_POLARITY 0x00020000
+#define AR_BT_RX_CLEAR_POLARITY_S 17
+#define AR_BT_PRIORITY_TIME 0x00fc0000
+#define AR_BT_PRIORITY_TIME_S 18
+#define AR_BT_FIRST_SLOT_TIME 0xff000000
+#define AR_BT_FIRST_SLOT_TIME_S 24
+
+#define AR_BT_COEX_WEIGHT 0x8174
+#define AR_BT_COEX_WGHT 0xff55
+#define AR_STOMP_ALL_WLAN_WGHT 0xffcc
+#define AR_STOMP_LOW_WLAN_WGHT 0xaaa8
+#define AR_STOMP_NONE_WLAN_WGHT 0xaa00
+#define AR_BTCOEX_BT_WGHT 0x0000ffff
+#define AR_BTCOEX_BT_WGHT_S 0
+#define AR_BTCOEX_WL_WGHT 0xffff0000
+#define AR_BTCOEX_WL_WGHT_S 16
+
+#define AR_BT_COEX_MODE2 0x817c
+#define AR_BT_BCN_MISS_THRESH 0x000000ff
+#define AR_BT_BCN_MISS_THRESH_S 0
+#define AR_BT_BCN_MISS_CNT 0x0000ff00
+#define AR_BT_BCN_MISS_CNT_S 8
+#define AR_BT_HOLD_RX_CLEAR 0x00010000
+#define AR_BT_HOLD_RX_CLEAR_S 16
+#define AR_BT_DISABLE_BT_ANT 0x00100000
+#define AR_BT_DISABLE_BT_ANT_S 20
+
#define AR_TXSIFS 0x81d0
#define AR_TXSIFS_TIME 0x000000FF
#define AR_TXSIFS_TX_LATENCY 0x00000F00
@@ -1416,7 +1572,10 @@ enum {
#define AR_TXOP_8_11 0x81f8
#define AR_TXOP_12_15 0x81fc
-
+#define AR_NEXT_NDP2_TIMER 0x8180
+#define AR_FIRST_NDP_TIMER 7
+#define AR_NDP2_PERIOD 0x81a0
+#define AR_NDP2_TIMER_MODE 0x81c0
#define AR_NEXT_TBTT_TIMER 0x8200
#define AR_NEXT_DMA_BEACON_ALERT 0x8204
#define AR_NEXT_SWBA 0x8208
@@ -1468,6 +1627,10 @@ enum {
#define AR_SLP_MIB_CLEAR 0x00000001
#define AR_SLP_MIB_PENDING 0x00000002
+#define AR_MAC_PCU_LOGIC_ANALYZER 0x8264
+#define AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768 0x20000000
+
+
#define AR_2040_MODE 0x8318
#define AR_2040_JOINED_RX_CLEAR 0x00000001
@@ -1485,6 +1648,39 @@ enum {
#define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002
#define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT 0x00000004
+#define AR_PCU_MISC_MODE2_RESERVED 0x00000038
+#define AR_PCU_MISC_MODE2_ADHOC_MCAST_KEYID_ENABLE 0x00000040
+#define AR_PCU_MISC_MODE2_CFP_IGNORE 0x00000080
+#define AR_PCU_MISC_MODE2_MGMT_QOS 0x0000FF00
+#define AR_PCU_MISC_MODE2_MGMT_QOS_S 8
+#define AR_PCU_MISC_MODE2_ENABLE_LOAD_NAV_BEACON_DURATION 0x00010000
+#define AR_PCU_MISC_MODE2_ENABLE_AGGWEP 0x00020000
+#define AR_PCU_MISC_MODE2_HWWAR1 0x00100000
+#define AR_PCU_MISC_MODE2_HWWAR2 0x02000000
+#define AR_PCU_MISC_MODE2_RESERVED2 0xFFFE0000
+
+#define AR_MAC_PCU_ASYNC_FIFO_REG3 0x8358
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL 0x00000400
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000
+
+
+#define AR_AES_MUTE_MASK0 0x805c
+#define AR_AES_MUTE_MASK0_FC 0x0000FFFF
+#define AR_AES_MUTE_MASK0_QOS 0xFFFF0000
+#define AR_AES_MUTE_MASK0_QOS_S 16
+
+#define AR_AES_MUTE_MASK1 0x8060
+#define AR_AES_MUTE_MASK1_SEQ 0x0000FFFF
+#define AR_AES_MUTE_MASK1_SEQ_S 0
+#define AR_AES_MUTE_MASK1_FC_MGMT 0xFFFF0000
+#define AR_AES_MUTE_MASK1_FC_MGMT_S 16
+
+#define AR_RATE_DURATION_0 0x8700
+#define AR_RATE_DURATION_31 0x87CC
+#define AR_RATE_DURATION_32 0x8780
+#define AR_RATE_DURATION(_n) (AR_RATE_DURATION_0 + ((_n)<<2))
+
+
#define AR_KEYTABLE_0 0x8800
#define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32))
#define AR_KEY_CACHE_SIZE 128
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index 1ff429b027d7..19b88f8177fd 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -351,7 +351,7 @@ void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
* Drop from tasklet to work to allow mutex for channel
* change.
*/
- queue_work(aphy->sc->hw->workqueue,
+ ieee80211_queue_work(aphy->sc->hw,
&aphy->sc->chan_work);
}
}
@@ -367,7 +367,7 @@ static void ath9k_mark_paused(struct ath_wiphy *aphy)
struct ath_softc *sc = aphy->sc;
aphy->state = ATH_WIPHY_PAUSED;
if (!__ath9k_wiphy_pausing(sc))
- queue_work(sc->hw->workqueue, &sc->chan_work);
+ ieee80211_queue_work(sc->hw, &sc->chan_work);
}
static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
@@ -521,7 +521,7 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy)
spin_unlock_bh(&sc->wiphy_lock);
ath_radio_disable(sc);
ath_radio_enable(sc);
- queue_work(aphy->sc->hw->workqueue,
+ ieee80211_queue_work(aphy->sc->hw,
&aphy->sc->chan_work);
return -EBUSY; /* previous select still in progress */
}
@@ -541,7 +541,7 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy)
if (now) {
/* Ready to request channel change immediately */
- queue_work(aphy->sc->hw->workqueue, &aphy->sc->chan_work);
+ ieee80211_queue_work(aphy->sc->hw, &aphy->sc->chan_work);
}
/*
@@ -648,8 +648,9 @@ try_again:
"change\n");
}
- queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
- sc->wiphy_scheduler_int);
+ ieee80211_queue_delayed_work(sc->hw,
+ &sc->wiphy_work,
+ sc->wiphy_scheduler_int);
}
void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
@@ -657,6 +658,23 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
cancel_delayed_work_sync(&sc->wiphy_work);
sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int);
if (sc->wiphy_scheduler_int)
- queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
- sc->wiphy_scheduler_int);
+ ieee80211_queue_delayed_work(sc->hw, &sc->wiphy_work,
+ sc->wiphy_scheduler_int);
+}
+
+/* caller must hold wiphy_lock */
+bool ath9k_all_wiphys_idle(struct ath_softc *sc)
+{
+ unsigned int i;
+ if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) {
+ return false;
+ }
+ for (i = 0; i < sc->num_sec_wiphy; i++) {
+ struct ath_wiphy *aphy = sc->sec_wiphy[i];
+ if (!aphy)
+ continue;
+ if (aphy->state != ATH_WIPHY_INACTIVE)
+ return false;
+ }
+ return true;
}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 4ccf48e396df..42551a48c8ac 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -59,6 +59,7 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid,
struct list_head *bf_head);
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
+ struct ath_txq *txq,
struct list_head *bf_q,
int txok, int sendbar);
static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
@@ -73,18 +74,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
/* Aggregation logic */
/*********************/
-static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno)
-{
- struct ath_atx_tid *tid;
- tid = ATH_AN_2_TID(an, tidno);
-
- if (tid->state & AGGR_ADDBA_COMPLETE ||
- tid->state & AGGR_ADDBA_PROGRESS)
- return 1;
- else
- return 0;
-}
-
static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
{
struct ath_atx_ac *ac = tid->ac;
@@ -224,7 +213,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_update_baw(sc, tid, bf->bf_seqno);
spin_unlock(&txq->axq_lock);
- ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
spin_lock(&txq->axq_lock);
}
@@ -232,13 +221,15 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
tid->baw_tail = tid->baw_head;
}
-static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf)
+static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf)
{
struct sk_buff *skb;
struct ieee80211_hdr *hdr;
bf->bf_state.bf_type |= BUF_RETRY;
bf->bf_retries++;
+ TX_STAT_INC(txq->axq_qnum, a_retries);
skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
@@ -250,7 +241,10 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
struct ath_buf *tbf;
spin_lock_bh(&sc->tx.txbuflock);
- ASSERT(!list_empty((&sc->tx.txbuf)));
+ if (WARN_ON(list_empty(&sc->tx.txbuf))) {
+ spin_unlock_bh(&sc->tx.txbuflock);
+ return NULL;
+ }
tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
list_del(&tbf->list);
spin_unlock_bh(&sc->tx.txbuflock);
@@ -337,7 +331,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (!(tid->state & AGGR_CLEANUP) &&
ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) {
if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
- ath_tx_set_retry(sc, bf);
+ ath_tx_set_retry(sc, txq, bf);
txpending = 1;
} else {
bf->bf_state.bf_type |= BUF_XRETRY;
@@ -384,13 +378,31 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_rc_status(bf, ds, nbad, txok, false);
}
- ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, !txfail, sendbar);
} else {
/* retry the un-acked ones */
if (bf->bf_next == NULL && bf_last->bf_stale) {
struct ath_buf *tbf;
tbf = ath_clone_txbuf(sc, bf_last);
+ /*
+ * Update tx baw and complete the frame with
+ * failed status if we run out of tx buf
+ */
+ if (!tbf) {
+ spin_lock_bh(&txq->axq_lock);
+ ath_tx_update_baw(sc, tid,
+ bf->bf_seqno);
+ spin_unlock_bh(&txq->axq_lock);
+
+ bf->bf_state.bf_type |= BUF_XRETRY;
+ ath_tx_rc_status(bf, ds, nbad,
+ 0, false);
+ ath_tx_complete_buf(sc, bf, txq,
+ &bf_head, 0, 0);
+ break;
+ }
+
ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc);
list_add_tail(&tbf->list, &bf_head);
} else {
@@ -414,7 +426,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (tid->state & AGGR_CLEANUP) {
if (tid->baw_head == tid->baw_tail) {
tid->state &= ~AGGR_ADDBA_COMPLETE;
- tid->addba_exchangeattempts = 0;
tid->state &= ~AGGR_CLEANUP;
/* send buffered frames as singles */
@@ -447,7 +458,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
struct ieee80211_tx_rate *rates;
struct ath_tx_info_priv *tx_info_priv;
u32 max_4ms_framelen, frmlen;
- u16 aggr_limit, legacy = 0, maxampdu;
+ u16 aggr_limit, legacy = 0;
int i;
skb = bf->bf_mpdu;
@@ -482,16 +493,20 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
return 0;
- aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_DEFAULT);
+ if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
+ aggr_limit = min((max_4ms_framelen * 3) / 8,
+ (u32)ATH_AMPDU_LIMIT_MAX);
+ else
+ aggr_limit = min(max_4ms_framelen,
+ (u32)ATH_AMPDU_LIMIT_MAX);
/*
* h/w can accept aggregates upto 16 bit lengths (65535).
* The IE, however can hold upto 65536, which shows up here
* as zero. Ignore 65536 since we are constrained by hw.
*/
- maxampdu = tid->an->maxampdu;
- if (maxampdu)
- aggr_limit = min(aggr_limit, maxampdu);
+ if (tid->an->maxampdu)
+ aggr_limit = min(aggr_limit, tid->an->maxampdu);
return aggr_limit;
}
@@ -499,7 +514,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
/*
* Returns the number of delimiters to be added to
* meet the minimum required mpdudensity.
- * caller should make sure that the rate is HT rate .
*/
static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
struct ath_buf *bf, u16 frmlen)
@@ -507,7 +521,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
const struct ath_rate_table *rt = sc->cur_rate_table;
struct sk_buff *skb = bf->bf_mpdu;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- u32 nsymbits, nsymbols, mpdudensity;
+ u32 nsymbits, nsymbols;
u16 minlen;
u8 rc, flags, rix;
int width, half_gi, ndelim, mindelim;
@@ -529,14 +543,12 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
* on highest rate in rate series (i.e. first rate) to determine
* required minimum length for subframe. Take into account
* whether high rate is 20 or 40Mhz and half or full GI.
- */
- mpdudensity = tid->an->mpdudensity;
-
- /*
+ *
* If there is no mpdu density restriction, no further calculation
* is needed.
*/
- if (mpdudensity == 0)
+
+ if (tid->an->mpdudensity == 0)
return ndelim;
rix = tx_info->control.rates[0].idx;
@@ -546,9 +558,9 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
if (half_gi)
- nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity);
+ nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
else
- nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity);
+ nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
if (nsymbols == 0)
nsymbols = 1;
@@ -565,6 +577,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
}
static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
+ struct ath_txq *txq,
struct ath_atx_tid *tid,
struct list_head *bf_q)
{
@@ -629,6 +642,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
bf_prev->bf_desc->ds_link = bf->bf_daddr;
}
bf_prev = bf;
+
} while (!list_empty(&tid->buf_q));
bf_first->bf_al = al;
@@ -651,7 +665,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
INIT_LIST_HEAD(&bf_q);
- status = ath_tx_form_aggr(sc, tid, &bf_q);
+ status = ath_tx_form_aggr(sc, txq, tid, &bf_q);
/*
* no frames picked up to be aggregated;
@@ -682,30 +696,26 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
txq->axq_aggr_depth++;
ath_tx_txqaddbuf(sc, txq, &bf_q);
+ TX_STAT_INC(txq->axq_qnum, a_aggr);
} while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
status != ATH_AGGR_BAW_CLOSED);
}
-int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
- u16 tid, u16 *ssn)
+void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+ u16 tid, u16 *ssn)
{
struct ath_atx_tid *txtid;
struct ath_node *an;
an = (struct ath_node *)sta->drv_priv;
-
- if (sc->sc_flags & SC_OP_TXAGGR) {
- txtid = ATH_AN_2_TID(an, tid);
- txtid->state |= AGGR_ADDBA_PROGRESS;
- ath_tx_pause_tid(sc, txtid);
- *ssn = txtid->seq_start;
- }
-
- return 0;
+ txtid = ATH_AN_2_TID(an, tid);
+ txtid->state |= AGGR_ADDBA_PROGRESS;
+ ath_tx_pause_tid(sc, txtid);
+ *ssn = txtid->seq_start;
}
-int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
+void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
{
struct ath_node *an = (struct ath_node *)sta->drv_priv;
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
@@ -715,12 +725,11 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
INIT_LIST_HEAD(&bf_head);
if (txtid->state & AGGR_CLEANUP)
- return 0;
+ return;
if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
txtid->state &= ~AGGR_ADDBA_PROGRESS;
- txtid->addba_exchangeattempts = 0;
- return 0;
+ return;
}
ath_tx_pause_tid(sc, txtid);
@@ -739,7 +748,7 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
}
list_move_tail(&bf->list, &bf_head);
ath_tx_update_baw(sc, txtid, bf->bf_seqno);
- ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
}
spin_unlock_bh(&txq->axq_lock);
@@ -747,11 +756,8 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
txtid->state |= AGGR_CLEANUP;
} else {
txtid->state &= ~AGGR_ADDBA_COMPLETE;
- txtid->addba_exchangeattempts = 0;
ath_tx_flush_tid(sc, txtid);
}
-
- return 0;
}
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
@@ -780,14 +786,8 @@ bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
txtid = ATH_AN_2_TID(an, tidno);
- if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
- if (!(txtid->state & AGGR_ADDBA_PROGRESS) &&
- (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) {
- txtid->addba_exchangeattempts++;
+ if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
return true;
- }
- }
-
return false;
}
@@ -870,14 +870,14 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
spin_lock_init(&txq->axq_lock);
txq->axq_depth = 0;
txq->axq_aggr_depth = 0;
- txq->axq_totalqueued = 0;
txq->axq_linkbuf = NULL;
+ txq->axq_tx_inprogress = false;
sc->tx.txqsetup |= 1<<qnum;
}
return &sc->tx.txq[qnum];
}
-static int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
+int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
{
int qnum;
@@ -1035,9 +1035,13 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
if (bf_isampdu(bf))
ath_tx_complete_aggr(sc, txq, bf, &bf_head, 0);
else
- ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
}
+ spin_lock_bh(&txq->axq_lock);
+ txq->axq_tx_inprogress = false;
+ spin_unlock_bh(&txq->axq_lock);
+
/* flush any pending frames if aggregation is enabled */
if (sc->sc_flags & SC_OP_TXAGGR) {
if (!retry_tx) {
@@ -1118,8 +1122,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
if (tid->paused)
continue;
- if ((txq->axq_depth % 2) == 0)
- ath_tx_sched_aggr(sc, txq, tid);
+ ath_tx_sched_aggr(sc, txq, tid);
/*
* add tid to round-robin queue if more frames
@@ -1183,7 +1186,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
list_splice_tail_init(head, &txq->axq_q);
txq->axq_depth++;
- txq->axq_totalqueued++;
txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
DPRINTF(sc, ATH_DBG_QUEUE,
@@ -1231,6 +1233,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
bf = list_first_entry(bf_head, struct ath_buf, list);
bf->bf_state.bf_type |= BUF_AMPDU;
+ TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
/*
* Do not queue to h/w when any of the following conditions is true:
@@ -1277,6 +1280,7 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_lastbf = bf;
ath_buf_set_rate(sc, bf);
ath_tx_txqaddbuf(sc, txq, bf_head);
+ TX_STAT_INC(txq->axq_qnum, queued);
}
static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
@@ -1290,6 +1294,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_nframes = 1;
ath_buf_set_rate(sc, bf);
ath_tx_txqaddbuf(sc, txq, bf_head);
+ TX_STAT_INC(txq->axq_qnum, queued);
}
static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
@@ -1636,7 +1641,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
goto tx_done;
}
- if (ath_aggr_query(sc, an, bf->bf_tidno)) {
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
/*
* Try aggregation if it's a unicast data frame
* and the destination is HT capable.
@@ -1815,6 +1820,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
}
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
+ struct ath_txq *txq,
struct list_head *bf_q,
int txok, int sendbar)
{
@@ -1822,7 +1828,6 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
unsigned long flags;
int tx_flags = 0;
-
if (sendbar)
tx_flags = ATH_TX_BAR;
@@ -1835,6 +1840,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
ath_tx_complete(sc, skb, tx_flags);
+ ath_debug_stat_tx(sc, txq, bf);
/*
* Return the list of ath_buf of this mpdu to free queue
@@ -1962,19 +1968,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
if (bf->bf_stale) {
bf_held = bf;
if (list_is_last(&bf_held->list, &txq->axq_q)) {
- txq->axq_link = NULL;
- txq->axq_linkbuf = NULL;
spin_unlock_bh(&txq->axq_lock);
-
- /*
- * The holding descriptor is the last
- * descriptor in queue. It's safe to remove
- * the last holding descriptor in BH context.
- */
- spin_lock_bh(&sc->tx.txbuflock);
- list_move_tail(&bf_held->list, &sc->tx.txbuf);
- spin_unlock_bh(&sc->tx.txbuflock);
-
break;
} else {
bf = list_entry(bf_held->list.next,
@@ -2011,6 +2005,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
txq->axq_aggr_depth--;
txok = (ds->ds_txstat.ts_status == 0);
+ txq->axq_tx_inprogress = false;
spin_unlock_bh(&txq->axq_lock);
if (bf_held) {
@@ -2033,7 +2028,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
if (bf_isampdu(bf))
ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok);
else
- ath_tx_complete_buf(sc, bf, &bf_head, txok, 0);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, txok, 0);
ath_wake_mac80211_queue(sc, txq);
@@ -2044,6 +2039,40 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
}
}
+static void ath_tx_complete_poll_work(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ tx_complete_work.work);
+ struct ath_txq *txq;
+ int i;
+ bool needreset = false;
+
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i)) {
+ txq = &sc->tx.txq[i];
+ spin_lock_bh(&txq->axq_lock);
+ if (txq->axq_depth) {
+ if (txq->axq_tx_inprogress) {
+ needreset = true;
+ spin_unlock_bh(&txq->axq_lock);
+ break;
+ } else {
+ txq->axq_tx_inprogress = true;
+ }
+ }
+ spin_unlock_bh(&txq->axq_lock);
+ }
+
+ if (needreset) {
+ DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n");
+ ath_reset(sc, false);
+ }
+
+ ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
+ msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
+}
+
+
void ath_tx_tasklet(struct ath_softc *sc)
{
@@ -2084,6 +2113,8 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
goto err;
}
+ INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
+
err:
if (error != 0)
ath_tx_cleanup(sc);
@@ -2122,7 +2153,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
tid->ac = &an->ac[acno];
tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_ADDBA_PROGRESS;
- tid->addba_exchangeattempts = 0;
}
for (acno = 0, ac = &an->ac[acno];
@@ -2179,7 +2209,6 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
tid->sched = false;
ath_tid_drain(sc, txq, tid);
tid->state &= ~AGGR_ADDBA_COMPLETE;
- tid->addba_exchangeattempts = 0;
tid->state &= ~AGGR_CLEANUP;
}
}
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 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include "ath.h"
+
MODULE_AUTHOR("Atheros Communications");
MODULE_DESCRIPTION("Shared library for Atheros wireless LAN cards.");
MODULE_LICENSE("Dual BSD/GPL");
+
+struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
+ u32 len,
+ gfp_t gfp_mask)
+{
+ struct sk_buff *skb;
+ u32 off;
+
+ /*
+ * Cache-line-align. This is important (for the
+ * 5210 at least) as not doing so causes bogus data
+ * in rx'd frames.
+ */
+
+ /* Note: the kernel can allocate a value greater than
+ * what we ask it to give us. We really only need 4 KB as that
+ * is this hardware supports and in fact we need at least 3849
+ * as that is the MAX AMSDU size this hardware supports.
+ * Unfortunately this means we may get 8 KB here from the
+ * kernel... and that is actually what is observed on some
+ * systems :( */
+ skb = __dev_alloc_skb(len + common->cachelsz - 1, gfp_mask);
+ if (skb != NULL) {
+ off = ((unsigned long) skb->data) % common->cachelsz;
+ if (off != 0)
+ skb_reserve(skb, common->cachelsz - off);
+ } else {
+ printk(KERN_ERR "skbuff alloc of size %u failed\n", len);
+ return NULL;
+ }
+
+ return skb;
+}
+EXPORT_SYMBOL(ath_rxbuf_alloc);
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index bf3d25ba7be1..077bcc142cde 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -586,7 +586,5 @@ u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
default:
return NO_CTL;
}
-
- return NO_CTL;
}
EXPORT_SYMBOL(ath_regd_get_band_ctl);
diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h
index 07291ccb23f2..c1dd857697a7 100644
--- a/drivers/net/wireless/ath/regd.h
+++ b/drivers/net/wireless/ath/regd.h
@@ -18,9 +18,16 @@
#define REGD_H
#include <linux/nl80211.h>
-
#include <net/cfg80211.h>
+#include "ath.h"
+
+enum ctl_group {
+ CTL_FCC = 0x10,
+ CTL_MKK = 0x40,
+ CTL_ETSI = 0x30,
+};
+
#define NO_CTL 0xff
#define SD_NO_CTL 0xE0
#define NO_CTL 0xff
@@ -47,29 +54,12 @@
#define CHANNEL_HALF_BW 10
#define CHANNEL_QUARTER_BW 5
-struct reg_dmn_pair_mapping {
- u16 regDmnEnum;
- u16 reg_5ghz_ctl;
- u16 reg_2ghz_ctl;
-};
-
struct country_code_to_enum_rd {
u16 countryCode;
u16 regDmnEnum;
const char *isoName;
};
-struct ath_regulatory {
- char alpha2[2];
- u16 country_code;
- u16 max_power_level;
- u32 tp_scale;
- u16 current_rd;
- u16 current_rd_ext;
- int16_t power_limit;
- struct reg_dmn_pair_mapping *regpair;
-};
-
enum CountryCode {
CTRY_ALBANIA = 8,
CTRY_ALGERIA = 12,
diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h
index 4d0e298cd1c7..9847af72208c 100644
--- a/drivers/net/wireless/ath/regd_common.h
+++ b/drivers/net/wireless/ath/regd_common.h
@@ -154,12 +154,6 @@ enum EnumRd {
DEBUG_REG_DMN = 0x01ff,
};
-enum ctl_group {
- CTL_FCC = 0x10,
- CTL_MKK = 0x40,
- CTL_ETSI = 0x30,
-};
-
/* Regpair to CTL band mapping */
static struct reg_dmn_pair_mapping regDomainPairs[] = {
/* regpair, 5 GHz CTL, 2 GHz CTL */
@@ -450,7 +444,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_SWITZERLAND, ETSI1_WORLD, "CH"},
{CTRY_SYRIA, NULL1_WORLD, "SY"},
{CTRY_TAIWAN, APL3_FCCA, "TW"},
- {CTRY_THAILAND, NULL1_WORLD, "TH"},
+ {CTRY_THAILAND, FCC3_WORLD, "TH"},
{CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"},
{CTRY_TUNISIA, ETSI3_WORLD, "TN"},
{CTRY_TURKEY, ETSI3_WORLD, "TR"},
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 291a94bd46fd..a3b36b3a9d67 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -781,7 +781,7 @@ static void tx_update_descriptor(struct atmel_private *priv, int is_bcast,
priv->tx_free_mem -= len;
}
-static int start_tx(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
{
static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
struct atmel_private *priv = netdev_priv(dev);
@@ -793,13 +793,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
!(*priv->present_callback)(priv->card)) {
dev->stats.tx_errors++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (priv->station_state != STATION_STATE_READY) {
dev->stats.tx_errors++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* first ensure the timer func cannot run */
@@ -856,7 +856,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
spin_unlock_bh(&priv->timerlock);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void atmel_transmit_management_frame(struct atmel_private *priv,
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 67f564e37225..83e38134accb 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -42,8 +42,8 @@ config B43_PCICORE_AUTOSELECT
default y
config B43_PCMCIA
- bool "Broadcom 43xx PCMCIA device support (EXPERIMENTAL)"
- depends on B43 && SSB_PCMCIAHOST_POSSIBLE && EXPERIMENTAL
+ bool "Broadcom 43xx PCMCIA device support"
+ depends on B43 && SSB_PCMCIAHOST_POSSIBLE
select SSB_PCMCIAHOST
---help---
Broadcom 43xx PCMCIA device support.
@@ -80,16 +80,14 @@ config B43_NPHY
SAY N.
config B43_PHY_LP
- bool "IEEE 802.11g LP-PHY support (BROKEN)"
- depends on B43 && EXPERIMENTAL && BROKEN
+ bool "Support for low-power (LP-PHY) devices (EXPERIMENTAL)"
+ depends on B43 && EXPERIMENTAL
+ default y
---help---
Support for the LP-PHY.
- The LP-PHY is an IEEE 802.11g based PHY built into some notebooks
- and embedded devices.
-
- THIS IS BROKEN AND DOES NOT WORK YET.
-
- SAY N.
+ The LP-PHY is a low-power PHY built into some notebooks
+ and embedded devices. It supports 802.11a/g
+ (802.11a support is optional, and currently disabled).
# This config option automatically enables b43 LEDS support,
# if it's possible.
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 40448067e4cc..09cfe68537b6 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -142,6 +142,17 @@
#define B43_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */
#define B43_BFL_ALTIQ 0x8000 /* alternate I/Q settings */
+/* SPROM boardflags_hi values */
+#define B43_BFH_NOPA 0x0001 /* has no PA */
+#define B43_BFH_RSSIINV 0x0002 /* RSSI uses positive slope (not TSSI) */
+#define B43_BFH_PAREF 0x0004 /* uses the PARef LDO */
+#define B43_BFH_3TSWITCH 0x0008 /* uses a triple throw switch shared
+ * with bluetooth */
+#define B43_BFH_PHASESHIFT 0x0010 /* can support phase shifter */
+#define B43_BFH_BUCKBOOST 0x0020 /* has buck/booster */
+#define B43_BFH_FEM_BT 0x0040 /* has FEM and switch to share antenna
+ * with bluetooth */
+
/* GPIO register offset, in both ChipCommon and PCI core. */
#define B43_GPIO_CONTROL 0x6c
@@ -482,6 +493,10 @@ enum {
/* Max size of a security key */
#define B43_SEC_KEYSIZE 16
+/* Max number of group keys */
+#define B43_NR_GROUP_KEYS 4
+/* Max number of pairwise keys */
+#define B43_NR_PAIRWISE_KEYS 50
/* Security algorithms. */
enum {
B43_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
@@ -601,6 +616,12 @@ struct b43_wl {
/* Pointer to the ieee80211 hardware data structure */
struct ieee80211_hw *hw;
+ /* Global driver mutex. Every operation must run with this mutex locked. */
+ struct mutex mutex;
+ /* Hard-IRQ spinlock. This lock protects things used in the hard-IRQ
+ * handler, only. This basically is just the IRQ mask register. */
+ spinlock_t hardirq_lock;
+
/* The number of queues that were registered with the mac80211 subsystem
* initially. This is a backup copy of hw->queues in case hw->queues has
* to be dynamically lowered at runtime (Firmware does not support QoS).
@@ -608,16 +629,12 @@ struct b43_wl {
* from the mac80211 subsystem. */
u16 mac80211_initially_registered_queues;
- struct mutex mutex;
- spinlock_t irq_lock;
/* R/W lock for data transmission.
* Transmissions on 2+ queues can run concurrently, but somebody else
* might sync with TX by write_lock_irqsave()'ing. */
rwlock_t tx_lock;
/* Lock for LEDs access. */
spinlock_t leds_lock;
- /* Lock for SHM access. */
- spinlock_t shm_lock;
/* We can only have one operating interface (802.11 core)
* at a time. General information about this interface follows.
@@ -628,7 +645,7 @@ struct b43_wl {
u8 mac_addr[ETH_ALEN];
/* Current BSSID */
u8 bssid[ETH_ALEN];
- /* Interface type. (IEEE80211_IF_TYPE_XXX) */
+ /* Interface type. (NL80211_IFTYPE_XXX) */
int if_type;
/* Is the card operating in AP, STA or IBSS mode? */
bool operating;
@@ -650,8 +667,7 @@ struct b43_wl {
bool radiotap_enabled;
bool radio_enabled;
- /* The beacon we are currently using (AP or IBSS mode).
- * This beacon stuff is protected by the irq_lock. */
+ /* The beacon we are currently using (AP or IBSS mode). */
struct sk_buff *current_beacon;
bool beacon0_uploaded;
bool beacon1_uploaded;
@@ -665,6 +681,11 @@ struct b43_wl {
* This is scheduled when we determine that the actual TX output
* power doesn't match what we want. */
struct work_struct txpower_adjust_work;
+
+ /* Packet transmit work */
+ struct work_struct tx_work;
+ /* Queue of packets to be transmitted. */
+ struct sk_buff_head tx_queue;
};
/* The type of the firmware file. */
@@ -739,14 +760,6 @@ enum {
smp_wmb(); \
} while (0)
-/* XXX--- HOW LOCKING WORKS IN B43 ---XXX
- *
- * You should always acquire both, wl->mutex and wl->irq_lock unless:
- * - You don't need to acquire wl->irq_lock, if the interface is stopped.
- * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet
- * and packet TX path (and _ONLY_ there.)
- */
-
/* Data structure for one wireless device (802.11 core) */
struct b43_wldev {
struct ssb_device *dev;
@@ -792,14 +805,12 @@ struct b43_wldev {
u32 dma_reason[6];
/* The currently active generic-interrupt mask. */
u32 irq_mask;
+
/* Link Quality calculation context. */
struct b43_noise_calculation noisecalc;
/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
int mac_suspended;
- /* Interrupt Service Routine tasklet (bottom-half) */
- struct tasklet_struct isr_tasklet;
-
/* Periodic tasks */
struct delayed_work periodic_work;
unsigned int periodic_state;
@@ -808,8 +819,7 @@ struct b43_wldev {
/* encryption/decryption */
u16 ktp; /* Key table pointer */
- u8 max_nr_keys;
- struct b43_key key[58];
+ struct b43_key key[B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS];
/* Firmware data */
struct b43_firmware fw;
@@ -834,7 +844,7 @@ static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev)
return ssb_get_drvdata(ssb_dev);
}
-/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */
+/* Is the device operating in a specified mode (NL80211_IFTYPE_XXX). */
static inline int b43_is_mode(struct b43_wl *wl, int type)
{
return (wl->operating && wl->if_type == type);
diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c
index 45e3d6af69f5..8f64943e3f60 100644
--- a/drivers/net/wireless/b43/debugfs.c
+++ b/drivers/net/wireless/b43/debugfs.c
@@ -46,8 +46,6 @@ struct b43_debugfs_fops {
struct file_operations fops;
/* Offset of struct b43_dfs_file in struct b43_dfsentry */
size_t file_struct_offset;
- /* Take wl->irq_lock before calling read/write? */
- bool take_irqlock;
};
static inline
@@ -127,7 +125,6 @@ static int shm16write__write_file(struct b43_wldev *dev,
unsigned int routing, addr, mask, set;
u16 val;
int res;
- unsigned long flags;
res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
&routing, &addr, &mask, &set);
@@ -144,15 +141,13 @@ static int shm16write__write_file(struct b43_wldev *dev,
if ((mask > 0xFFFF) || (set > 0xFFFF))
return -E2BIG;
- spin_lock_irqsave(&dev->wl->shm_lock, flags);
if (mask == 0)
val = 0;
else
- val = __b43_shm_read16(dev, routing, addr);
+ val = b43_shm_read16(dev, routing, addr);
val &= mask;
val |= set;
- __b43_shm_write16(dev, routing, addr, val);
- spin_unlock_irqrestore(&dev->wl->shm_lock, flags);
+ b43_shm_write16(dev, routing, addr, val);
return 0;
}
@@ -206,7 +201,6 @@ static int shm32write__write_file(struct b43_wldev *dev,
unsigned int routing, addr, mask, set;
u32 val;
int res;
- unsigned long flags;
res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
&routing, &addr, &mask, &set);
@@ -223,15 +217,13 @@ static int shm32write__write_file(struct b43_wldev *dev,
if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
return -E2BIG;
- spin_lock_irqsave(&dev->wl->shm_lock, flags);
if (mask == 0)
val = 0;
else
- val = __b43_shm_read32(dev, routing, addr);
+ val = b43_shm_read32(dev, routing, addr);
val &= mask;
val |= set;
- __b43_shm_write32(dev, routing, addr, val);
- spin_unlock_irqrestore(&dev->wl->shm_lock, flags);
+ b43_shm_write32(dev, routing, addr, val);
return 0;
}
@@ -372,14 +364,12 @@ static ssize_t txstat_read_file(struct b43_wldev *dev,
{
struct b43_txstatus_log *log = &dev->dfsentry->txstatlog;
ssize_t count = 0;
- unsigned long flags;
int i, idx;
struct b43_txstatus *stat;
- spin_lock_irqsave(&log->lock, flags);
if (log->end < 0) {
fappend("Nothing transmitted, yet\n");
- goto out_unlock;
+ goto out;
}
fappend("b43 TX status reports:\n\n"
"index | cookie | seq | phy_stat | frame_count | "
@@ -409,13 +399,11 @@ static ssize_t txstat_read_file(struct b43_wldev *dev,
break;
i++;
}
-out_unlock:
- spin_unlock_irqrestore(&log->lock, flags);
+out:
return count;
}
-/* wl->irq_lock is locked */
static int restart_write_file(struct b43_wldev *dev,
const char *buf, size_t count)
{
@@ -556,12 +544,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
goto out_unlock;
}
memset(buf, 0, bufsize);
- if (dfops->take_irqlock) {
- spin_lock_irq(&dev->wl->irq_lock);
- ret = dfops->read(dev, buf, bufsize);
- spin_unlock_irq(&dev->wl->irq_lock);
- } else
- ret = dfops->read(dev, buf, bufsize);
+ ret = dfops->read(dev, buf, bufsize);
if (ret <= 0) {
free_pages((unsigned long)buf, buforder);
err = ret;
@@ -623,12 +606,7 @@ static ssize_t b43_debugfs_write(struct file *file,
err = -EFAULT;
goto out_freepage;
}
- if (dfops->take_irqlock) {
- spin_lock_irq(&dev->wl->irq_lock);
- err = dfops->write(dev, buf, count);
- spin_unlock_irq(&dev->wl->irq_lock);
- } else
- err = dfops->write(dev, buf, count);
+ err = dfops->write(dev, buf, count);
if (err)
goto out_freepage;
@@ -641,7 +619,7 @@ out_unlock:
}
-#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \
+#define B43_DEBUGFS_FOPS(name, _read, _write) \
static struct b43_debugfs_fops fops_##name = { \
.read = _read, \
.write = _write, \
@@ -652,20 +630,19 @@ out_unlock:
}, \
.file_struct_offset = offsetof(struct b43_dfsentry, \
file_##name), \
- .take_irqlock = _take_irqlock, \
}
-B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file, 1);
-B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file, 1);
-B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file, 1);
-B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file, 1);
-B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file, 1);
-B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file, 1);
-B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1);
-B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1);
-B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
-B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
-B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0);
+B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file);
+B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file);
+B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file);
+B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file);
+B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file);
+B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file);
+B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file);
+B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file);
+B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL);
+B43_DEBUGFS_FOPS(restart, NULL, restart_write_file);
+B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL);
bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
@@ -738,7 +715,6 @@ void b43_debugfs_add_device(struct b43_wldev *dev)
return;
}
log->end = -1;
- spin_lock_init(&log->lock);
dev->dfsentry = e;
@@ -822,7 +798,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev)
kfree(e);
}
-/* Called with IRQs disabled. */
void b43_debugfs_log_txstat(struct b43_wldev *dev,
const struct b43_txstatus *status)
{
@@ -834,14 +809,12 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev,
if (!e)
return;
log = &e->txstatlog;
- spin_lock(&log->lock); /* IRQs are already disabled. */
i = log->end + 1;
if (i == B43_NR_LOGGED_TXSTATUS)
i = 0;
log->end = i;
cur = &(log->log[i]);
memcpy(cur, status, sizeof(*cur));
- spin_unlock(&log->lock);
}
void b43_debugfs_init(void)
diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h
index b9d4de4a979c..e47b4b488b04 100644
--- a/drivers/net/wireless/b43/debugfs.h
+++ b/drivers/net/wireless/b43/debugfs.h
@@ -23,9 +23,10 @@ struct dentry;
#define B43_NR_LOGGED_TXSTATUS 100
struct b43_txstatus_log {
+ /* This structure is protected by wl->mutex */
+
struct b43_txstatus *log;
int end;
- spinlock_t lock;
};
struct b43_dfs_file {
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 7964cc32b258..a467ee260a19 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -856,7 +856,6 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
} else
B43_WARN_ON(1);
}
- spin_lock_init(&ring->lock);
#ifdef CONFIG_B43_DEBUG
ring->last_injected_overflow = jiffies;
#endif
@@ -1188,7 +1187,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
header = &(ring->txhdr_cache[(slot / TX_SLOTS_PER_FRAME) * hdrsize]);
cookie = generate_cookie(ring, slot);
err = b43_generate_txhdr(ring->dev, header,
- skb->data, skb->len, info, cookie);
+ skb, info, cookie);
if (unlikely(err)) {
ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots;
@@ -1315,7 +1314,6 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
struct b43_dmaring *ring;
struct ieee80211_hdr *hdr;
int err = 0;
- unsigned long flags;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
hdr = (struct ieee80211_hdr *)skb->data;
@@ -1331,18 +1329,25 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
dev, skb_get_queue_mapping(skb));
}
- spin_lock_irqsave(&ring->lock, flags);
-
B43_WARN_ON(!ring->tx);
- /* Check if the queue was stopped in mac80211,
- * but we got called nevertheless.
- * That would be a mac80211 bug. */
- B43_WARN_ON(ring->stopped);
- if (unlikely(free_slots(ring) < TX_SLOTS_PER_FRAME)) {
- b43warn(dev->wl, "DMA queue overflow\n");
+ if (unlikely(ring->stopped)) {
+ /* We get here only because of a bug in mac80211.
+ * Because of a race, one packet may be queued after
+ * the queue is stopped, thus we got called when we shouldn't.
+ * For now, just refuse the transmit. */
+ if (b43_debug(dev, B43_DBG_DMAVERBOSE))
+ b43err(dev->wl, "Packet after queue stopped\n");
err = -ENOSPC;
- goto out_unlock;
+ goto out;
+ }
+
+ if (unlikely(WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME))) {
+ /* If we get here, we have a real error with the queue
+ * full, but queues not stopped. */
+ b43err(dev->wl, "DMA queue overflow\n");
+ err = -ENOSPC;
+ goto out;
}
/* Assign the queue number to the ring (if not already done before)
@@ -1356,11 +1361,11 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
* anymore and must not transmit it unencrypted. */
dev_kfree_skb_any(skb);
err = 0;
- goto out_unlock;
+ goto out;
}
if (unlikely(err)) {
b43err(dev->wl, "DMA tx mapping failure\n");
- goto out_unlock;
+ goto out;
}
ring->nr_tx_packets++;
if ((free_slots(ring) < TX_SLOTS_PER_FRAME) ||
@@ -1372,13 +1377,11 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
}
}
-out_unlock:
- spin_unlock_irqrestore(&ring->lock, flags);
+out:
return err;
}
-/* Called with IRQs disabled. */
void b43_dma_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status)
{
@@ -1393,8 +1396,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
if (unlikely(!ring))
return;
- spin_lock(&ring->lock); /* IRQs are already disabled. */
-
B43_WARN_ON(!ring->tx);
ops = ring->ops;
while (1) {
@@ -1453,8 +1454,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index);
}
}
-
- spin_unlock(&ring->lock);
}
void b43_dma_get_tx_stats(struct b43_wldev *dev,
@@ -1462,17 +1461,14 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev,
{
const int nr_queues = dev->wl->hw->queues;
struct b43_dmaring *ring;
- unsigned long flags;
int i;
for (i = 0; i < nr_queues; i++) {
ring = select_ring_by_priority(dev, i);
- spin_lock_irqsave(&ring->lock, flags);
stats[i].len = ring->used_slots / TX_SLOTS_PER_FRAME;
stats[i].limit = ring->nr_slots / TX_SLOTS_PER_FRAME;
stats[i].count = ring->nr_tx_packets;
- spin_unlock_irqrestore(&ring->lock, flags);
}
}
@@ -1583,22 +1579,14 @@ void b43_dma_rx(struct b43_dmaring *ring)
static void b43_dma_tx_suspend_ring(struct b43_dmaring *ring)
{
- unsigned long flags;
-
- spin_lock_irqsave(&ring->lock, flags);
B43_WARN_ON(!ring->tx);
ring->ops->tx_suspend(ring);
- spin_unlock_irqrestore(&ring->lock, flags);
}
static void b43_dma_tx_resume_ring(struct b43_dmaring *ring)
{
- unsigned long flags;
-
- spin_lock_irqsave(&ring->lock, flags);
B43_WARN_ON(!ring->tx);
ring->ops->tx_resume(ring);
- spin_unlock_irqrestore(&ring->lock, flags);
}
void b43_dma_tx_suspend(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index 05dde646d831..f0b0838fb5ba 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -2,7 +2,6 @@
#define B43_DMA_H_
#include <linux/ieee80211.h>
-#include <linux/spinlock.h>
#include "b43.h"
@@ -244,8 +243,6 @@ struct b43_dmaring {
/* The QOS priority assigned to this ring. Only used for TX rings.
* This is the mac80211 "queue" value. */
u8 queue_prio;
- /* Lock, only used for TX. */
- spinlock_t lock;
struct b43_wldev *dev;
#ifdef CONFIG_B43_DEBUG
/* Maximum number of used slots. */
diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c
index 22d0fbd83a62..976104f634a1 100644
--- a/drivers/net/wireless/b43/lo.c
+++ b/drivers/net/wireless/b43/lo.c
@@ -477,7 +477,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
} else
b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802);
if (phy->rev >= 2)
- b43_dummy_transmission(dev);
+ b43_dummy_transmission(dev, false, true);
b43_gphy_channel_switch(dev, 6, 0);
b43_radio_read16(dev, 0x51); /* dummy read */
if (phy->type == B43_PHYTYPE_G)
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index e71c8d9cd706..7a9a3fa55425 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -58,6 +58,7 @@ MODULE_DESCRIPTION("Broadcom B43 wireless driver");
MODULE_AUTHOR("Martin Langer");
MODULE_AUTHOR("Stefano Brivio");
MODULE_AUTHOR("Michael Buesch");
+MODULE_AUTHOR("Gábor Stefanik");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID);
@@ -80,13 +81,17 @@ static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+static int modparam_hwtkip;
+module_param_named(hwtkip, modparam_hwtkip, int, 0444);
+MODULE_PARM_DESC(hwtkip, "Enable hardware tkip.");
+
static int modparam_qos = 1;
module_param_named(qos, modparam_qos, int, 0444);
MODULE_PARM_DESC(qos, "Enable QOS support (default on)");
static int modparam_btcoex = 1;
module_param_named(btcoex, modparam_btcoex, int, 0444);
-MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistance (default on)");
+MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistence (default on)");
int b43_modparam_verbose = B43_VERBOSITY_DEFAULT;
module_param_named(verbose, b43_modparam_verbose, int, 0644);
@@ -286,7 +291,7 @@ static struct ieee80211_supported_band b43_band_2GHz = {
static void b43_wireless_core_exit(struct b43_wldev *dev);
static int b43_wireless_core_init(struct b43_wldev *dev);
-static void b43_wireless_core_stop(struct b43_wldev *dev);
+static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev);
static int b43_wireless_core_start(struct b43_wldev *dev);
static int b43_ratelimit(struct b43_wl *wl)
@@ -385,7 +390,7 @@ static inline void b43_shm_control_word(struct b43_wldev *dev,
b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
}
-u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
+u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
{
u32 ret;
@@ -395,9 +400,8 @@ u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
/* Unaligned access */
b43_shm_control_word(dev, routing, offset >> 2);
ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
- ret <<= 16;
b43_shm_control_word(dev, routing, (offset >> 2) + 1);
- ret |= b43_read16(dev, B43_MMIO_SHM_DATA);
+ ret |= ((u32)b43_read16(dev, B43_MMIO_SHM_DATA)) << 16;
goto out;
}
@@ -409,20 +413,7 @@ out:
return ret;
}
-u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
-{
- struct b43_wl *wl = dev->wl;
- unsigned long flags;
- u32 ret;
-
- spin_lock_irqsave(&wl->shm_lock, flags);
- ret = __b43_shm_read32(dev, routing, offset);
- spin_unlock_irqrestore(&wl->shm_lock, flags);
-
- return ret;
-}
-
-u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
+u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
{
u16 ret;
@@ -443,20 +434,7 @@ out:
return ret;
}
-u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
-{
- struct b43_wl *wl = dev->wl;
- unsigned long flags;
- u16 ret;
-
- spin_lock_irqsave(&wl->shm_lock, flags);
- ret = __b43_shm_read16(dev, routing, offset);
- spin_unlock_irqrestore(&wl->shm_lock, flags);
-
- return ret;
-}
-
-void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
+void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
{
if (routing == B43_SHM_SHARED) {
B43_WARN_ON(offset & 0x0001);
@@ -464,9 +442,10 @@ void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value
/* Unaligned access */
b43_shm_control_word(dev, routing, offset >> 2);
b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
- (value >> 16) & 0xffff);
+ value & 0xFFFF);
b43_shm_control_word(dev, routing, (offset >> 2) + 1);
- b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
+ b43_write16(dev, B43_MMIO_SHM_DATA,
+ (value >> 16) & 0xFFFF);
return;
}
offset >>= 2;
@@ -475,17 +454,7 @@ void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value
b43_write32(dev, B43_MMIO_SHM_DATA, value);
}
-void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
-{
- struct b43_wl *wl = dev->wl;
- unsigned long flags;
-
- spin_lock_irqsave(&wl->shm_lock, flags);
- __b43_shm_write32(dev, routing, offset, value);
- spin_unlock_irqrestore(&wl->shm_lock, flags);
-}
-
-void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
+void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
{
if (routing == B43_SHM_SHARED) {
B43_WARN_ON(offset & 0x0001);
@@ -501,16 +470,6 @@ void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value
b43_write16(dev, B43_MMIO_SHM_DATA, value);
}
-void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
-{
- struct b43_wl *wl = dev->wl;
- unsigned long flags;
-
- spin_lock_irqsave(&wl->shm_lock, flags);
- __b43_shm_write16(dev, routing, offset, value);
- spin_unlock_irqrestore(&wl->shm_lock, flags);
-}
-
/* Read HostFlags */
u64 b43_hf_read(struct b43_wldev *dev)
{
@@ -680,22 +639,11 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev)
b43_set_slot_time(dev, 20);
}
-/* Synchronize IRQ top- and bottom-half.
- * IRQs must be masked before calling this.
- * This must not be called with the irq_lock held.
- */
-static void b43_synchronize_irq(struct b43_wldev *dev)
-{
- synchronize_irq(dev->dev->irq);
- tasklet_kill(&dev->isr_tasklet);
-}
-
/* DummyTransmission function, as documented on
- * http://bcm-specs.sipsolutions.net/DummyTransmission
+ * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission
*/
-void b43_dummy_transmission(struct b43_wldev *dev)
+void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
{
- struct b43_wl *wl = dev->wl;
struct b43_phy *phy = &dev->phy;
unsigned int i, max_loop;
u16 value;
@@ -707,41 +655,46 @@ void b43_dummy_transmission(struct b43_wldev *dev)
0x00000000,
};
- switch (phy->type) {
- case B43_PHYTYPE_A:
+ if (ofdm) {
max_loop = 0x1E;
buffer[0] = 0x000201CC;
- break;
- case B43_PHYTYPE_B:
- case B43_PHYTYPE_G:
+ } else {
max_loop = 0xFA;
buffer[0] = 0x000B846E;
- break;
- default:
- B43_WARN_ON(1);
- return;
}
- spin_lock_irq(&wl->irq_lock);
- write_lock(&wl->tx_lock);
-
for (i = 0; i < 5; i++)
b43_ram_write(dev, i * 4, buffer[i]);
- /* Commit writes */
- b43_read32(dev, B43_MMIO_MACCTL);
-
b43_write16(dev, 0x0568, 0x0000);
- b43_write16(dev, 0x07C0, 0x0000);
- value = ((phy->type == B43_PHYTYPE_A) ? 1 : 0);
+ if (dev->dev->id.revision < 11)
+ b43_write16(dev, 0x07C0, 0x0000);
+ else
+ b43_write16(dev, 0x07C0, 0x0100);
+ value = (ofdm ? 0x41 : 0x40);
b43_write16(dev, 0x050C, value);
+ if ((phy->type == B43_PHYTYPE_N) || (phy->type == B43_PHYTYPE_LP))
+ b43_write16(dev, 0x0514, 0x1A02);
b43_write16(dev, 0x0508, 0x0000);
b43_write16(dev, 0x050A, 0x0000);
b43_write16(dev, 0x054C, 0x0000);
b43_write16(dev, 0x056A, 0x0014);
b43_write16(dev, 0x0568, 0x0826);
b43_write16(dev, 0x0500, 0x0000);
- b43_write16(dev, 0x0502, 0x0030);
+ if (!pa_on && (phy->type == B43_PHYTYPE_N)) {
+ //SPEC TODO
+ }
+
+ switch (phy->type) {
+ case B43_PHYTYPE_N:
+ b43_write16(dev, 0x0502, 0x00D0);
+ break;
+ case B43_PHYTYPE_LP:
+ b43_write16(dev, 0x0502, 0x0050);
+ break;
+ default:
+ b43_write16(dev, 0x0502, 0x0030);
+ }
if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
b43_radio_write16(dev, 0x0051, 0x0017);
@@ -765,9 +718,6 @@ void b43_dummy_transmission(struct b43_wldev *dev)
}
if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
b43_radio_write16(dev, 0x0051, 0x0037);
-
- write_unlock(&wl->tx_lock);
- spin_unlock_irq(&wl->irq_lock);
}
static void key_write(struct b43_wldev *dev,
@@ -796,18 +746,19 @@ static void key_write(struct b43_wldev *dev,
static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr)
{
u32 addrtmp[2] = { 0, 0, };
- u8 per_sta_keys_start = 8;
+ u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
if (b43_new_kidx_api(dev))
- per_sta_keys_start = 4;
+ pairwise_keys_start = B43_NR_GROUP_KEYS;
- B43_WARN_ON(index < per_sta_keys_start);
- /* We have two default TX keys and possibly two default RX keys.
+ B43_WARN_ON(index < pairwise_keys_start);
+ /* We have four default TX keys and possibly four default RX keys.
* Physical mac 0 is mapped to physical key 4 or 8, depending
* on the firmware version.
* So we must adjust the index here.
*/
- index -= per_sta_keys_start;
+ index -= pairwise_keys_start;
+ B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS);
if (addr) {
addrtmp[0] = addr[0];
@@ -818,27 +769,90 @@ static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr)
addrtmp[1] |= ((u32) (addr[5]) << 8);
}
- if (dev->dev->id.revision >= 5) {
- /* Receive match transmitter address mechanism */
- b43_shm_write32(dev, B43_SHM_RCMTA,
- (index * 2) + 0, addrtmp[0]);
- b43_shm_write16(dev, B43_SHM_RCMTA,
- (index * 2) + 1, addrtmp[1]);
- } else {
- /* RXE (Receive Engine) and
- * PSM (Programmable State Machine) mechanism
- */
- if (index < 8) {
- /* TODO write to RCM 16, 19, 22 and 25 */
- } else {
- b43_shm_write32(dev, B43_SHM_SHARED,
- B43_SHM_SH_PSM + (index * 6) + 0,
- addrtmp[0]);
- b43_shm_write16(dev, B43_SHM_SHARED,
- B43_SHM_SH_PSM + (index * 6) + 4,
- addrtmp[1]);
- }
+ /* Receive match transmitter address (RCMTA) mechanism */
+ b43_shm_write32(dev, B43_SHM_RCMTA,
+ (index * 2) + 0, addrtmp[0]);
+ b43_shm_write16(dev, B43_SHM_RCMTA,
+ (index * 2) + 1, addrtmp[1]);
+}
+
+/* The ucode will use phase1 key with TEK key to decrypt rx packets.
+ * When a packet is received, the iv32 is checked.
+ * - if it doesn't the packet is returned without modification (and software
+ * decryption can be done). That's what happen when iv16 wrap.
+ * - if it does, the rc4 key is computed, and decryption is tried.
+ * Either it will success and B43_RX_MAC_DEC is returned,
+ * either it fails and B43_RX_MAC_DEC|B43_RX_MAC_DECERR is returned
+ * and the packet is not usable (it got modified by the ucode).
+ * So in order to never have B43_RX_MAC_DECERR, we should provide
+ * a iv32 and phase1key that match. Because we drop packets in case of
+ * B43_RX_MAC_DECERR, if we have a correct iv32 but a wrong phase1key, all
+ * packets will be lost without higher layer knowing (ie no resync possible
+ * until next wrap).
+ *
+ * NOTE : this should support 50 key like RCMTA because
+ * (B43_SHM_SH_KEYIDXBLOCK - B43_SHM_SH_TKIPTSCTTAK)/14 = 50
+ */
+static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32,
+ u16 *phase1key)
+{
+ unsigned int i;
+ u32 offset;
+ u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
+
+ if (!modparam_hwtkip)
+ return;
+
+ if (b43_new_kidx_api(dev))
+ pairwise_keys_start = B43_NR_GROUP_KEYS;
+
+ B43_WARN_ON(index < pairwise_keys_start);
+ /* We have four default TX keys and possibly four default RX keys.
+ * Physical mac 0 is mapped to physical key 4 or 8, depending
+ * on the firmware version.
+ * So we must adjust the index here.
+ */
+ index -= pairwise_keys_start;
+ B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS);
+
+ if (b43_debug(dev, B43_DBG_KEYS)) {
+ b43dbg(dev->wl, "rx_tkip_phase1_write : idx 0x%x, iv32 0x%x\n",
+ index, iv32);
}
+ /* Write the key to the RX tkip shared mem */
+ offset = B43_SHM_SH_TKIPTSCTTAK + index * (10 + 4);
+ for (i = 0; i < 10; i += 2) {
+ b43_shm_write16(dev, B43_SHM_SHARED, offset + i,
+ phase1key ? phase1key[i / 2] : 0);
+ }
+ b43_shm_write16(dev, B43_SHM_SHARED, offset + i, iv32);
+ b43_shm_write16(dev, B43_SHM_SHARED, offset + i + 2, iv32 >> 16);
+}
+
+static void b43_op_update_tkip_key(struct ieee80211_hw *hw,
+ struct ieee80211_key_conf *keyconf, const u8 *addr,
+ u32 iv32, u16 *phase1key)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev;
+ int index = keyconf->hw_key_idx;
+
+ if (B43_WARN_ON(!modparam_hwtkip))
+ return;
+
+ mutex_lock(&wl->mutex);
+
+ dev = wl->current_dev;
+ if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
+ goto out_unlock;
+
+ keymac_write(dev, index, NULL); /* First zero out mac to avoid race */
+
+ rx_tkip_phase1_write(dev, index, iv32, phase1key);
+ keymac_write(dev, index, addr);
+
+out_unlock:
+ mutex_unlock(&wl->mutex);
}
static void do_key_write(struct b43_wldev *dev,
@@ -846,20 +860,33 @@ static void do_key_write(struct b43_wldev *dev,
const u8 *key, size_t key_len, const u8 *mac_addr)
{
u8 buf[B43_SEC_KEYSIZE] = { 0, };
- u8 per_sta_keys_start = 8;
+ u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
if (b43_new_kidx_api(dev))
- per_sta_keys_start = 4;
+ pairwise_keys_start = B43_NR_GROUP_KEYS;
- B43_WARN_ON(index >= dev->max_nr_keys);
+ B43_WARN_ON(index >= ARRAY_SIZE(dev->key));
B43_WARN_ON(key_len > B43_SEC_KEYSIZE);
- if (index >= per_sta_keys_start)
+ if (index >= pairwise_keys_start)
keymac_write(dev, index, NULL); /* First zero out mac. */
+ if (algorithm == B43_SEC_ALGO_TKIP) {
+ /*
+ * We should provide an initial iv32, phase1key pair.
+ * We could start with iv32=0 and compute the corresponding
+ * phase1key, but this means calling ieee80211_get_tkip_key
+ * with a fake skb (or export other tkip function).
+ * Because we are lazy we hope iv32 won't start with
+ * 0xffffffff and let's b43_op_update_tkip_key provide a
+ * correct pair.
+ */
+ rx_tkip_phase1_write(dev, index, 0xffffffff, (u16*)buf);
+ } else if (index >= pairwise_keys_start) /* clear it */
+ rx_tkip_phase1_write(dev, index, 0, NULL);
if (key)
memcpy(buf, key, key_len);
key_write(dev, index, algorithm, buf);
- if (index >= per_sta_keys_start)
+ if (index >= pairwise_keys_start)
keymac_write(dev, index, mac_addr);
dev->key[index].algorithm = algorithm;
@@ -872,21 +899,33 @@ static int b43_key_write(struct b43_wldev *dev,
struct ieee80211_key_conf *keyconf)
{
int i;
- int sta_keys_start;
-
+ int pairwise_keys_start;
+
+ /* For ALG_TKIP the key is encoded as a 256-bit (32 byte) data block:
+ * - Temporal Encryption Key (128 bits)
+ * - Temporal Authenticator Tx MIC Key (64 bits)
+ * - Temporal Authenticator Rx MIC Key (64 bits)
+ *
+ * Hardware only store TEK
+ */
+ if (algorithm == B43_SEC_ALGO_TKIP && key_len == 32)
+ key_len = 16;
if (key_len > B43_SEC_KEYSIZE)
return -EINVAL;
- for (i = 0; i < dev->max_nr_keys; i++) {
+ for (i = 0; i < ARRAY_SIZE(dev->key); i++) {
/* Check that we don't already have this key. */
B43_WARN_ON(dev->key[i].keyconf == keyconf);
}
if (index < 0) {
/* Pairwise key. Get an empty slot for the key. */
if (b43_new_kidx_api(dev))
- sta_keys_start = 4;
+ pairwise_keys_start = B43_NR_GROUP_KEYS;
else
- sta_keys_start = 8;
- for (i = sta_keys_start; i < dev->max_nr_keys; i++) {
+ pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
+ for (i = pairwise_keys_start;
+ i < pairwise_keys_start + B43_NR_PAIRWISE_KEYS;
+ i++) {
+ B43_WARN_ON(i >= ARRAY_SIZE(dev->key));
if (!dev->key[i].keyconf) {
/* found empty */
index = i;
@@ -914,7 +953,7 @@ static int b43_key_write(struct b43_wldev *dev,
static int b43_key_clear(struct b43_wldev *dev, int index)
{
- if (B43_WARN_ON((index < 0) || (index >= dev->max_nr_keys)))
+ if (B43_WARN_ON((index < 0) || (index >= ARRAY_SIZE(dev->key))))
return -EINVAL;
do_key_write(dev, index, B43_SEC_ALGO_NONE,
NULL, B43_SEC_KEYSIZE, NULL);
@@ -929,16 +968,19 @@ static int b43_key_clear(struct b43_wldev *dev, int index)
static void b43_clear_keys(struct b43_wldev *dev)
{
- int i;
+ int i, count;
- for (i = 0; i < dev->max_nr_keys; i++)
+ if (b43_new_kidx_api(dev))
+ count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS;
+ else
+ count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS;
+ for (i = 0; i < count; i++)
b43_key_clear(dev, i);
}
static void b43_dump_keymemory(struct b43_wldev *dev)
{
- unsigned int i, index, offset;
- DECLARE_MAC_BUF(macbuf);
+ unsigned int i, index, count, offset, pairwise_keys_start;
u8 mac[ETH_ALEN];
u16 algo;
u32 rcmta0;
@@ -952,7 +994,14 @@ static void b43_dump_keymemory(struct b43_wldev *dev)
hf = b43_hf_read(dev);
b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n",
!!(hf & B43_HF_USEDEFKEYS));
- for (index = 0; index < dev->max_nr_keys; index++) {
+ if (b43_new_kidx_api(dev)) {
+ pairwise_keys_start = B43_NR_GROUP_KEYS;
+ count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS;
+ } else {
+ pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
+ count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS;
+ }
+ for (index = 0; index < count; index++) {
key = &(dev->key[index]);
printk(KERN_DEBUG "Key slot %02u: %s",
index, (key->keyconf == NULL) ? " " : "*");
@@ -966,15 +1015,22 @@ static void b43_dump_keymemory(struct b43_wldev *dev)
B43_SHM_SH_KEYIDXBLOCK + (index * 2));
printk(" Algo: %04X/%02X", algo, key->algorithm);
- if (index >= 4) {
+ if (index >= pairwise_keys_start) {
+ if (key->algorithm == B43_SEC_ALGO_TKIP) {
+ printk(" TKIP: ");
+ offset = B43_SHM_SH_TKIPTSCTTAK + (index - 4) * (10 + 4);
+ for (i = 0; i < 14; i += 2) {
+ u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
+ printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
+ }
+ }
rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA,
- ((index - 4) * 2) + 0);
+ ((index - pairwise_keys_start) * 2) + 0);
rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA,
- ((index - 4) * 2) + 1);
+ ((index - pairwise_keys_start) * 2) + 1);
*((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
*((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
- printk(" MAC: %s",
- print_mac(macbuf, mac));
+ printk(" MAC: %pM", mac);
} else
printk(" DEFAULT KEY");
printk("\n");
@@ -1338,7 +1394,8 @@ static u16 b43_antenna_to_phyctl(int antenna)
return B43_TXH_PHY_ANT2;
case B43_ANTENNA3:
return B43_TXH_PHY_ANT3;
- case B43_ANTENNA_AUTO:
+ case B43_ANTENNA_AUTO0:
+ case B43_ANTENNA_AUTO1:
return B43_TXH_PHY_ANT01AUTO;
}
B43_WARN_ON(1);
@@ -1431,113 +1488,6 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset);
}
-static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
- u16 shm_offset, u16 size,
- struct ieee80211_rate *rate)
-{
- struct b43_plcp_hdr4 plcp;
- u32 tmp;
- __le16 dur;
-
- plcp.data = 0;
- b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value);
- dur = ieee80211_generic_frame_duration(dev->wl->hw,
- dev->wl->vif, size,
- rate);
- /* Write PLCP in two parts and timing for packet transfer */
- tmp = le32_to_cpu(plcp.data);
- b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF);
- b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 2, tmp >> 16);
- b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 6, le16_to_cpu(dur));
-}
-
-/* Instead of using custom probe response template, this function
- * just patches custom beacon template by:
- * 1) Changing packet type
- * 2) Patching duration field
- * 3) Stripping TIM
- */
-static const u8 *b43_generate_probe_resp(struct b43_wldev *dev,
- u16 *dest_size,
- struct ieee80211_rate *rate)
-{
- const u8 *src_data;
- u8 *dest_data;
- u16 src_size, elem_size, src_pos, dest_pos;
- __le16 dur;
- struct ieee80211_hdr *hdr;
- size_t ie_start;
-
- src_size = dev->wl->current_beacon->len;
- src_data = (const u8 *)dev->wl->current_beacon->data;
-
- /* Get the start offset of the variable IEs in the packet. */
- ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
- B43_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, u.beacon.variable));
-
- if (B43_WARN_ON(src_size < ie_start))
- return NULL;
-
- dest_data = kmalloc(src_size, GFP_ATOMIC);
- if (unlikely(!dest_data))
- return NULL;
-
- /* Copy the static data and all Information Elements, except the TIM. */
- memcpy(dest_data, src_data, ie_start);
- src_pos = ie_start;
- dest_pos = ie_start;
- for ( ; src_pos < src_size - 2; src_pos += elem_size) {
- elem_size = src_data[src_pos + 1] + 2;
- if (src_data[src_pos] == 5) {
- /* This is the TIM. */
- continue;
- }
- memcpy(dest_data + dest_pos, src_data + src_pos,
- elem_size);
- dest_pos += elem_size;
- }
- *dest_size = dest_pos;
- hdr = (struct ieee80211_hdr *)dest_data;
-
- /* Set the frame control. */
- hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_PROBE_RESP);
- dur = ieee80211_generic_frame_duration(dev->wl->hw,
- dev->wl->vif, *dest_size,
- rate);
- hdr->duration_id = dur;
-
- return dest_data;
-}
-
-static void b43_write_probe_resp_template(struct b43_wldev *dev,
- u16 ram_offset,
- u16 shm_size_offset,
- struct ieee80211_rate *rate)
-{
- const u8 *probe_resp_data;
- u16 size;
-
- size = dev->wl->current_beacon->len;
- probe_resp_data = b43_generate_probe_resp(dev, &size, rate);
- if (unlikely(!probe_resp_data))
- return;
-
- /* Looks like PLCP headers plus packet timings are stored for
- * all possible basic rates
- */
- b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]);
- b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]);
- b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]);
- b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]);
-
- size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6));
- b43_write_template_common(dev, probe_resp_data,
- size, ram_offset, shm_size_offset,
- rate->hw_value);
- kfree(probe_resp_data);
-}
-
static void b43_upload_beacon0(struct b43_wldev *dev)
{
struct b43_wl *wl = dev->wl;
@@ -1545,10 +1495,6 @@ static void b43_upload_beacon0(struct b43_wldev *dev)
if (wl->beacon0_uploaded)
return;
b43_write_beacon_template(dev, 0x68, 0x18);
- /* FIXME: Probe resp upload doesn't really belong here,
- * but we don't use that feature anyway. */
- b43_write_probe_resp_template(dev, 0x268, 0x4A,
- &__b43_ratetable[3]);
wl->beacon0_uploaded = 1;
}
@@ -1611,6 +1557,27 @@ static void handle_irq_beacon(struct b43_wldev *dev)
}
}
+static void b43_do_beacon_update_trigger_work(struct b43_wldev *dev)
+{
+ u32 old_irq_mask = dev->irq_mask;
+
+ /* update beacon right away or defer to irq */
+ handle_irq_beacon(dev);
+ if (old_irq_mask != dev->irq_mask) {
+ /* The handler updated the IRQ mask. */
+ B43_WARN_ON(!dev->irq_mask);
+ if (b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)) {
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
+ } else {
+ /* Device interrupts are currently disabled. That means
+ * we just ran the hardirq handler and scheduled the
+ * IRQ thread. The thread will write the IRQ mask when
+ * it finished, so there's nothing to do here. Writing
+ * the mask _here_ would incorrectly re-enable IRQs. */
+ }
+ }
+}
+
static void b43_beacon_update_trigger_work(struct work_struct *work)
{
struct b43_wl *wl = container_of(work, struct b43_wl,
@@ -1620,19 +1587,22 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
mutex_lock(&wl->mutex);
dev = wl->current_dev;
if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
- spin_lock_irq(&wl->irq_lock);
- /* update beacon right away or defer to irq */
- handle_irq_beacon(dev);
- /* The handler might have updated the IRQ mask. */
- b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
- mmiowb();
- spin_unlock_irq(&wl->irq_lock);
+ if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) {
+ /* wl->mutex is enough. */
+ b43_do_beacon_update_trigger_work(dev);
+ mmiowb();
+ } else {
+ spin_lock_irq(&wl->hardirq_lock);
+ b43_do_beacon_update_trigger_work(dev);
+ mmiowb();
+ spin_unlock_irq(&wl->hardirq_lock);
+ }
}
mutex_unlock(&wl->mutex);
}
/* Asynchronously update the packet templates in template RAM.
- * Locking: Requires wl->irq_lock to be locked. */
+ * Locking: Requires wl->mutex to be locked. */
static void b43_update_templates(struct b43_wl *wl)
{
struct sk_buff *beacon;
@@ -1656,7 +1626,7 @@ static void b43_update_templates(struct b43_wl *wl)
wl->current_beacon = beacon;
wl->beacon0_uploaded = 0;
wl->beacon1_uploaded = 0;
- queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
+ ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
}
static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
@@ -1769,18 +1739,15 @@ out:
B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK);
}
-/* Interrupt handler bottom-half */
-static void b43_interrupt_tasklet(struct b43_wldev *dev)
+static void b43_do_interrupt_thread(struct b43_wldev *dev)
{
u32 reason;
u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
u32 merged_dma_reason = 0;
int i;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->wl->irq_lock, flags);
- B43_WARN_ON(b43_status(dev) != B43_STAT_STARTED);
+ if (unlikely(b43_status(dev) != B43_STAT_STARTED))
+ return;
reason = dev->irq_reason;
for (i = 0; i < ARRAY_SIZE(dma_reason); i++) {
@@ -1813,8 +1780,6 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
dma_reason[2], dma_reason[3],
dma_reason[4], dma_reason[5]);
b43_controller_restart(dev, "DMA error");
- mmiowb();
- spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
return;
}
if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
@@ -1858,47 +1823,36 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
if (reason & B43_IRQ_TX_OK)
handle_irq_transmit_status(dev);
+ /* Re-enable interrupts on the device by restoring the current interrupt mask. */
b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
- mmiowb();
- spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
}
-static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason)
+/* Interrupt thread handler. Handles device interrupts in thread context. */
+static irqreturn_t b43_interrupt_thread_handler(int irq, void *dev_id)
{
- b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
+ struct b43_wldev *dev = dev_id;
- b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
- b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]);
- b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]);
- b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]);
- b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]);
-/* Unused ring
- b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]);
-*/
+ mutex_lock(&dev->wl->mutex);
+ b43_do_interrupt_thread(dev);
+ mmiowb();
+ mutex_unlock(&dev->wl->mutex);
+
+ return IRQ_HANDLED;
}
-/* Interrupt handler top-half */
-static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
+static irqreturn_t b43_do_interrupt(struct b43_wldev *dev)
{
- irqreturn_t ret = IRQ_NONE;
- struct b43_wldev *dev = dev_id;
u32 reason;
- B43_WARN_ON(!dev);
-
- spin_lock(&dev->wl->irq_lock);
+ /* This code runs under wl->hardirq_lock, but _only_ on non-SDIO busses.
+ * On SDIO, this runs under wl->mutex. */
- if (unlikely(b43_status(dev) < B43_STAT_STARTED)) {
- /* This can only happen on shared IRQ lines. */
- goto out;
- }
reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
if (reason == 0xffffffff) /* shared IRQ */
- goto out;
- ret = IRQ_HANDLED;
+ return IRQ_NONE;
reason &= dev->irq_mask;
if (!reason)
- goto out;
+ return IRQ_HANDLED;
dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
& 0x0001DC00;
@@ -1915,15 +1869,38 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
& 0x0000DC00;
*/
- b43_interrupt_ack(dev, reason);
- /* disable all IRQs. They are enabled again in the bottom half. */
+ /* ACK the interrupt. */
+ b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
+ b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
+ b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]);
+ b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]);
+ b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]);
+ b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]);
+/* Unused ring
+ b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]);
+*/
+
+ /* Disable IRQs on the device. The IRQ thread handler will re-enable them. */
b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
- /* save the reason code and call our bottom half. */
+ /* Save the reason bitmasks for the IRQ thread handler. */
dev->irq_reason = reason;
- tasklet_schedule(&dev->isr_tasklet);
-out:
+
+ return IRQ_WAKE_THREAD;
+}
+
+/* Interrupt handler top-half. This runs with interrupts disabled. */
+static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
+{
+ struct b43_wldev *dev = dev_id;
+ irqreturn_t ret;
+
+ if (unlikely(b43_status(dev) < B43_STAT_STARTED))
+ return IRQ_NONE;
+
+ spin_lock(&dev->wl->hardirq_lock);
+ ret = b43_do_interrupt(dev);
mmiowb();
- spin_unlock(&dev->wl->irq_lock);
+ spin_unlock(&dev->wl->hardirq_lock);
return ret;
}
@@ -2061,8 +2038,12 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
filename = "ucode5";
else if ((rev >= 11) && (rev <= 12))
filename = "ucode11";
- else if (rev >= 13)
+ else if (rev == 13)
filename = "ucode13";
+ else if (rev == 14)
+ filename = "ucode14";
+ else if (rev >= 15)
+ filename = "ucode15";
else
goto err_no_ucode;
err = b43_do_request_fw(ctx, filename, &fw->ucode);
@@ -2110,6 +2091,16 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
else
goto err_no_initvals;
break;
+ case B43_PHYTYPE_LP:
+ if (rev == 13)
+ filename = "lp0initvals13";
+ else if (rev == 14)
+ filename = "lp0initvals14";
+ else if (rev >= 15)
+ filename = "lp0initvals15";
+ else
+ goto err_no_initvals;
+ break;
default:
goto err_no_initvals;
}
@@ -2144,6 +2135,16 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
else
goto err_no_initvals;
break;
+ case B43_PHYTYPE_LP:
+ if (rev == 13)
+ filename = "lp0bsinitvals13";
+ else if (rev == 14)
+ filename = "lp0bsinitvals14";
+ else if (rev >= 15)
+ filename = "lp0bsinitvals15";
+ else
+ goto err_no_initvals;
+ break;
default:
goto err_no_initvals;
}
@@ -2671,6 +2672,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev)
case B43_PHYTYPE_A:
case B43_PHYTYPE_G:
case B43_PHYTYPE_N:
+ case B43_PHYTYPE_LP:
b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
@@ -2916,7 +2918,7 @@ out_requeue:
delay = msecs_to_jiffies(50);
else
delay = round_jiffies_relative(HZ * 15);
- queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay);
+ ieee80211_queue_delayed_work(wl->hw, &dev->periodic_work, delay);
out:
mutex_unlock(&wl->mutex);
}
@@ -2927,15 +2929,16 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev)
dev->periodic_state = 0;
INIT_DELAYED_WORK(work, b43_periodic_work_handler);
- queue_delayed_work(dev->wl->hw->workqueue, work, 0);
+ ieee80211_queue_delayed_work(dev->wl->hw, work, 0);
}
/* Check if communication with the device works correctly. */
static int b43_validate_chipaccess(struct b43_wldev *dev)
{
- u32 v, backup;
+ u32 v, backup0, backup4;
- backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
+ backup0 = b43_shm_read32(dev, B43_SHM_SHARED, 0);
+ backup4 = b43_shm_read32(dev, B43_SHM_SHARED, 4);
/* Check for read/write and endianness problems. */
b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55);
@@ -2945,7 +2948,23 @@ static int b43_validate_chipaccess(struct b43_wldev *dev)
if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
goto error;
- b43_shm_write32(dev, B43_SHM_SHARED, 0, backup);
+ /* Check if unaligned 32bit SHM_SHARED access works properly.
+ * However, don't bail out on failure, because it's noncritical. */
+ b43_shm_write16(dev, B43_SHM_SHARED, 0, 0x1122);
+ b43_shm_write16(dev, B43_SHM_SHARED, 2, 0x3344);
+ b43_shm_write16(dev, B43_SHM_SHARED, 4, 0x5566);
+ b43_shm_write16(dev, B43_SHM_SHARED, 6, 0x7788);
+ if (b43_shm_read32(dev, B43_SHM_SHARED, 2) != 0x55663344)
+ b43warn(dev->wl, "Unaligned 32bit SHM read access is broken\n");
+ b43_shm_write32(dev, B43_SHM_SHARED, 2, 0xAABBCCDD);
+ if (b43_shm_read16(dev, B43_SHM_SHARED, 0) != 0x1122 ||
+ b43_shm_read16(dev, B43_SHM_SHARED, 2) != 0xCCDD ||
+ b43_shm_read16(dev, B43_SHM_SHARED, 4) != 0xAABB ||
+ b43_shm_read16(dev, B43_SHM_SHARED, 6) != 0x7788)
+ b43warn(dev->wl, "Unaligned 32bit SHM write access is broken\n");
+
+ b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0);
+ b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4);
if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) {
/* The 32bit register shadows the two 16bit registers
@@ -2972,17 +2991,14 @@ error:
static void b43_security_init(struct b43_wldev *dev)
{
- dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20;
- B43_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key));
dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP);
/* KTP is a word address, but we address SHM bytewise.
* So multiply by two.
*/
dev->ktp *= 2;
- if (dev->dev->id.revision >= 5) {
- /* Number of RCMTA address slots */
- b43_write16(dev, B43_MMIO_RCMTA_COUNT, dev->max_nr_keys - 8);
- }
+ /* Number of RCMTA address slots */
+ b43_write16(dev, B43_MMIO_RCMTA_COUNT, B43_NR_PAIRWISE_KEYS);
+ /* Clear the key memory. */
b43_clear_keys(dev);
}
@@ -2990,15 +3006,12 @@ static void b43_security_init(struct b43_wldev *dev)
static int b43_rng_read(struct hwrng *rng, u32 *data)
{
struct b43_wl *wl = (struct b43_wl *)rng->priv;
- unsigned long flags;
- /* Don't take wl->mutex here, as it could deadlock with
- * hwrng internal locking. It's not needed to take
- * wl->mutex here, anyway. */
+ /* FIXME: We need to take wl->mutex here to make sure the device
+ * is not going away from under our ass. However it could deadlock
+ * with hwrng internal locking. */
- spin_lock_irqsave(&wl->irq_lock, flags);
*data = b43_read16(wl->current_dev, B43_MMIO_RNG);
- spin_unlock_irqrestore(&wl->irq_lock, flags);
return (sizeof(u16));
}
@@ -3034,46 +3047,52 @@ static int b43_rng_init(struct b43_wl *wl)
return err;
}
-static int b43_op_tx(struct ieee80211_hw *hw,
- struct sk_buff *skb)
+static void b43_tx_work(struct work_struct *work)
{
- struct b43_wl *wl = hw_to_b43_wl(hw);
- struct b43_wldev *dev = wl->current_dev;
- unsigned long flags;
- int err;
+ struct b43_wl *wl = container_of(work, struct b43_wl, tx_work);
+ struct b43_wldev *dev;
+ struct sk_buff *skb;
+ int err = 0;
- if (unlikely(skb->len < 2 + 2 + 6)) {
- /* Too short, this can't be a valid frame. */
- goto drop_packet;
+ mutex_lock(&wl->mutex);
+ dev = wl->current_dev;
+ if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED)) {
+ mutex_unlock(&wl->mutex);
+ return;
}
- B43_WARN_ON(skb_shinfo(skb)->nr_frags);
- if (unlikely(!dev))
- goto drop_packet;
- /* Transmissions on seperate queues can run concurrently. */
- read_lock_irqsave(&wl->tx_lock, flags);
+ while (skb_queue_len(&wl->tx_queue)) {
+ skb = skb_dequeue(&wl->tx_queue);
- err = -ENODEV;
- if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
if (b43_using_pio_transfers(dev))
err = b43_pio_tx(dev, skb);
else
err = b43_dma_tx(dev, skb);
+ if (unlikely(err))
+ dev_kfree_skb(skb); /* Drop it */
}
- read_unlock_irqrestore(&wl->tx_lock, flags);
+ mutex_unlock(&wl->mutex);
+}
- if (unlikely(err))
- goto drop_packet;
- return NETDEV_TX_OK;
+static int b43_op_tx(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+
+ if (unlikely(skb->len < 2 + 2 + 6)) {
+ /* Too short, this can't be a valid frame. */
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+ B43_WARN_ON(skb_shinfo(skb)->nr_frags);
+
+ skb_queue_tail(&wl->tx_queue, skb);
+ ieee80211_queue_work(wl->hw, &wl->tx_work);
-drop_packet:
- /* We can not transmit this packet. Drop it. */
- dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
-/* Locking: wl->irq_lock */
static void b43_qos_params_upload(struct b43_wldev *dev,
const struct ieee80211_tx_queue_params *p,
u16 shm_offset)
@@ -3082,6 +3101,9 @@ static void b43_qos_params_upload(struct b43_wldev *dev,
int bslots, tmp;
unsigned int i;
+ if (!dev->qos_enabled)
+ return;
+
bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min;
memset(&params, 0, sizeof(params));
@@ -3127,6 +3149,9 @@ static void b43_qos_upload_all(struct b43_wldev *dev)
struct b43_qos_params *params;
unsigned int i;
+ if (!dev->qos_enabled)
+ return;
+
BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
ARRAY_SIZE(wl->qos_params));
@@ -3186,6 +3211,16 @@ static void b43_qos_clear(struct b43_wl *wl)
/* Initialize the core's QOS capabilities */
static void b43_qos_init(struct b43_wldev *dev)
{
+ if (!dev->qos_enabled) {
+ /* Disable QOS support. */
+ b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_EDCF);
+ b43_write16(dev, B43_MMIO_IFSCTL,
+ b43_read16(dev, B43_MMIO_IFSCTL)
+ & ~B43_MMIO_IFSCTL_USE_EDCF);
+ b43dbg(dev->wl, "QoS disabled\n");
+ return;
+ }
+
/* Upload the current QOS parameters. */
b43_qos_upload_all(dev);
@@ -3194,6 +3229,7 @@ static void b43_qos_init(struct b43_wldev *dev)
b43_write16(dev, B43_MMIO_IFSCTL,
b43_read16(dev, B43_MMIO_IFSCTL)
| B43_MMIO_IFSCTL_USE_EDCF);
+ b43dbg(dev->wl, "QoS enabled\n");
}
static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue,
@@ -3235,22 +3271,20 @@ static int b43_op_get_tx_stats(struct ieee80211_hw *hw,
struct ieee80211_tx_queue_stats *stats)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
- struct b43_wldev *dev = wl->current_dev;
- unsigned long flags;
+ struct b43_wldev *dev;
int err = -ENODEV;
- if (!dev)
- goto out;
- spin_lock_irqsave(&wl->irq_lock, flags);
- if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
+ mutex_lock(&wl->mutex);
+ dev = wl->current_dev;
+ if (dev && b43_status(dev) >= B43_STAT_STARTED) {
if (b43_using_pio_transfers(dev))
b43_pio_get_tx_stats(dev, stats);
else
b43_dma_get_tx_stats(dev, stats);
err = 0;
}
- spin_unlock_irqrestore(&wl->irq_lock, flags);
-out:
+ mutex_unlock(&wl->mutex);
+
return err;
}
@@ -3258,11 +3292,10 @@ static int b43_op_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
- unsigned long flags;
- spin_lock_irqsave(&wl->irq_lock, flags);
+ mutex_lock(&wl->mutex);
memcpy(stats, &wl->ieee_stats, sizeof(*stats));
- spin_unlock_irqrestore(&wl->irq_lock, flags);
+ mutex_unlock(&wl->mutex);
return 0;
}
@@ -3274,7 +3307,6 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw)
u64 tsf;
mutex_lock(&wl->mutex);
- spin_lock_irq(&wl->irq_lock);
dev = wl->current_dev;
if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED))
@@ -3282,7 +3314,6 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw)
else
tsf = 0;
- spin_unlock_irq(&wl->irq_lock);
mutex_unlock(&wl->mutex);
return tsf;
@@ -3294,13 +3325,11 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
struct b43_wldev *dev;
mutex_lock(&wl->mutex);
- spin_lock_irq(&wl->irq_lock);
dev = wl->current_dev;
if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED))
b43_tsf_write(dev, tsf);
- spin_unlock_irq(&wl->irq_lock);
mutex_unlock(&wl->mutex);
}
@@ -3386,7 +3415,7 @@ static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan)
prev_status = b43_status(down_dev);
/* Shutdown the currently running core. */
if (prev_status >= B43_STAT_STARTED)
- b43_wireless_core_stop(down_dev);
+ down_dev = b43_wireless_core_stop(down_dev);
if (prev_status >= B43_STAT_INITIALIZED)
b43_wireless_core_exit(down_dev);
@@ -3450,7 +3479,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
struct b43_wldev *dev;
struct b43_phy *phy;
struct ieee80211_conf *conf = &hw->conf;
- unsigned long flags;
int antenna;
int err = 0;
@@ -3481,13 +3509,11 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
/* Adjust the desired TX power level. */
if (conf->power_level != 0) {
- spin_lock_irqsave(&wl->irq_lock, flags);
if (conf->power_level != phy->desired_txpower) {
phy->desired_txpower = conf->power_level;
b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME |
B43_TXPWR_IGNORE_TSSI);
}
- spin_unlock_irqrestore(&wl->irq_lock, flags);
}
/* Antennas for RX and management frame TX. */
@@ -3572,7 +3598,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev;
- unsigned long flags;
mutex_lock(&wl->mutex);
@@ -3582,7 +3607,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
B43_WARN_ON(wl->vif != vif);
- spin_lock_irqsave(&wl->irq_lock, flags);
if (changed & BSS_CHANGED_BSSID) {
if (conf->bssid)
memcpy(wl->bssid, conf->bssid, ETH_ALEN);
@@ -3600,7 +3624,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BSSID)
b43_write_mac_bssid_templates(dev);
}
- spin_unlock_irqrestore(&wl->irq_lock, flags);
b43_mac_suspend(dev);
@@ -3641,15 +3664,6 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return -ENOSPC; /* User disabled HW-crypto */
mutex_lock(&wl->mutex);
- spin_lock_irq(&wl->irq_lock);
- write_lock(&wl->tx_lock);
- /* Why do we need all this locking here?
- * mutex -> Every config operation must take it.
- * irq_lock -> We modify the dev->key array, which is accessed
- * in the IRQ handlers.
- * tx_lock -> We modify the dev->key array, which is accessed
- * in the TX handler.
- */
dev = wl->current_dev;
err = -ENODEV;
@@ -3687,8 +3701,10 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
switch (cmd) {
case SET_KEY:
- if (algorithm == B43_SEC_ALGO_TKIP) {
- /* FIXME: No TKIP hardware encryption for now. */
+ if (algorithm == B43_SEC_ALGO_TKIP &&
+ (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ||
+ !modparam_hwtkip)) {
+ /* We support only pairwise key */
err = -EOPNOTSUPP;
goto out_unlock;
}
@@ -3718,6 +3734,8 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
b43_hf_read(dev) & ~B43_HF_USEDEFKEYS);
}
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ if (algorithm == B43_SEC_ALGO_TKIP)
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
break;
case DISABLE_KEY: {
err = b43_key_clear(dev, key->hw_key_idx);
@@ -3737,8 +3755,6 @@ out_unlock:
sta ? sta->addr : bcast_addr);
b43_dump_keymemory(dev);
}
- write_unlock(&wl->tx_lock);
- spin_unlock_irq(&wl->irq_lock);
mutex_unlock(&wl->mutex);
return err;
@@ -3746,18 +3762,18 @@ out_unlock:
static void b43_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed, unsigned int *fflags,
- int mc_count, struct dev_addr_list *mc_list)
+ u64 multicast)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
- struct b43_wldev *dev = wl->current_dev;
- unsigned long flags;
+ struct b43_wldev *dev;
+ mutex_lock(&wl->mutex);
+ dev = wl->current_dev;
if (!dev) {
*fflags = 0;
- return;
+ goto out_unlock;
}
- spin_lock_irqsave(&wl->irq_lock, flags);
*fflags &= FIF_PROMISC_IN_BSS |
FIF_ALLMULTI |
FIF_FCSFAIL |
@@ -3778,41 +3794,70 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw,
if (changed && b43_status(dev) >= B43_STAT_INITIALIZED)
b43_adjust_opmode(dev);
- spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+out_unlock:
+ mutex_unlock(&wl->mutex);
}
-/* Locking: wl->mutex */
-static void b43_wireless_core_stop(struct b43_wldev *dev)
+/* Locking: wl->mutex
+ * Returns the current dev. This might be different from the passed in dev,
+ * because the core might be gone away while we unlocked the mutex. */
+static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev)
{
struct b43_wl *wl = dev->wl;
- unsigned long flags;
+ struct b43_wldev *orig_dev;
- if (b43_status(dev) < B43_STAT_STARTED)
- return;
+redo:
+ if (!dev || b43_status(dev) < B43_STAT_STARTED)
+ return dev;
- /* Disable and sync interrupts. We must do this before than
- * setting the status to INITIALIZED, as the interrupt handler
- * won't care about IRQs then. */
- spin_lock_irqsave(&wl->irq_lock, flags);
- b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
- b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */
- spin_unlock_irqrestore(&wl->irq_lock, flags);
- b43_synchronize_irq(dev);
+ /* Cancel work. Unlock to avoid deadlocks. */
+ mutex_unlock(&wl->mutex);
+ cancel_delayed_work_sync(&dev->periodic_work);
+ cancel_work_sync(&wl->tx_work);
+ mutex_lock(&wl->mutex);
+ dev = wl->current_dev;
+ if (!dev || b43_status(dev) < B43_STAT_STARTED) {
+ /* Whoops, aliens ate up the device while we were unlocked. */
+ return dev;
+ }
- write_lock_irqsave(&wl->tx_lock, flags);
+ /* Disable interrupts on the device. */
b43_set_status(dev, B43_STAT_INITIALIZED);
- write_unlock_irqrestore(&wl->tx_lock, flags);
-
- b43_pio_stop(dev);
+ if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) {
+ /* wl->mutex is locked. That is enough. */
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
+ b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
+ } else {
+ spin_lock_irq(&wl->hardirq_lock);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
+ b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
+ spin_unlock_irq(&wl->hardirq_lock);
+ }
+ /* Synchronize the interrupt handlers. Unlock to avoid deadlocks. */
+ orig_dev = dev;
mutex_unlock(&wl->mutex);
- /* Must unlock as it would otherwise deadlock. No races here.
- * Cancel the possibly running self-rearming periodic work. */
- cancel_delayed_work_sync(&dev->periodic_work);
+ synchronize_irq(dev->dev->irq);
mutex_lock(&wl->mutex);
+ dev = wl->current_dev;
+ if (!dev)
+ return dev;
+ if (dev != orig_dev) {
+ if (b43_status(dev) >= B43_STAT_STARTED)
+ goto redo;
+ return dev;
+ }
+ B43_WARN_ON(b43_read32(dev, B43_MMIO_GEN_IRQ_MASK));
+
+ /* Drain the TX queue */
+ while (skb_queue_len(&wl->tx_queue))
+ dev_kfree_skb(skb_dequeue(&wl->tx_queue));
b43_mac_suspend(dev);
free_irq(dev->dev->irq, dev);
b43dbg(wl, "Wireless interface stopped\n");
+
+ return dev;
}
/* Locking: wl->mutex */
@@ -3823,8 +3868,9 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
drain_txstatus_queue(dev);
- err = request_irq(dev->dev->irq, b43_interrupt_handler,
- IRQF_SHARED, KBUILD_MODNAME, dev);
+ err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,
+ b43_interrupt_thread_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
if (err) {
b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
goto out;
@@ -3885,7 +3931,7 @@ static int b43_phy_versioning(struct b43_wldev *dev)
#endif
#ifdef CONFIG_B43_PHY_LP
case B43_PHYTYPE_LP:
- if (phy_rev > 1)
+ if (phy_rev > 2)
unsupported = 1;
break;
#endif
@@ -3942,7 +3988,7 @@ static int b43_phy_versioning(struct b43_wldev *dev)
unsupported = 1;
break;
case B43_PHYTYPE_LP:
- if (radio_ver != 0x2062)
+ if (radio_ver != 0x2062 && radio_ver != 0x2063)
unsupported = 1;
break;
default:
@@ -4046,16 +4092,20 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
bus->pcicore.dev->id.revision <= 5) {
/* IMCFGLO timeouts workaround. */
tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
- tmp &= ~SSB_IMCFGLO_REQTO;
- tmp &= ~SSB_IMCFGLO_SERTO;
switch (bus->bustype) {
case SSB_BUSTYPE_PCI:
case SSB_BUSTYPE_PCMCIA:
+ tmp &= ~SSB_IMCFGLO_REQTO;
+ tmp &= ~SSB_IMCFGLO_SERTO;
tmp |= 0x32;
break;
case SSB_BUSTYPE_SSB:
+ tmp &= ~SSB_IMCFGLO_REQTO;
+ tmp &= ~SSB_IMCFGLO_SERTO;
tmp |= 0x53;
break;
+ default:
+ break;
}
ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
}
@@ -4103,8 +4153,8 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
{
u32 macctl;
- B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
- if (b43_status(dev) != B43_STAT_INITIALIZED)
+ B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED);
+ if (!dev || b43_status(dev) != B43_STAT_INITIALIZED)
return;
b43_set_status(dev, B43_STAT_UNINIT);
@@ -4257,7 +4307,6 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev;
- unsigned long flags;
int err = -EOPNOTSUPP;
/* TODO: allow WDS/AP devices to coexist */
@@ -4281,12 +4330,10 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
wl->if_type = conf->type;
memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
- spin_lock_irqsave(&wl->irq_lock, flags);
b43_adjust_opmode(dev);
b43_set_pretbtt(dev);
b43_set_synth_pu_delay(dev, 0);
b43_upload_card_macaddress(dev);
- spin_unlock_irqrestore(&wl->irq_lock, flags);
err = 0;
out_mutex_unlock:
@@ -4300,7 +4347,6 @@ static void b43_op_remove_interface(struct ieee80211_hw *hw,
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev = wl->current_dev;
- unsigned long flags;
b43dbg(wl, "Removing Interface type %d\n", conf->type);
@@ -4312,11 +4358,9 @@ static void b43_op_remove_interface(struct ieee80211_hw *hw,
wl->operating = 0;
- spin_lock_irqsave(&wl->irq_lock, flags);
b43_adjust_opmode(dev);
memset(wl->mac_addr, 0, ETH_ALEN);
b43_upload_card_macaddress(dev);
- spin_unlock_irqrestore(&wl->irq_lock, flags);
mutex_unlock(&wl->mutex);
}
@@ -4376,10 +4420,15 @@ static void b43_op_stop(struct ieee80211_hw *hw)
cancel_work_sync(&(wl->beacon_update_trigger));
mutex_lock(&wl->mutex);
- if (b43_status(dev) >= B43_STAT_STARTED)
- b43_wireless_core_stop(dev);
+ if (b43_status(dev) >= B43_STAT_STARTED) {
+ dev = b43_wireless_core_stop(dev);
+ if (!dev)
+ goto out_unlock;
+ }
b43_wireless_core_exit(dev);
wl->radio_enabled = 0;
+
+out_unlock:
mutex_unlock(&wl->mutex);
cancel_work_sync(&(wl->txpower_adjust_work));
@@ -4389,11 +4438,10 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, bool set)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
- unsigned long flags;
- spin_lock_irqsave(&wl->irq_lock, flags);
+ mutex_lock(&wl->mutex);
b43_update_templates(wl);
- spin_unlock_irqrestore(&wl->irq_lock, flags);
+ mutex_unlock(&wl->mutex);
return 0;
}
@@ -4445,6 +4493,7 @@ static const struct ieee80211_ops b43_hw_ops = {
.bss_info_changed = b43_op_bss_info_changed,
.configure_filter = b43_op_configure_filter,
.set_key = b43_op_set_key,
+ .update_tkip_key = b43_op_update_tkip_key,
.get_stats = b43_op_get_stats,
.get_tx_stats = b43_op_get_tx_stats,
.get_tsf = b43_op_get_tsf,
@@ -4473,8 +4522,13 @@ static void b43_chip_reset(struct work_struct *work)
prev_status = b43_status(dev);
/* Bring the device down... */
- if (prev_status >= B43_STAT_STARTED)
- b43_wireless_core_stop(dev);
+ if (prev_status >= B43_STAT_STARTED) {
+ dev = b43_wireless_core_stop(dev);
+ if (!dev) {
+ err = -ENODEV;
+ goto out;
+ }
+ }
if (prev_status >= B43_STAT_INITIALIZED)
b43_wireless_core_exit(dev);
@@ -4580,9 +4634,12 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
case B43_PHYTYPE_A:
have_5ghz_phy = 1;
break;
+ case B43_PHYTYPE_LP: //FIXME not always!
+#if 0 //FIXME enabling 5GHz causes a NULL pointer dereference
+ have_5ghz_phy = 1;
+#endif
case B43_PHYTYPE_G:
case B43_PHYTYPE_N:
- case B43_PHYTYPE_LP:
have_2ghz_phy = 1;
break;
default:
@@ -4597,7 +4654,8 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
}
if (1 /* disable A-PHY */) {
/* FIXME: For now we disable the A-PHY on multi-PHY devices. */
- if (dev->phy.type != B43_PHYTYPE_N) {
+ if (dev->phy.type != B43_PHYTYPE_N &&
+ dev->phy.type != B43_PHYTYPE_LP) {
have_2ghz_phy = 1;
have_5ghz_phy = 0;
}
@@ -4685,9 +4743,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
wldev->wl = wl;
b43_set_status(wldev, B43_STAT_UNINIT);
wldev->bad_frames_preempt = modparam_bad_frames_preempt;
- tasklet_init(&wldev->isr_tasklet,
- (void (*)(unsigned long))b43_interrupt_tasklet,
- (unsigned long)wldev);
INIT_LIST_HEAD(&wldev->list);
err = b43_wireless_core_attach(wldev);
@@ -4784,14 +4839,14 @@ static int b43_wireless_init(struct ssb_device *dev)
/* Initialize struct b43_wl */
wl->hw = hw;
- spin_lock_init(&wl->irq_lock);
- rwlock_init(&wl->tx_lock);
spin_lock_init(&wl->leds_lock);
- spin_lock_init(&wl->shm_lock);
mutex_init(&wl->mutex);
+ spin_lock_init(&wl->hardirq_lock);
INIT_LIST_HEAD(&wl->devlist);
INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
+ INIT_WORK(&wl->tx_work, b43_tx_work);
+ skb_queue_head_init(&wl->tx_queue);
ssb_set_devtypedata(dev, wl);
b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n",
@@ -4873,7 +4928,7 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason)
if (b43_status(dev) < B43_STAT_INITIALIZED)
return;
b43info(dev->wl, "Controller RESET (%s) ...\n", reason);
- queue_work(dev->wl->hw->workqueue, &dev->restart_work);
+ ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
}
#ifdef CONFIG_PM
@@ -4889,8 +4944,8 @@ static int b43_suspend(struct ssb_device *dev, pm_message_t state)
wldev->suspend_in_progress = true;
wldev->suspend_init_status = b43_status(wldev);
if (wldev->suspend_init_status >= B43_STAT_STARTED)
- b43_wireless_core_stop(wldev);
- if (wldev->suspend_init_status >= B43_STAT_INITIALIZED)
+ wldev = b43_wireless_core_stop(wldev);
+ if (wldev && wldev->suspend_init_status >= B43_STAT_INITIALIZED)
b43_wireless_core_exit(wldev);
mutex_unlock(&wl->mutex);
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
index 950fb1b0546d..40db03678d9f 100644
--- a/drivers/net/wireless/b43/main.h
+++ b/drivers/net/wireless/b43/main.h
@@ -112,18 +112,14 @@ void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
void b43_tsf_write(struct b43_wldev *dev, u64 tsf);
u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
-u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
-u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
-void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
-void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
u64 b43_hf_read(struct b43_wldev *dev);
void b43_hf_write(struct b43_wldev *dev, u64 value);
-void b43_dummy_transmission(struct b43_wldev *dev);
+void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on);
void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags);
diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c
index 816e028a2620..d90217c3a706 100644
--- a/drivers/net/wireless/b43/phy_a.c
+++ b/drivers/net/wireless/b43/phy_a.c
@@ -518,58 +518,40 @@ static unsigned int b43_aphy_op_get_default_chan(struct b43_wldev *dev)
static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
{//TODO
struct b43_phy *phy = &dev->phy;
- u64 hf;
u16 tmp;
int autodiv = 0;
if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1)
autodiv = 1;
- hf = b43_hf_read(dev);
- hf &= ~B43_HF_ANTDIVHELP;
- b43_hf_write(dev, hf);
+ b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP);
- tmp = b43_phy_read(dev, B43_PHY_BBANDCFG);
- tmp &= ~B43_PHY_BBANDCFG_RXANT;
- tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
- << B43_PHY_BBANDCFG_RXANT_SHIFT;
- b43_phy_write(dev, B43_PHY_BBANDCFG, tmp);
+ b43_phy_maskset(dev, B43_PHY_BBANDCFG, ~B43_PHY_BBANDCFG_RXANT,
+ (autodiv ? B43_ANTENNA_AUTO1 : antenna) <<
+ B43_PHY_BBANDCFG_RXANT_SHIFT);
if (autodiv) {
tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
- if (antenna == B43_ANTENNA_AUTO0)
+ if (antenna == B43_ANTENNA_AUTO1)
tmp &= ~B43_PHY_ANTDWELL_AUTODIV1;
else
tmp |= B43_PHY_ANTDWELL_AUTODIV1;
b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
}
- if (phy->rev < 3) {
- tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
- tmp = (tmp & 0xFF00) | 0x24;
- b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
- } else {
- tmp = b43_phy_read(dev, B43_PHY_OFDM61);
- tmp |= 0x10;
- b43_phy_write(dev, B43_PHY_OFDM61, tmp);
- if (phy->analog == 3) {
- b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
- 0x1D);
- b43_phy_write(dev, B43_PHY_ADIVRELATED,
- 8);
+ if (phy->rev < 3)
+ b43_phy_maskset(dev, B43_PHY_ANTDWELL, 0xFF00, 0x24);
+ else {
+ b43_phy_set(dev, B43_PHY_OFDM61, 0x10);
+ if (phy->rev == 3) {
+ b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, 0x1D);
+ b43_phy_write(dev, B43_PHY_ADIVRELATED, 8);
} else {
- b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
- 0x3A);
- tmp =
- b43_phy_read(dev,
- B43_PHY_ADIVRELATED);
- tmp = (tmp & 0xFF00) | 8;
- b43_phy_write(dev, B43_PHY_ADIVRELATED,
- tmp);
+ b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, 0x3A);
+ b43_phy_maskset(dev, B43_PHY_ADIVRELATED, 0xFF00, 8);
}
}
- hf |= B43_HF_ANTDIVHELP;
- b43_hf_write(dev, hf);
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP);
}
static void b43_aphy_op_adjust_txpower(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 6d241622210e..75b26e175e8f 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -240,22 +240,44 @@ void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
dev->phy.ops->phy_write(dev, reg, value);
}
+void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg)
+{
+ assert_mac_suspended(dev);
+ dev->phy.ops->phy_write(dev, destreg,
+ dev->phy.ops->phy_read(dev, srcreg));
+}
+
void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
{
- b43_phy_write(dev, offset,
- b43_phy_read(dev, offset) & mask);
+ if (dev->phy.ops->phy_maskset) {
+ assert_mac_suspended(dev);
+ dev->phy.ops->phy_maskset(dev, offset, mask, 0);
+ } else {
+ b43_phy_write(dev, offset,
+ b43_phy_read(dev, offset) & mask);
+ }
}
void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set)
{
- b43_phy_write(dev, offset,
- b43_phy_read(dev, offset) | set);
+ if (dev->phy.ops->phy_maskset) {
+ assert_mac_suspended(dev);
+ dev->phy.ops->phy_maskset(dev, offset, 0xFFFF, set);
+ } else {
+ b43_phy_write(dev, offset,
+ b43_phy_read(dev, offset) | set);
+ }
}
void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
{
- b43_phy_write(dev, offset,
- (b43_phy_read(dev, offset) & mask) | set);
+ if (dev->phy.ops->phy_maskset) {
+ assert_mac_suspended(dev);
+ dev->phy.ops->phy_maskset(dev, offset, mask, set);
+ } else {
+ b43_phy_write(dev, offset,
+ (b43_phy_read(dev, offset) & mask) | set);
+ }
}
int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
@@ -325,7 +347,6 @@ void b43_phy_txpower_adjust_work(struct work_struct *work)
mutex_unlock(&wl->mutex);
}
-/* Called with wl->irq_lock locked */
void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
{
struct b43_phy *phy = &dev->phy;
@@ -352,7 +373,7 @@ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
/* We must adjust the transmission power in hardware.
* Schedule b43_phy_txpower_adjust_work(). */
- queue_work(dev->wl->hw->workqueue, &dev->wl->txpower_adjust_work);
+ ieee80211_queue_work(dev->wl->hw, &dev->wl->txpower_adjust_work);
}
int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset)
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h
index 44cc918e4fc6..9edd4e8e0c85 100644
--- a/drivers/net/wireless/b43/phy_common.h
+++ b/drivers/net/wireless/b43/phy_common.h
@@ -49,11 +49,11 @@ enum b43_interference_mitigation {
/* Antenna identifiers */
enum {
- B43_ANTENNA0, /* Antenna 0 */
- B43_ANTENNA1, /* Antenna 0 */
- B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
- B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
- B43_ANTENNA2,
+ B43_ANTENNA0 = 0, /* Antenna 0 */
+ B43_ANTENNA1 = 1, /* Antenna 1 */
+ B43_ANTENNA_AUTO0 = 2, /* Automatic, starting with antenna 0 */
+ B43_ANTENNA_AUTO1 = 3, /* Automatic, starting with antenna 1 */
+ B43_ANTENNA2 = 4,
B43_ANTENNA3 = 8,
B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
@@ -95,6 +95,8 @@ enum b43_txpwr_result {
* Must not be NULL.
* @phy_write: Write to a PHY register.
* Must not be NULL.
+ * @phy_maskset: Maskset a PHY register, taking shortcuts.
+ * If it is NULL, a generic algorithm is used.
* @radio_read: Read from a Radio register.
* Must not be NULL.
* @radio_write: Write to a Radio register.
@@ -129,7 +131,7 @@ enum b43_txpwr_result {
* If the parameter "ignore_tssi" is true, the TSSI values should
* be ignored and a recalculation of the power settings should be
* done even if the TSSI values did not change.
- * This callback is called with wl->irq_lock held and must not sleep.
+ * This function may sleep, but should not.
* Must not be NULL.
* @adjust_txpower: Write the previously calculated TX power settings
* (from @recalc_txpower) to the hardware.
@@ -154,6 +156,7 @@ struct b43_phy_operations {
/* Register access */
u16 (*phy_read)(struct b43_wldev *dev, u16 reg);
void (*phy_write)(struct b43_wldev *dev, u16 reg, u16 value);
+ void (*phy_maskset)(struct b43_wldev *dev, u16 reg, u16 mask, u16 set);
u16 (*radio_read)(struct b43_wldev *dev, u16 reg);
void (*radio_write)(struct b43_wldev *dev, u16 reg, u16 value);
@@ -291,6 +294,11 @@ u16 b43_phy_read(struct b43_wldev *dev, u16 reg);
void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value);
/**
+ * b43_phy_copy - copy contents of 16bit PHY register to another
+ */
+void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg);
+
+/**
* b43_phy_mask - Mask a PHY register with a mask
*/
void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask);
@@ -371,7 +379,6 @@ void b43_software_rfkill(struct b43_wldev *dev, bool blocked);
*
* Compare the current TX power output to the desired power emission
* and schedule an adjustment in case it mismatches.
- * Requires wl->irq_lock locked.
*
* @flags: OR'ed enum b43_phy_txpower_check_flags flags.
* See the docs below.
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c
index 5300232449f6..382826a8da82 100644
--- a/drivers/net/wireless/b43/phy_g.c
+++ b/drivers/net/wireless/b43/phy_g.c
@@ -333,7 +333,7 @@ static void b43_set_all_gains(struct b43_wldev *dev,
b43_phy_maskset(dev, 0x04A1, 0xBFBF, tmp);
b43_phy_maskset(dev, 0x04A2, 0xBFBF, tmp);
}
- b43_dummy_transmission(dev);
+ b43_dummy_transmission(dev, false, true);
}
static void b43_set_original_gains(struct b43_wldev *dev)
@@ -365,7 +365,7 @@ static void b43_set_original_gains(struct b43_wldev *dev)
b43_phy_maskset(dev, 0x04A0, 0xBFBF, 0x4040);
b43_phy_maskset(dev, 0x04A1, 0xBFBF, 0x4040);
b43_phy_maskset(dev, 0x04A2, 0xBFBF, 0x4000);
- b43_dummy_transmission(dev);
+ b43_dummy_transmission(dev, false, true);
}
/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
@@ -1964,7 +1964,7 @@ static void b43_phy_init_pctl(struct b43_wldev *dev)
}
b43_set_txpower_g(dev, &bbatt, &rfatt, 0);
}
- b43_dummy_transmission(dev);
+ b43_dummy_transmission(dev, false, true);
gphy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI);
if (B43_DEBUG) {
/* Current-Idle-TSSI sanity check. */
@@ -2651,65 +2651,54 @@ static unsigned int b43_gphy_op_get_default_chan(struct b43_wldev *dev)
static void b43_gphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
{
struct b43_phy *phy = &dev->phy;
- u64 hf;
u16 tmp;
int autodiv = 0;
if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1)
autodiv = 1;
- hf = b43_hf_read(dev);
- hf &= ~B43_HF_ANTDIVHELP;
- b43_hf_write(dev, hf);
+ b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP);
- tmp = b43_phy_read(dev, B43_PHY_BBANDCFG);
- tmp &= ~B43_PHY_BBANDCFG_RXANT;
- tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
- << B43_PHY_BBANDCFG_RXANT_SHIFT;
- b43_phy_write(dev, B43_PHY_BBANDCFG, tmp);
+ b43_phy_maskset(dev, B43_PHY_BBANDCFG, ~B43_PHY_BBANDCFG_RXANT,
+ (autodiv ? B43_ANTENNA_AUTO1 : antenna) <<
+ B43_PHY_BBANDCFG_RXANT_SHIFT);
if (autodiv) {
tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
- if (antenna == B43_ANTENNA_AUTO0)
+ if (antenna == B43_ANTENNA_AUTO1)
tmp &= ~B43_PHY_ANTDWELL_AUTODIV1;
else
tmp |= B43_PHY_ANTDWELL_AUTODIV1;
b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
}
+
tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT);
if (autodiv)
tmp |= B43_PHY_ANTWRSETT_ARXDIV;
else
tmp &= ~B43_PHY_ANTWRSETT_ARXDIV;
b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp);
- if (phy->rev >= 2) {
- tmp = b43_phy_read(dev, B43_PHY_OFDM61);
- tmp |= B43_PHY_OFDM61_10;
- b43_phy_write(dev, B43_PHY_OFDM61, tmp);
- tmp =
- b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK);
- tmp = (tmp & 0xFF00) | 0x15;
- b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK,
- tmp);
+ if (autodiv)
+ b43_phy_set(dev, B43_PHY_ANTWRSETT, B43_PHY_ANTWRSETT_ARXDIV);
+ else {
+ b43_phy_mask(dev, B43_PHY_ANTWRSETT,
+ B43_PHY_ANTWRSETT_ARXDIV);
+ }
- if (phy->rev == 2) {
- b43_phy_write(dev, B43_PHY_ADIVRELATED,
- 8);
- } else {
- tmp =
- b43_phy_read(dev,
- B43_PHY_ADIVRELATED);
- tmp = (tmp & 0xFF00) | 8;
- b43_phy_write(dev, B43_PHY_ADIVRELATED,
- tmp);
- }
+ if (phy->rev >= 2) {
+ b43_phy_set(dev, B43_PHY_OFDM61, B43_PHY_OFDM61_10);
+ b43_phy_maskset(dev, B43_PHY_DIVSRCHGAINBACK, 0xFF00, 0x15);
+
+ if (phy->rev == 2)
+ b43_phy_write(dev, B43_PHY_ADIVRELATED, 8);
+ else
+ b43_phy_maskset(dev, B43_PHY_ADIVRELATED, 0xFF00, 8);
}
if (phy->rev >= 6)
b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC);
- hf |= B43_HF_ANTDIVHELP;
- b43_hf_write(dev, hf);
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP);
}
static int b43_gphy_op_interf_mitigation(struct b43_wldev *dev,
@@ -2834,8 +2823,6 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
b43_mac_suspend(dev);
- spin_lock_irq(&dev->wl->irq_lock);
-
/* Calculate the new attenuation values. */
bbatt = gphy->bbatt.att;
bbatt += gphy->bbatt_delta;
@@ -2875,11 +2862,6 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
gphy->rfatt.att = rfatt;
gphy->bbatt.att = bbatt;
- /* We drop the lock early, so we can sleep during hardware
- * adjustment. Possible races with op_recalc_txpower are harmless,
- * as we will be called once again in case we raced. */
- spin_unlock_irq(&dev->wl->irq_lock);
-
if (b43_debug(dev, B43_DBG_XMITPOWER))
b43dbg(dev->wl, "Adjusting TX power\n");
diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h
index 718947fd41ae..8569fdd4c6be 100644
--- a/drivers/net/wireless/b43/phy_g.h
+++ b/drivers/net/wireless/b43/phy_g.h
@@ -141,8 +141,7 @@ struct b43_phy_g {
int tgt_idle_tssi;
/* Current idle TSSI */
int cur_idle_tssi;
- /* The current average TSSI.
- * Needs irq_lock, as it's updated in the IRQ path. */
+ /* The current average TSSI. */
u8 average_tssi;
/* Current TX power level attenuation control values */
struct b43_bbatt bbatt;
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index ea0d3a3a6a64..3e02d969f683 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -1,9 +1,10 @@
/*
Broadcom B43 wireless driver
- IEEE 802.11g LP-PHY driver
+ IEEE 802.11a/g LP-PHY driver
Copyright (c) 2008-2009 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2009 Gábor Stefanik <netrolller.3d@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -29,6 +30,25 @@
#include "tables_lpphy.h"
+static inline u16 channel2freq_lp(u8 channel)
+{
+ if (channel < 14)
+ return (2407 + 5 * channel);
+ else if (channel == 14)
+ return 2484;
+ else if (channel < 184)
+ return (5000 + 5 * channel);
+ else
+ return (4000 + 5 * channel);
+}
+
+static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev)
+{
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ return 1;
+ return 36;
+}
+
static int b43_lpphy_op_allocate(struct b43_wldev *dev)
{
struct b43_phy_lp *lpphy;
@@ -59,14 +79,325 @@ static void b43_lpphy_op_free(struct b43_wldev *dev)
dev->phy.lp = NULL;
}
+static void lpphy_read_band_sprom(struct b43_wldev *dev)
+{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ struct ssb_bus *bus = dev->dev->bus;
+ u16 cckpo, maxpwr;
+ u32 ofdmpo;
+ int i;
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ lpphy->tx_isolation_med_band = bus->sprom.tri2g;
+ lpphy->bx_arch = bus->sprom.bxa2g;
+ lpphy->rx_pwr_offset = bus->sprom.rxpo2g;
+ lpphy->rssi_vf = bus->sprom.rssismf2g;
+ lpphy->rssi_vc = bus->sprom.rssismc2g;
+ lpphy->rssi_gs = bus->sprom.rssisav2g;
+ lpphy->txpa[0] = bus->sprom.pa0b0;
+ lpphy->txpa[1] = bus->sprom.pa0b1;
+ lpphy->txpa[2] = bus->sprom.pa0b2;
+ maxpwr = bus->sprom.maxpwr_bg;
+ lpphy->max_tx_pwr_med_band = maxpwr;
+ cckpo = bus->sprom.cck2gpo;
+ ofdmpo = bus->sprom.ofdm2gpo;
+ if (cckpo) {
+ for (i = 0; i < 4; i++) {
+ lpphy->tx_max_rate[i] =
+ maxpwr - (ofdmpo & 0xF) * 2;
+ ofdmpo >>= 4;
+ }
+ ofdmpo = bus->sprom.ofdm2gpo;
+ for (i = 4; i < 15; i++) {
+ lpphy->tx_max_rate[i] =
+ maxpwr - (ofdmpo & 0xF) * 2;
+ ofdmpo >>= 4;
+ }
+ } else {
+ ofdmpo &= 0xFF;
+ for (i = 0; i < 4; i++)
+ lpphy->tx_max_rate[i] = maxpwr;
+ for (i = 4; i < 15; i++)
+ lpphy->tx_max_rate[i] = maxpwr - ofdmpo;
+ }
+ } else { /* 5GHz */
+ lpphy->tx_isolation_low_band = bus->sprom.tri5gl;
+ lpphy->tx_isolation_med_band = bus->sprom.tri5g;
+ lpphy->tx_isolation_hi_band = bus->sprom.tri5gh;
+ lpphy->bx_arch = bus->sprom.bxa5g;
+ lpphy->rx_pwr_offset = bus->sprom.rxpo5g;
+ lpphy->rssi_vf = bus->sprom.rssismf5g;
+ lpphy->rssi_vc = bus->sprom.rssismc5g;
+ lpphy->rssi_gs = bus->sprom.rssisav5g;
+ lpphy->txpa[0] = bus->sprom.pa1b0;
+ lpphy->txpa[1] = bus->sprom.pa1b1;
+ lpphy->txpa[2] = bus->sprom.pa1b2;
+ lpphy->txpal[0] = bus->sprom.pa1lob0;
+ lpphy->txpal[1] = bus->sprom.pa1lob1;
+ lpphy->txpal[2] = bus->sprom.pa1lob2;
+ lpphy->txpah[0] = bus->sprom.pa1hib0;
+ lpphy->txpah[1] = bus->sprom.pa1hib1;
+ lpphy->txpah[2] = bus->sprom.pa1hib2;
+ maxpwr = bus->sprom.maxpwr_al;
+ ofdmpo = bus->sprom.ofdm5glpo;
+ lpphy->max_tx_pwr_low_band = maxpwr;
+ for (i = 4; i < 12; i++) {
+ lpphy->tx_max_ratel[i] = maxpwr - (ofdmpo & 0xF) * 2;
+ ofdmpo >>= 4;
+ }
+ maxpwr = bus->sprom.maxpwr_a;
+ ofdmpo = bus->sprom.ofdm5gpo;
+ lpphy->max_tx_pwr_med_band = maxpwr;
+ for (i = 4; i < 12; i++) {
+ lpphy->tx_max_rate[i] = maxpwr - (ofdmpo & 0xF) * 2;
+ ofdmpo >>= 4;
+ }
+ maxpwr = bus->sprom.maxpwr_ah;
+ ofdmpo = bus->sprom.ofdm5ghpo;
+ lpphy->max_tx_pwr_hi_band = maxpwr;
+ for (i = 4; i < 12; i++) {
+ lpphy->tx_max_rateh[i] = maxpwr - (ofdmpo & 0xF) * 2;
+ ofdmpo >>= 4;
+ }
+ }
+}
+
+static void lpphy_adjust_gain_table(struct b43_wldev *dev, u32 freq)
+{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ u16 temp[3];
+ u16 isolation;
+
+ B43_WARN_ON(dev->phy.rev >= 2);
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ isolation = lpphy->tx_isolation_med_band;
+ else if (freq <= 5320)
+ isolation = lpphy->tx_isolation_low_band;
+ else if (freq <= 5700)
+ isolation = lpphy->tx_isolation_med_band;
+ else
+ isolation = lpphy->tx_isolation_hi_band;
+
+ temp[0] = ((isolation - 26) / 12) << 12;
+ temp[1] = temp[0] + 0x1000;
+ temp[2] = temp[0] + 0x2000;
+
+ b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), 3, temp);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp);
+}
+
static void lpphy_table_init(struct b43_wldev *dev)
{
- //TODO
+ u32 freq = channel2freq_lp(b43_lpphy_op_get_default_chan(dev));
+
+ if (dev->phy.rev < 2)
+ lpphy_rev0_1_table_init(dev);
+ else
+ lpphy_rev2plus_table_init(dev);
+
+ lpphy_init_tx_gain_table(dev);
+
+ if (dev->phy.rev < 2)
+ lpphy_adjust_gain_table(dev, freq);
}
static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
{
- B43_WARN_ON(1);//TODO rev < 2 not supported, yet.
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ u16 tmp, tmp2;
+
+ b43_phy_mask(dev, B43_LPPHY_AFE_DAC_CTL, 0xF7FF);
+ b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0);
+ b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, 0);
+ b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, 0);
+ b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0);
+ b43_phy_set(dev, B43_LPPHY_AFE_DAC_CTL, 0x0004);
+ b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x0078);
+ b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800);
+ b43_phy_write(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x0016);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_0, 0xFFF8, 0x0004);
+ b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5400);
+ b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2400);
+ b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100);
+ b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0x0006);
+ b43_phy_mask(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFFE);
+ b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x0005);
+ b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0x0180);
+ b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3C00);
+ b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFFF0, 0x0005);
+ b43_phy_maskset(dev, B43_LPPHY_GAIN_MISMATCH_LIMIT, 0xFFC0, 0x001A);
+ b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0x00B3);
+ b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00);
+ b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB,
+ 0xFF00, lpphy->rx_pwr_offset);
+ if ((bus->sprom.boardflags_lo & B43_BFL_FEM) &&
+ ((b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ||
+ (bus->sprom.boardflags_hi & B43_BFH_PAREF))) {
+ ssb_pmu_set_ldo_voltage(&bus->chipco, LDO_PAREF, 0x28);
+ ssb_pmu_set_ldo_paref(&bus->chipco, true);
+ if (dev->phy.rev == 0) {
+ b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
+ 0xFFCF, 0x0010);
+ }
+ b43_lptab_write(dev, B43_LPTAB16(11, 7), 60);
+ } else {
+ ssb_pmu_set_ldo_paref(&bus->chipco, false);
+ b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
+ 0xFFCF, 0x0020);
+ b43_lptab_write(dev, B43_LPTAB16(11, 7), 100);
+ }
+ tmp = lpphy->rssi_vf | lpphy->rssi_vc << 4 | 0xA000;
+ b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, tmp);
+ if (bus->sprom.boardflags_hi & B43_BFH_RSSIINV)
+ b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x0AAA);
+ else
+ b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x02AA);
+ b43_lptab_write(dev, B43_LPTAB16(11, 1), 24);
+ b43_phy_maskset(dev, B43_LPPHY_RX_RADIO_CTL,
+ 0xFFF9, (lpphy->bx_arch << 1));
+ if (dev->phy.rev == 1 &&
+ (bus->sprom.boardflags_hi & B43_BFH_FEM_BT)) {
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0x3F00, 0x0900);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0400);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0B00);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xC0FF, 0x0900);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xC0FF, 0x0B00);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xC0FF, 0x0900);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xC0FF, 0x0B00);
+ } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ ||
+ (bus->boardinfo.type == 0x048A) || ((dev->phy.rev == 0) &&
+ (bus->sprom.boardflags_lo & B43_BFL_FEM))) {
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0001);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0400);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0001);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0500);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0800);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0A00);
+ } else if (dev->phy.rev == 1 ||
+ (bus->sprom.boardflags_lo & B43_BFL_FEM)) {
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0004);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0800);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0004);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0C00);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0100);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0300);
+ } else {
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0900);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0006);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0500);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700);
+ }
+ if (dev->phy.rev == 1 && (bus->sprom.boardflags_hi & B43_BFH_PAREF)) {
+ b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1);
+ b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2);
+ b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3);
+ b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_8, B43_LPPHY_TR_LOOKUP_4);
+ }
+ if ((bus->sprom.boardflags_hi & B43_BFH_FEM_BT) &&
+ (bus->chip_id == 0x5354) &&
+ (bus->chip_package == SSB_CHIPPACK_BCM4712S)) {
+ b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006);
+ b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005);
+ b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF);
+ //FIXME the Broadcom driver caches & delays this HF write!
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_PR45960W);
+ }
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000);
+ b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0040);
+ b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0xA400);
+ b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xF0FF, 0x0B00);
+ b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x0007);
+ b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFF8, 0x0003);
+ b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFC7, 0x0020);
+ b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF);
+ } else { /* 5GHz */
+ b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0x7FFF);
+ b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFBF);
+ }
+ if (dev->phy.rev == 1) {
+ tmp = b43_phy_read(dev, B43_LPPHY_CLIPCTRTHRESH);
+ tmp2 = (tmp & 0x03E0) >> 5;
+ tmp2 |= tmp2 << 5;
+ b43_phy_write(dev, B43_LPPHY_4C3, tmp2);
+ tmp = b43_phy_read(dev, B43_LPPHY_GAINDIRECTMISMATCH);
+ tmp2 = (tmp & 0x1F00) >> 8;
+ tmp2 |= tmp2 << 5;
+ b43_phy_write(dev, B43_LPPHY_4C4, tmp2);
+ tmp = b43_phy_read(dev, B43_LPPHY_VERYLOWGAINDB);
+ tmp2 = tmp & 0x00FF;
+ tmp2 |= tmp << 8;
+ b43_phy_write(dev, B43_LPPHY_4C5, tmp2);
+ }
+}
+
+static void lpphy_save_dig_flt_state(struct b43_wldev *dev)
+{
+ static const u16 addr[] = {
+ B43_PHY_OFDM(0xC1),
+ B43_PHY_OFDM(0xC2),
+ B43_PHY_OFDM(0xC3),
+ B43_PHY_OFDM(0xC4),
+ B43_PHY_OFDM(0xC5),
+ B43_PHY_OFDM(0xC6),
+ B43_PHY_OFDM(0xC7),
+ B43_PHY_OFDM(0xC8),
+ B43_PHY_OFDM(0xCF),
+ };
+
+ static const u16 coefs[] = {
+ 0xDE5E, 0xE832, 0xE331, 0x4D26,
+ 0x0026, 0x1420, 0x0020, 0xFE08,
+ 0x0008,
+ };
+
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(addr); i++) {
+ lpphy->dig_flt_state[i] = b43_phy_read(dev, addr[i]);
+ b43_phy_write(dev, addr[i], coefs[i]);
+ }
+}
+
+static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
+{
+ static const u16 addr[] = {
+ B43_PHY_OFDM(0xC1),
+ B43_PHY_OFDM(0xC2),
+ B43_PHY_OFDM(0xC3),
+ B43_PHY_OFDM(0xC4),
+ B43_PHY_OFDM(0xC5),
+ B43_PHY_OFDM(0xC6),
+ B43_PHY_OFDM(0xC7),
+ B43_PHY_OFDM(0xC8),
+ B43_PHY_OFDM(0xCF),
+ };
+
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(addr); i++)
+ b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]);
}
static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
@@ -83,7 +414,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
b43_phy_write(dev, B43_PHY_OFDM(0xF9), 0);
b43_phy_write(dev, B43_LPPHY_TR_LOOKUP_1, 0);
b43_phy_set(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x10);
- b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x78);
+ b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0xB4);
b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xF8FF, 0x200);
b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xFF00, 0x7F);
b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFF0F, 0x40);
@@ -91,7 +422,12 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x4000);
b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x2000);
b43_phy_set(dev, B43_PHY_OFDM(0x10A), 0x1);
- b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10);
+ if (bus->boardinfo.rev >= 0x18) {
+ b43_lptab_write(dev, B43_LPTAB32(17, 65), 0xEC);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x14);
+ } else {
+ b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10);
+ }
b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0xFF00, 0xF4);
b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0x00FF, 0xF100);
b43_phy_write(dev, B43_LPPHY_CLIPTHRESH, 0x48);
@@ -100,7 +436,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
b43_phy_maskset(dev, B43_LPPHY_PWR_THRESH1, 0xFFF0, 0x9);
b43_phy_mask(dev, B43_LPPHY_GAINDIRECTMISMATCH, ~0xF);
b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5500);
- b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xF81F, 0xA0);
+ b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0xA0);
b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xE0FF, 0x300);
b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2A00);
if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
@@ -121,8 +457,10 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12);
b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000);
- b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0);
- b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40);
+ if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
+ b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0);
+ b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40);
+ }
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x40);
@@ -130,6 +468,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x6);
b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0x9D00);
b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0xFF00, 0xA1);
+ b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF);
} else /* 5GHz */
b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x40);
@@ -142,6 +481,14 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_1,
0x2000 | ((u16)lpphy->rssi_gs << 10) |
((u16)lpphy->rssi_vc << 4) | lpphy->rssi_vf);
+
+ if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
+ b43_phy_set(dev, B43_LPPHY_AFE_ADC_CTL_0, 0x1C);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_CTL, 0x00FF, 0x8800);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_1, 0xFC3C, 0x0400);
+ }
+
+ lpphy_save_dig_flt_state(dev);
}
static void lpphy_baseband_init(struct b43_wldev *dev)
@@ -161,8 +508,9 @@ struct b2062_freqdata {
/* Initialize the 2062 radio. */
static void lpphy_2062_init(struct b43_wldev *dev)
{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
struct ssb_bus *bus = dev->dev->bus;
- u32 crystalfreq, pdiv, tmp, ref;
+ u32 crystalfreq, tmp, ref;
unsigned int i;
const struct b2062_freqdata *fd = NULL;
@@ -186,10 +534,15 @@ static void lpphy_2062_init(struct b43_wldev *dev)
b43_radio_write(dev, B2062_N_TX_CTL3, 0);
b43_radio_write(dev, B2062_N_TX_CTL4, 0);
b43_radio_write(dev, B2062_N_TX_CTL5, 0);
+ b43_radio_write(dev, B2062_N_TX_CTL6, 0);
b43_radio_write(dev, B2062_N_PDN_CTL0, 0x40);
b43_radio_write(dev, B2062_N_PDN_CTL0, 0);
b43_radio_write(dev, B2062_N_CALIB_TS, 0x10);
b43_radio_write(dev, B2062_N_CALIB_TS, 0);
+ if (dev->phy.rev > 0) {
+ b43_radio_write(dev, B2062_S_BG_CTL1,
+ (b43_radio_read(dev, B2062_N_COMM2) >> 1) | 0x80);
+ }
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
b43_radio_set(dev, B2062_N_TSSI_CTL0, 0x1);
else
@@ -201,23 +554,27 @@ static void lpphy_2062_init(struct b43_wldev *dev)
B43_WARN_ON(!(bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU));
B43_WARN_ON(crystalfreq == 0);
- if (crystalfreq >= 30000000) {
- pdiv = 1;
+ if (crystalfreq <= 30000000) {
+ lpphy->pdiv = 1;
b43_radio_mask(dev, B2062_S_RFPLL_CTL1, 0xFFFB);
} else {
- pdiv = 2;
+ lpphy->pdiv = 2;
b43_radio_set(dev, B2062_S_RFPLL_CTL1, 0x4);
}
- tmp = (800000000 * pdiv + crystalfreq) / (32000000 * pdiv);
- tmp = (tmp - 1) & 0xFF;
+ tmp = (((800000000 * lpphy->pdiv + crystalfreq) /
+ (2 * crystalfreq)) - 8) & 0xFF;
+ b43_radio_write(dev, B2062_S_RFPLL_CTL7, tmp);
+
+ tmp = (((100 * crystalfreq + 16000000 * lpphy->pdiv) /
+ (32000000 * lpphy->pdiv)) - 1) & 0xFF;
b43_radio_write(dev, B2062_S_RFPLL_CTL18, tmp);
- tmp = (2 * crystalfreq + 1000000 * pdiv) / (2000000 * pdiv);
- tmp = ((tmp & 0xFF) - 1) & 0xFFFF;
+ tmp = (((2 * crystalfreq + 1000000 * lpphy->pdiv) /
+ (2000000 * lpphy->pdiv)) - 1) & 0xFF;
b43_radio_write(dev, B2062_S_RFPLL_CTL19, tmp);
- ref = (1000 * pdiv + 2 * crystalfreq) / (2000 * pdiv);
+ ref = (1000 * lpphy->pdiv + 2 * crystalfreq) / (2000 * lpphy->pdiv);
ref &= 0xFFFF;
for (i = 0; i < ARRAY_SIZE(freqdata_tab); i++) {
if (ref < freqdata_tab[i].freq) {
@@ -241,12 +598,78 @@ static void lpphy_2062_init(struct b43_wldev *dev)
/* Initialize the 2063 radio. */
static void lpphy_2063_init(struct b43_wldev *dev)
{
- //TODO
+ b2063_upload_init_table(dev);
+ b43_radio_write(dev, B2063_LOGEN_SP5, 0);
+ b43_radio_set(dev, B2063_COMM8, 0x38);
+ b43_radio_write(dev, B2063_REG_SP1, 0x56);
+ b43_radio_mask(dev, B2063_RX_BB_CTL2, ~0x2);
+ b43_radio_write(dev, B2063_PA_SP7, 0);
+ b43_radio_write(dev, B2063_TX_RF_SP6, 0x20);
+ b43_radio_write(dev, B2063_TX_RF_SP9, 0x40);
+ if (dev->phy.rev == 2) {
+ b43_radio_write(dev, B2063_PA_SP3, 0xa0);
+ b43_radio_write(dev, B2063_PA_SP4, 0xa0);
+ b43_radio_write(dev, B2063_PA_SP2, 0x18);
+ } else {
+ b43_radio_write(dev, B2063_PA_SP3, 0x20);
+ b43_radio_write(dev, B2063_PA_SP2, 0x20);
+ }
}
+struct lpphy_stx_table_entry {
+ u16 phy_offset;
+ u16 phy_shift;
+ u16 rf_addr;
+ u16 rf_shift;
+ u16 mask;
+};
+
+static const struct lpphy_stx_table_entry lpphy_stx_table[] = {
+ { .phy_offset = 2, .phy_shift = 6, .rf_addr = 0x3d, .rf_shift = 3, .mask = 0x01, },
+ { .phy_offset = 1, .phy_shift = 12, .rf_addr = 0x4c, .rf_shift = 1, .mask = 0x01, },
+ { .phy_offset = 1, .phy_shift = 8, .rf_addr = 0x50, .rf_shift = 0, .mask = 0x7f, },
+ { .phy_offset = 0, .phy_shift = 8, .rf_addr = 0x44, .rf_shift = 0, .mask = 0xff, },
+ { .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4a, .rf_shift = 0, .mask = 0xff, },
+ { .phy_offset = 0, .phy_shift = 4, .rf_addr = 0x4d, .rf_shift = 0, .mask = 0xff, },
+ { .phy_offset = 1, .phy_shift = 4, .rf_addr = 0x4e, .rf_shift = 0, .mask = 0xff, },
+ { .phy_offset = 0, .phy_shift = 12, .rf_addr = 0x4f, .rf_shift = 0, .mask = 0x0f, },
+ { .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4f, .rf_shift = 4, .mask = 0x0f, },
+ { .phy_offset = 3, .phy_shift = 0, .rf_addr = 0x49, .rf_shift = 0, .mask = 0x0f, },
+ { .phy_offset = 4, .phy_shift = 3, .rf_addr = 0x46, .rf_shift = 4, .mask = 0x07, },
+ { .phy_offset = 3, .phy_shift = 15, .rf_addr = 0x46, .rf_shift = 0, .mask = 0x01, },
+ { .phy_offset = 4, .phy_shift = 0, .rf_addr = 0x46, .rf_shift = 1, .mask = 0x07, },
+ { .phy_offset = 3, .phy_shift = 8, .rf_addr = 0x48, .rf_shift = 4, .mask = 0x07, },
+ { .phy_offset = 3, .phy_shift = 11, .rf_addr = 0x48, .rf_shift = 0, .mask = 0x0f, },
+ { .phy_offset = 3, .phy_shift = 4, .rf_addr = 0x49, .rf_shift = 4, .mask = 0x0f, },
+ { .phy_offset = 2, .phy_shift = 15, .rf_addr = 0x45, .rf_shift = 0, .mask = 0x01, },
+ { .phy_offset = 5, .phy_shift = 13, .rf_addr = 0x52, .rf_shift = 4, .mask = 0x07, },
+ { .phy_offset = 6, .phy_shift = 0, .rf_addr = 0x52, .rf_shift = 7, .mask = 0x01, },
+ { .phy_offset = 5, .phy_shift = 3, .rf_addr = 0x41, .rf_shift = 5, .mask = 0x07, },
+ { .phy_offset = 5, .phy_shift = 6, .rf_addr = 0x41, .rf_shift = 0, .mask = 0x0f, },
+ { .phy_offset = 5, .phy_shift = 10, .rf_addr = 0x42, .rf_shift = 5, .mask = 0x07, },
+ { .phy_offset = 4, .phy_shift = 15, .rf_addr = 0x42, .rf_shift = 0, .mask = 0x01, },
+ { .phy_offset = 5, .phy_shift = 0, .rf_addr = 0x42, .rf_shift = 1, .mask = 0x07, },
+ { .phy_offset = 4, .phy_shift = 11, .rf_addr = 0x43, .rf_shift = 4, .mask = 0x0f, },
+ { .phy_offset = 4, .phy_shift = 7, .rf_addr = 0x43, .rf_shift = 0, .mask = 0x0f, },
+ { .phy_offset = 4, .phy_shift = 6, .rf_addr = 0x45, .rf_shift = 1, .mask = 0x01, },
+ { .phy_offset = 2, .phy_shift = 7, .rf_addr = 0x40, .rf_shift = 4, .mask = 0x0f, },
+ { .phy_offset = 2, .phy_shift = 11, .rf_addr = 0x40, .rf_shift = 0, .mask = 0x0f, },
+};
+
static void lpphy_sync_stx(struct b43_wldev *dev)
{
- //TODO
+ const struct lpphy_stx_table_entry *e;
+ unsigned int i;
+ u16 tmp;
+
+ for (i = 0; i < ARRAY_SIZE(lpphy_stx_table); i++) {
+ e = &lpphy_stx_table[i];
+ tmp = b43_radio_read(dev, e->rf_addr);
+ tmp >>= e->rf_shift;
+ tmp <<= e->phy_shift;
+ b43_phy_maskset(dev, B43_PHY_OFDM(0xF2 + e->phy_offset),
+ ~(e->mask << e->phy_shift), tmp);
+ }
}
static void lpphy_radio_init(struct b43_wldev *dev)
@@ -257,17 +680,381 @@ static void lpphy_radio_init(struct b43_wldev *dev)
b43_phy_mask(dev, B43_LPPHY_FOURWIRE_CTL, 0xFFFD);
udelay(1);
- if (dev->phy.rev < 2) {
+ if (dev->phy.radio_ver == 0x2062) {
lpphy_2062_init(dev);
} else {
lpphy_2063_init(dev);
lpphy_sync_stx(dev);
b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80);
b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0);
- //TODO Do something on the backplane
+ if (dev->dev->bus->chip_id == 0x4325) {
+ // TODO SSB PMU recalibration
+ }
+ }
+}
+
+struct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; };
+
+static void lpphy_set_rc_cap(struct b43_wldev *dev)
+{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+
+ u8 rc_cap = (lpphy->rc_cap & 0x1F) >> 1;
+
+ if (dev->phy.rev == 1) //FIXME check channel 14!
+ rc_cap = min_t(u8, rc_cap + 5, 15);
+
+ b43_radio_write(dev, B2062_N_RXBB_CALIB2,
+ max_t(u8, lpphy->rc_cap - 4, 0x80));
+ b43_radio_write(dev, B2062_N_TX_CTL_A, rc_cap | 0x80);
+ b43_radio_write(dev, B2062_S_RXG_CNT16,
+ ((lpphy->rc_cap & 0x1F) >> 2) | 0x80);
+}
+
+static u8 lpphy_get_bb_mult(struct b43_wldev *dev)
+{
+ return (b43_lptab_read(dev, B43_LPTAB16(0, 87)) & 0xFF00) >> 8;
+}
+
+static void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult)
+{
+ b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8);
+}
+
+static void lpphy_set_deaf(struct b43_wldev *dev, bool user)
+{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+
+ if (user)
+ lpphy->crs_usr_disable = 1;
+ else
+ lpphy->crs_sys_disable = 1;
+ b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80);
+}
+
+static void lpphy_clear_deaf(struct b43_wldev *dev, bool user)
+{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+
+ if (user)
+ lpphy->crs_usr_disable = 0;
+ else
+ lpphy->crs_sys_disable = 0;
+
+ if (!lpphy->crs_usr_disable && !lpphy->crs_sys_disable) {
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL,
+ 0xFF1F, 0x60);
+ else
+ b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL,
+ 0xFF1F, 0x20);
}
}
+static void lpphy_disable_crs(struct b43_wldev *dev, bool user)
+{
+ lpphy_set_deaf(dev, user);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x1);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFF7);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x10);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFDF);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFBF);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x7);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x38);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x100);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFDFF);
+ b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL0, 0);
+ b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL1, 1);
+ b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL2, 0x20);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFBFF);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xF7FF);
+ b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
+ b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45AF);
+ b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF);
+}
+
+static void lpphy_restore_crs(struct b43_wldev *dev, bool user)
+{
+ lpphy_clear_deaf(dev, user);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00);
+}
+
+struct lpphy_tx_gains { u16 gm, pga, pad, dac; };
+
+static struct lpphy_tx_gains lpphy_get_tx_gains(struct b43_wldev *dev)
+{
+ struct lpphy_tx_gains gains;
+ u16 tmp;
+
+ gains.dac = (b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0x380) >> 7;
+ if (dev->phy.rev < 2) {
+ tmp = b43_phy_read(dev,
+ B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7FF;
+ gains.gm = tmp & 0x0007;
+ gains.pga = (tmp & 0x0078) >> 3;
+ gains.pad = (tmp & 0x780) >> 7;
+ } else {
+ tmp = b43_phy_read(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL);
+ gains.pad = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0xFF;
+ gains.gm = tmp & 0xFF;
+ gains.pga = (tmp >> 8) & 0xFF;
+ }
+
+ return gains;
+}
+
+static void lpphy_set_dac_gain(struct b43_wldev *dev, u16 dac)
+{
+ u16 ctl = b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0xC7F;
+ ctl |= dac << 7;
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DAC_CTL, 0xF000, ctl);
+}
+
+static void lpphy_set_tx_gains(struct b43_wldev *dev,
+ struct lpphy_tx_gains gains)
+{
+ u16 rf_gain, pa_gain;
+
+ if (dev->phy.rev < 2) {
+ rf_gain = (gains.pad << 7) | (gains.pga << 3) | gains.gm;
+ b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
+ 0xF800, rf_gain);
+ } else {
+ pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x1FC0;
+ pa_gain <<= 2;
+ b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
+ (gains.pga << 8) | gains.gm);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0xFB),
+ 0x8000, gains.pad | pa_gain);
+ b43_phy_write(dev, B43_PHY_OFDM(0xFC),
+ (gains.pga << 8) | gains.gm);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0xFD),
+ 0x8000, gains.pad | pa_gain);
+ }
+ lpphy_set_dac_gain(dev, gains.dac);
+ if (dev->phy.rev < 2) {
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF, 1 << 8);
+ } else {
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14);
+ }
+ b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF, 1 << 6);
+}
+
+static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain)
+{
+ u16 trsw = gain & 0x1;
+ u16 lna = (gain & 0xFFFC) | ((gain & 0xC) >> 2);
+ u16 ext_lna = (gain & 2) >> 1;
+
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
+ 0xFBFF, ext_lna << 10);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
+ 0xF7FF, ext_lna << 11);
+ b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
+}
+
+static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain)
+{
+ u16 low_gain = gain & 0xFFFF;
+ u16 high_gain = (gain >> 16) & 0xF;
+ u16 ext_lna = (gain >> 21) & 0x1;
+ u16 trsw = ~(gain >> 20) & 0x1;
+ u16 tmp;
+
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
+ 0xFDFF, ext_lna << 9);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
+ 0xFBFF, ext_lna << 10);
+ b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF0, high_gain);
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ tmp = (gain >> 2) & 0x3;
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
+ 0xE7FF, tmp<<11);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0xE6), 0xFFE7, tmp << 3);
+ }
+}
+
+static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
+{
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF);
+ if (dev->phy.rev >= 2) {
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
+ b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7);
+ }
+ } else {
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
+ }
+}
+
+static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
+{
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
+ if (dev->phy.rev >= 2) {
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
+ b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8);
+ }
+ } else {
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200);
+ }
+}
+
+static void lpphy_set_rx_gain(struct b43_wldev *dev, u32 gain)
+{
+ if (dev->phy.rev < 2)
+ lpphy_rev0_1_set_rx_gain(dev, gain);
+ else
+ lpphy_rev2plus_set_rx_gain(dev, gain);
+ lpphy_enable_rx_gain_override(dev);
+}
+
+static void lpphy_set_rx_gain_by_index(struct b43_wldev *dev, u16 idx)
+{
+ u32 gain = b43_lptab_read(dev, B43_LPTAB16(12, idx));
+ lpphy_set_rx_gain(dev, gain);
+}
+
+static void lpphy_stop_ddfs(struct b43_wldev *dev)
+{
+ b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFD);
+ b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xFFDF);
+}
+
+static void lpphy_run_ddfs(struct b43_wldev *dev, int i_on, int q_on,
+ int incr1, int incr2, int scale_idx)
+{
+ lpphy_stop_ddfs(dev);
+ b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0xFF80);
+ b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0x80FF);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0xFF80, incr1);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0x80FF, incr2 << 8);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF7, i_on << 3);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFEF, q_on << 4);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFF9F, scale_idx << 5);
+ b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFB);
+ b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x2);
+ b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x20);
+}
+
+static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time,
+ struct lpphy_iq_est *iq_est)
+{
+ int i;
+
+ b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFF7);
+ b43_phy_write(dev, B43_LPPHY_IQ_NUM_SMPLS_ADDR, samples);
+ b43_phy_maskset(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFF00, time);
+ b43_phy_mask(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFEFF);
+ b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
+
+ for (i = 0; i < 500; i++) {
+ if (!(b43_phy_read(dev,
+ B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
+ break;
+ msleep(1);
+ }
+
+ if ((b43_phy_read(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
+ b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
+ return false;
+ }
+
+ iq_est->iq_prod = b43_phy_read(dev, B43_LPPHY_IQ_ACC_HI_ADDR);
+ iq_est->iq_prod <<= 16;
+ iq_est->iq_prod |= b43_phy_read(dev, B43_LPPHY_IQ_ACC_LO_ADDR);
+
+ iq_est->i_pwr = b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_HI_ADDR);
+ iq_est->i_pwr <<= 16;
+ iq_est->i_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_LO_ADDR);
+
+ iq_est->q_pwr = b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_HI_ADDR);
+ iq_est->q_pwr <<= 16;
+ iq_est->q_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_LO_ADDR);
+
+ b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
+ return true;
+}
+
+static int lpphy_loopback(struct b43_wldev *dev)
+{
+ struct lpphy_iq_est iq_est;
+ int i, index = -1;
+ u32 tmp;
+
+ memset(&iq_est, 0, sizeof(iq_est));
+
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x3);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
+ b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 1);
+ b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x8);
+ b43_radio_write(dev, B2062_N_TX_CTL_A, 0x80);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x80);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x80);
+ for (i = 0; i < 32; i++) {
+ lpphy_set_rx_gain_by_index(dev, i);
+ lpphy_run_ddfs(dev, 1, 1, 5, 5, 0);
+ if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
+ continue;
+ tmp = (iq_est.i_pwr + iq_est.q_pwr) / 1000;
+ if ((tmp > 4000) && (tmp < 10000)) {
+ index = i;
+ break;
+ }
+ }
+ lpphy_stop_ddfs(dev);
+ return index;
+}
+
+/* Fixed-point division algorithm using only integer math. */
+static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
+{
+ u32 quotient, remainder;
+
+ if (divisor == 0)
+ return 0;
+
+ quotient = dividend / divisor;
+ remainder = dividend % divisor;
+
+ while (precision > 0) {
+ quotient <<= 1;
+ if (remainder << 1 >= divisor) {
+ quotient++;
+ remainder = (remainder << 1) - divisor;
+ }
+ precision--;
+ }
+
+ if (remainder << 1 >= divisor)
+ quotient++;
+
+ return quotient;
+}
+
/* Read the TX power control mode from hardware. */
static void lpphy_read_tx_pctl_mode_from_hardware(struct b43_wldev *dev)
{
@@ -322,9 +1109,9 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev,
struct b43_phy_lp *lpphy = dev->phy.lp;
enum b43_lpphy_txpctl_mode oldmode;
- oldmode = lpphy->txpctl_mode;
lpphy_read_tx_pctl_mode_from_hardware(dev);
- if (lpphy->txpctl_mode == mode)
+ oldmode = lpphy->txpctl_mode;
+ if (oldmode == mode)
return;
lpphy->txpctl_mode = mode;
@@ -345,13 +1132,186 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev,
}
if (dev->phy.rev >= 2) {
if (mode == B43_LPPHY_TXPCTL_HW)
- b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0x2);
+ b43_phy_set(dev, B43_PHY_OFDM(0xD0), 0x2);
else
- b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0);
+ b43_phy_mask(dev, B43_PHY_OFDM(0xD0), 0xFFFD);
}
lpphy_write_tx_pctl_mode_to_hardware(dev);
}
+static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
+ unsigned int new_channel);
+
+static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev)
+{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ struct lpphy_iq_est iq_est;
+ struct lpphy_tx_gains tx_gains;
+ static const u32 ideal_pwr_table[21] = {
+ 0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
+ 0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
+ 0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
+ 0x0004c, 0x0002c, 0x0001a,
+ };
+ bool old_txg_ovr;
+ u8 old_bbmult;
+ u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval,
+ old_rf2_ovr, old_rf2_ovrval, old_phy_ctl;
+ enum b43_lpphy_txpctl_mode old_txpctl;
+ u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0;
+ int loopback, i, j, inner_sum, err;
+
+ memset(&iq_est, 0, sizeof(iq_est));
+
+ err = b43_lpphy_op_switch_channel(dev, 7);
+ if (err) {
+ b43dbg(dev->wl,
+ "RC calib: Failed to switch to channel 7, error = %d\n",
+ err);
+ }
+ old_txg_ovr = !!(b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40);
+ old_bbmult = lpphy_get_bb_mult(dev);
+ if (old_txg_ovr)
+ tx_gains = lpphy_get_tx_gains(dev);
+ old_rf_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_0);
+ old_rf_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_VAL_0);
+ old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR);
+ old_afe_ovrval = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVRVAL);
+ old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2);
+ old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL);
+ old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL);
+ lpphy_read_tx_pctl_mode_from_hardware(dev);
+ old_txpctl = lpphy->txpctl_mode;
+
+ lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
+ lpphy_disable_crs(dev, true);
+ loopback = lpphy_loopback(dev);
+ if (loopback == -1)
+ goto finish;
+ lpphy_set_rx_gain_by_index(dev, loopback);
+ b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFFBF, 0x40);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFF8, 0x1);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFC7, 0x8);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F, 0xC0);
+ for (i = 128; i <= 159; i++) {
+ b43_radio_write(dev, B2062_N_RXBB_CALIB2, i);
+ inner_sum = 0;
+ for (j = 5; j <= 25; j++) {
+ lpphy_run_ddfs(dev, 1, 1, j, j, 0);
+ if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
+ goto finish;
+ mean_sq_pwr = iq_est.i_pwr + iq_est.q_pwr;
+ if (j == 5)
+ tmp = mean_sq_pwr;
+ ideal_pwr = ((ideal_pwr_table[j-5] >> 3) + 1) >> 1;
+ normal_pwr = lpphy_qdiv_roundup(mean_sq_pwr, tmp, 12);
+ mean_sq_pwr = ideal_pwr - normal_pwr;
+ mean_sq_pwr *= mean_sq_pwr;
+ inner_sum += mean_sq_pwr;
+ if ((i == 128) || (inner_sum < mean_sq_pwr_min)) {
+ lpphy->rc_cap = i;
+ mean_sq_pwr_min = inner_sum;
+ }
+ }
+ }
+ lpphy_stop_ddfs(dev);
+
+finish:
+ lpphy_restore_crs(dev, true);
+ b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval);
+ b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr);
+ b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval);
+ b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, old_afe_ovr);
+ b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, old_rf2_ovrval);
+ b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, old_rf2_ovr);
+ b43_phy_write(dev, B43_LPPHY_LP_PHY_CTL, old_phy_ctl);
+
+ lpphy_set_bb_mult(dev, old_bbmult);
+ if (old_txg_ovr) {
+ /*
+ * SPEC FIXME: The specs say "get_tx_gains" here, which is
+ * illogical. According to lwfinger, vendor driver v4.150.10.5
+ * has a Set here, while v4.174.64.19 has a Get - regression in
+ * the vendor driver? This should be tested this once the code
+ * is testable.
+ */
+ lpphy_set_tx_gains(dev, tx_gains);
+ }
+ lpphy_set_tx_power_control(dev, old_txpctl);
+ if (lpphy->rc_cap)
+ lpphy_set_rc_cap(dev);
+}
+
+static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
+ u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF;
+ int i;
+
+ b43_radio_write(dev, B2063_RX_BB_SP8, 0x0);
+ b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
+ b43_radio_mask(dev, B2063_PLL_SP1, 0xF7);
+ b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C);
+ b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x15);
+ b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x70);
+ b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x52);
+ b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1);
+ b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7D);
+
+ for (i = 0; i < 10000; i++) {
+ if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)
+ break;
+ msleep(1);
+ }
+
+ if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2))
+ b43_radio_write(dev, B2063_RX_BB_SP8, tmp);
+
+ tmp = b43_radio_read(dev, B2063_TX_BB_SP3) & 0xFF;
+
+ b43_radio_write(dev, B2063_TX_BB_SP3, 0x0);
+ b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
+ b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C);
+ b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x55);
+ b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x76);
+
+ if (crystal_freq == 24000000) {
+ b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0xFC);
+ b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x0);
+ } else {
+ b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x13);
+ b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1);
+ }
+
+ b43_radio_write(dev, B2063_PA_SP7, 0x7D);
+
+ for (i = 0; i < 10000; i++) {
+ if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)
+ break;
+ msleep(1);
+ }
+
+ if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2))
+ b43_radio_write(dev, B2063_TX_BB_SP3, tmp);
+
+ b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
+}
+
+static void lpphy_calibrate_rc(struct b43_wldev *dev)
+{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+
+ if (dev->phy.rev >= 2) {
+ lpphy_rev2plus_rc_calib(dev);
+ } else if (!lpphy->rc_cap) {
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ lpphy_rev0_1_rc_calib(dev);
+ } else {
+ lpphy_set_rc_cap(dev);
+ }
+}
+
static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index)
{
struct b43_phy_lp *lpphy = dev->phy.lp;
@@ -423,32 +1383,110 @@ static void lpphy_calibration(struct b43_wldev *dev)
b43_mac_enable(dev);
}
-/* Initialize TX power control */
-static void lpphy_tx_pctl_init(struct b43_wldev *dev)
+static void lpphy_set_tssi_mux(struct b43_wldev *dev, enum tssi_mux_mode mode)
{
- if (0/*FIXME HWPCTL capable */) {
- //TODO
- } else { /* This device is only software TX power control capable. */
- if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
- //TODO
+ if (mode != TSSI_MUX_EXT) {
+ b43_radio_set(dev, B2063_PA_SP1, 0x2);
+ b43_phy_set(dev, B43_PHY_OFDM(0xF3), 0x1000);
+ b43_radio_write(dev, B2063_PA_CTL10, 0x51);
+ if (mode == TSSI_MUX_POSTPA) {
+ b43_radio_mask(dev, B2063_PA_SP1, 0xFFFE);
+ b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFC7);
} else {
- //TODO
+ b43_radio_maskset(dev, B2063_PA_SP1, 0xFFFE, 0x1);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVRVAL,
+ 0xFFC7, 0x20);
}
- //TODO set BB multiplier to 0x0096
+ } else {
+ B43_WARN_ON(1);
}
}
-static int b43_lpphy_op_init(struct b43_wldev *dev)
+static void lpphy_tx_pctl_init_hw(struct b43_wldev *dev)
{
- /* TODO: band SPROM */
- lpphy_baseband_init(dev);
- lpphy_radio_init(dev);
- //TODO calibrate RC
- //TODO set channel
- lpphy_tx_pctl_init(dev);
- //TODO full calib
+ u16 tmp;
+ int i;
- return 0;
+ //SPEC TODO Call LP PHY Clear TX Power offsets
+ for (i = 0; i < 64; i++) {
+ if (dev->phy.rev >= 2)
+ b43_lptab_write(dev, B43_LPTAB32(7, i + 1), i);
+ else
+ b43_lptab_write(dev, B43_LPTAB32(10, i + 1), i);
+ }
+
+ b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xFF00, 0xFF);
+ b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0x8FFF, 0x5000);
+ b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0xFFC0, 0x1F);
+ if (dev->phy.rev < 2) {
+ b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xEFFF);
+ b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xDFFF, 0x2000);
+ } else {
+ b43_phy_mask(dev, B43_PHY_OFDM(0x103), 0xFFFE);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFFB, 0x4);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFEF, 0x10);
+ b43_radio_maskset(dev, B2063_IQ_CALIB_CTL2, 0xF3, 0x1);
+ lpphy_set_tssi_mux(dev, TSSI_MUX_POSTPA);
+ }
+ b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0x7FFF, 0x8000);
+ b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xFF);
+ b43_phy_write(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xA);
+ b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
+ (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE,
+ B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF);
+ b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xF8FF);
+ b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
+ (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE,
+ B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW);
+
+ if (dev->phy.rev < 2) {
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF, 0x1000);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xEFFF);
+ } else {
+ lpphy_set_tx_power_by_index(dev, 0x7F);
+ }
+
+ b43_dummy_transmission(dev, true, true);
+
+ tmp = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_STAT);
+ if (tmp & 0x8000) {
+ b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI,
+ 0xFFC0, (tmp & 0xFF) - 32);
+ }
+
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF);
+
+ // (SPEC?) TODO Set "Target TX frequency" variable to 0
+ // SPEC FIXME "Set BB Multiplier to 0xE000" impossible - bb_mult is u8!
+}
+
+static void lpphy_tx_pctl_init_sw(struct b43_wldev *dev)
+{
+ struct lpphy_tx_gains gains;
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ gains.gm = 4;
+ gains.pad = 12;
+ gains.pga = 12;
+ gains.dac = 0;
+ } else {
+ gains.gm = 7;
+ gains.pad = 14;
+ gains.pga = 15;
+ gains.dac = 0;
+ }
+ lpphy_set_tx_gains(dev, gains);
+ lpphy_set_bb_mult(dev, 150);
+}
+
+/* Initialize TX power control */
+static void lpphy_tx_pctl_init(struct b43_wldev *dev)
+{
+ if (0/*FIXME HWPCTL capable */) {
+ lpphy_tx_pctl_init_hw(dev);
+ } else { /* This device is only software TX power control capable. */
+ lpphy_tx_pctl_init_sw(dev);
+ }
}
static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg)
@@ -463,6 +1501,14 @@ static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
+static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
+ u16 set)
+{
+ b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_PHY_DATA,
+ (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
+}
+
static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg)
{
/* Register 1 is a 32-bit register. */
@@ -493,23 +1539,681 @@ static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
//TODO
}
+struct b206x_channel {
+ u8 channel;
+ u16 freq;
+ u8 data[12];
+};
+
+static const struct b206x_channel b2062_chantbl[] = {
+ { .channel = 1, .freq = 2412, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 2, .freq = 2417, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 3, .freq = 2422, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 4, .freq = 2427, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 5, .freq = 2432, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 6, .freq = 2437, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 7, .freq = 2442, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 8, .freq = 2447, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 9, .freq = 2452, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 10, .freq = 2457, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 11, .freq = 2462, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 12, .freq = 2467, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 13, .freq = 2472, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 14, .freq = 2484, .data[0] = 0xFF, .data[1] = 0xFF,
+ .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+ .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+ { .channel = 34, .freq = 5170, .data[0] = 0x00, .data[1] = 0x22,
+ .data[2] = 0x20, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 38, .freq = 5190, .data[0] = 0x00, .data[1] = 0x11,
+ .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 42, .freq = 5210, .data[0] = 0x00, .data[1] = 0x11,
+ .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 46, .freq = 5230, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 36, .freq = 5180, .data[0] = 0x00, .data[1] = 0x11,
+ .data[2] = 0x20, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 40, .freq = 5200, .data[0] = 0x00, .data[1] = 0x11,
+ .data[2] = 0x10, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 44, .freq = 5220, .data[0] = 0x00, .data[1] = 0x11,
+ .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 48, .freq = 5240, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 52, .freq = 5260, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 56, .freq = 5280, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 60, .freq = 5300, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x63, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 64, .freq = 5320, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x62, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 100, .freq = 5500, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x30, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 104, .freq = 5520, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 108, .freq = 5540, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 112, .freq = 5560, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 116, .freq = 5580, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x10, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 120, .freq = 5600, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 124, .freq = 5620, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 128, .freq = 5640, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 132, .freq = 5660, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 136, .freq = 5680, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 140, .freq = 5700, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 149, .freq = 5745, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 153, .freq = 5765, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 157, .freq = 5785, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 161, .freq = 5805, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 165, .freq = 5825, .data[0] = 0x00, .data[1] = 0x00,
+ .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 184, .freq = 4920, .data[0] = 0x55, .data[1] = 0x77,
+ .data[2] = 0x90, .data[3] = 0xF7, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+ { .channel = 188, .freq = 4940, .data[0] = 0x44, .data[1] = 0x77,
+ .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+ { .channel = 192, .freq = 4960, .data[0] = 0x44, .data[1] = 0x66,
+ .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+ { .channel = 196, .freq = 4980, .data[0] = 0x33, .data[1] = 0x66,
+ .data[2] = 0x70, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+ { .channel = 200, .freq = 5000, .data[0] = 0x22, .data[1] = 0x55,
+ .data[2] = 0x60, .data[3] = 0xD7, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+ { .channel = 204, .freq = 5020, .data[0] = 0x22, .data[1] = 0x55,
+ .data[2] = 0x60, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+ { .channel = 208, .freq = 5040, .data[0] = 0x22, .data[1] = 0x44,
+ .data[2] = 0x50, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+ { .channel = 212, .freq = 5060, .data[0] = 0x11, .data[1] = 0x44,
+ .data[2] = 0x50, .data[3] = 0xA5, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+ { .channel = 216, .freq = 5080, .data[0] = 0x00, .data[1] = 0x44,
+ .data[2] = 0x40, .data[3] = 0xB6, .data[4] = 0x3C, .data[5] = 0x77,
+ .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+};
+
+static const struct b206x_channel b2063_chantbl[] = {
+ { .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C,
+ .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 2, .freq = 2417, .data[0] = 0x6F, .data[1] = 0x3C,
+ .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 3, .freq = 2422, .data[0] = 0x6F, .data[1] = 0x3C,
+ .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 4, .freq = 2427, .data[0] = 0x6F, .data[1] = 0x2C,
+ .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 5, .freq = 2432, .data[0] = 0x6F, .data[1] = 0x2C,
+ .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 6, .freq = 2437, .data[0] = 0x6F, .data[1] = 0x2C,
+ .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 7, .freq = 2442, .data[0] = 0x6F, .data[1] = 0x2C,
+ .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 8, .freq = 2447, .data[0] = 0x6F, .data[1] = 0x2C,
+ .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 9, .freq = 2452, .data[0] = 0x6F, .data[1] = 0x1C,
+ .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 10, .freq = 2457, .data[0] = 0x6F, .data[1] = 0x1C,
+ .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 11, .freq = 2462, .data[0] = 0x6E, .data[1] = 0x1C,
+ .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 12, .freq = 2467, .data[0] = 0x6E, .data[1] = 0x1C,
+ .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 13, .freq = 2472, .data[0] = 0x6E, .data[1] = 0x1C,
+ .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 14, .freq = 2484, .data[0] = 0x6E, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+ .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x80, .data[11] = 0x70, },
+ { .channel = 34, .freq = 5170, .data[0] = 0x6A, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x02, .data[5] = 0x05,
+ .data[6] = 0x0D, .data[7] = 0x0D, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x20, .data[11] = 0x00, },
+ { .channel = 36, .freq = 5180, .data[0] = 0x6A, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x05,
+ .data[6] = 0x0D, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x20, .data[11] = 0x00, },
+ { .channel = 38, .freq = 5190, .data[0] = 0x6A, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
+ .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
+ .data[10] = 0x20, .data[11] = 0x00, },
+ { .channel = 40, .freq = 5200, .data[0] = 0x69, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
+ .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
+ .data[10] = 0x20, .data[11] = 0x00, },
+ { .channel = 42, .freq = 5210, .data[0] = 0x69, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
+ .data[6] = 0x0B, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
+ .data[10] = 0x20, .data[11] = 0x00, },
+ { .channel = 44, .freq = 5220, .data[0] = 0x69, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x04,
+ .data[6] = 0x0B, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
+ .data[10] = 0x20, .data[11] = 0x00, },
+ { .channel = 46, .freq = 5230, .data[0] = 0x69, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
+ .data[6] = 0x0A, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
+ .data[10] = 0x20, .data[11] = 0x00, },
+ { .channel = 48, .freq = 5240, .data[0] = 0x69, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
+ .data[6] = 0x0A, .data[7] = 0x0A, .data[8] = 0x77, .data[9] = 0x60,
+ .data[10] = 0x20, .data[11] = 0x00, },
+ { .channel = 52, .freq = 5260, .data[0] = 0x68, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x02,
+ .data[6] = 0x09, .data[7] = 0x09, .data[8] = 0x77, .data[9] = 0x60,
+ .data[10] = 0x20, .data[11] = 0x00, },
+ { .channel = 56, .freq = 5280, .data[0] = 0x68, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
+ .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
+ .data[10] = 0x10, .data[11] = 0x00, },
+ { .channel = 60, .freq = 5300, .data[0] = 0x68, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
+ .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
+ .data[10] = 0x10, .data[11] = 0x00, },
+ { .channel = 64, .freq = 5320, .data[0] = 0x67, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
+ .data[10] = 0x10, .data[11] = 0x00, },
+ { .channel = 100, .freq = 5500, .data[0] = 0x64, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x02, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 104, .freq = 5520, .data[0] = 0x64, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x01, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 108, .freq = 5540, .data[0] = 0x63, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x01, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 112, .freq = 5560, .data[0] = 0x63, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 116, .freq = 5580, .data[0] = 0x62, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 120, .freq = 5600, .data[0] = 0x62, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 124, .freq = 5620, .data[0] = 0x62, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 128, .freq = 5640, .data[0] = 0x61, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 132, .freq = 5660, .data[0] = 0x61, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 136, .freq = 5680, .data[0] = 0x61, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 140, .freq = 5700, .data[0] = 0x60, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 149, .freq = 5745, .data[0] = 0x60, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 153, .freq = 5765, .data[0] = 0x60, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 157, .freq = 5785, .data[0] = 0x60, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 161, .freq = 5805, .data[0] = 0x60, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 165, .freq = 5825, .data[0] = 0x60, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+ .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+ .data[10] = 0x00, .data[11] = 0x00, },
+ { .channel = 184, .freq = 4920, .data[0] = 0x6E, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0E,
+ .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xC0,
+ .data[10] = 0x50, .data[11] = 0x00, },
+ { .channel = 188, .freq = 4940, .data[0] = 0x6E, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0D,
+ .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
+ .data[10] = 0x50, .data[11] = 0x00, },
+ { .channel = 192, .freq = 4960, .data[0] = 0x6E, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
+ .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
+ .data[10] = 0x50, .data[11] = 0x00, },
+ { .channel = 196, .freq = 4980, .data[0] = 0x6D, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
+ .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
+ .data[10] = 0x40, .data[11] = 0x00, },
+ { .channel = 200, .freq = 5000, .data[0] = 0x6D, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0B,
+ .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
+ .data[10] = 0x40, .data[11] = 0x00, },
+ { .channel = 204, .freq = 5020, .data[0] = 0x6D, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0A,
+ .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
+ .data[10] = 0x40, .data[11] = 0x00, },
+ { .channel = 208, .freq = 5040, .data[0] = 0x6C, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x07, .data[5] = 0x09,
+ .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
+ .data[10] = 0x40, .data[11] = 0x00, },
+ { .channel = 212, .freq = 5060, .data[0] = 0x6C, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x06, .data[5] = 0x08,
+ .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
+ .data[10] = 0x40, .data[11] = 0x00, },
+ { .channel = 216, .freq = 5080, .data[0] = 0x6C, .data[1] = 0x0C,
+ .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x05, .data[5] = 0x08,
+ .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
+ .data[10] = 0x40, .data[11] = 0x00, },
+};
+
+static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+
+ b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF);
+ udelay(20);
+ if (bus->chip_id == 0x5354) {
+ b43_radio_write(dev, B2062_N_COMM1, 4);
+ b43_radio_write(dev, B2062_S_RFPLL_CTL2, 4);
+ } else {
+ b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0);
+ }
+ udelay(5);
+}
+
+static void lpphy_b2062_vco_calib(struct b43_wldev *dev)
+{
+ b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x42);
+ b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x62);
+ udelay(200);
+}
+
+static int lpphy_b2062_tune(struct b43_wldev *dev,
+ unsigned int channel)
+{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ struct ssb_bus *bus = dev->dev->bus;
+ const struct b206x_channel *chandata = NULL;
+ u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
+ u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
+ int i, err = 0;
+
+ for (i = 0; i < ARRAY_SIZE(b2062_chantbl); i++) {
+ if (b2062_chantbl[i].channel == channel) {
+ chandata = &b2062_chantbl[i];
+ break;
+ }
+ }
+
+ if (B43_WARN_ON(!chandata))
+ return -EINVAL;
+
+ b43_radio_set(dev, B2062_S_RFPLL_CTL14, 0x04);
+ b43_radio_write(dev, B2062_N_LGENA_TUNE0, chandata->data[0]);
+ b43_radio_write(dev, B2062_N_LGENA_TUNE2, chandata->data[1]);
+ b43_radio_write(dev, B2062_N_LGENA_TUNE3, chandata->data[2]);
+ b43_radio_write(dev, B2062_N_TX_TUNE, chandata->data[3]);
+ b43_radio_write(dev, B2062_S_LGENG_CTL1, chandata->data[4]);
+ b43_radio_write(dev, B2062_N_LGENA_CTL5, chandata->data[5]);
+ b43_radio_write(dev, B2062_N_LGENA_CTL6, chandata->data[6]);
+ b43_radio_write(dev, B2062_N_TX_PGA, chandata->data[7]);
+ b43_radio_write(dev, B2062_N_TX_PAD, chandata->data[8]);
+
+ tmp1 = crystal_freq / 1000;
+ tmp2 = lpphy->pdiv * 1000;
+ b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xCC);
+ b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0x07);
+ lpphy_b2062_reset_pll_bias(dev);
+ tmp3 = tmp2 * channel2freq_lp(channel);
+ if (channel2freq_lp(channel) < 4000)
+ tmp3 *= 2;
+ tmp4 = 48 * tmp1;
+ tmp6 = tmp3 / tmp4;
+ tmp7 = tmp3 % tmp4;
+ b43_radio_write(dev, B2062_S_RFPLL_CTL26, tmp6);
+ tmp5 = tmp7 * 0x100;
+ tmp6 = tmp5 / tmp4;
+ tmp7 = tmp5 % tmp4;
+ b43_radio_write(dev, B2062_S_RFPLL_CTL27, tmp6);
+ tmp5 = tmp7 * 0x100;
+ tmp6 = tmp5 / tmp4;
+ tmp7 = tmp5 % tmp4;
+ b43_radio_write(dev, B2062_S_RFPLL_CTL28, tmp6);
+ tmp5 = tmp7 * 0x100;
+ tmp6 = tmp5 / tmp4;
+ tmp7 = tmp5 % tmp4;
+ b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4));
+ tmp8 = b43_radio_read(dev, B2062_S_RFPLL_CTL19);
+ tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1);
+ b43_radio_write(dev, B2062_S_RFPLL_CTL23, (tmp9 >> 8) + 16);
+ b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF);
+
+ lpphy_b2062_vco_calib(dev);
+ if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) {
+ b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xFC);
+ b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0);
+ lpphy_b2062_reset_pll_bias(dev);
+ lpphy_b2062_vco_calib(dev);
+ if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10)
+ err = -EIO;
+ }
+
+ b43_radio_mask(dev, B2062_S_RFPLL_CTL14, ~0x04);
+ return err;
+}
+
+
+/* This was previously called lpphy_japan_filter */
+static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel)
+{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter!
+
+ if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific?
+ b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9);
+ if ((dev->phy.rev == 1) && (lpphy->rc_cap))
+ lpphy_set_rc_cap(dev);
+ } else {
+ b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F);
+ }
+}
+
+static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
+{
+ u16 tmp;
+
+ b43_radio_mask(dev, B2063_PLL_SP1, ~0x40);
+ tmp = b43_radio_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8;
+ b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp);
+ udelay(1);
+ b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4);
+ udelay(1);
+ b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6);
+ udelay(1);
+ b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7);
+ udelay(300);
+ b43_radio_set(dev, B2063_PLL_SP1, 0x40);
+}
+
+static int lpphy_b2063_tune(struct b43_wldev *dev,
+ unsigned int channel)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+
+ static const struct b206x_channel *chandata = NULL;
+ u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
+ u32 freqref, vco_freq, val1, val2, val3, timeout, timeoutref, count;
+ u16 old_comm15, scale;
+ u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+ int i, div = (crystal_freq <= 26000000 ? 1 : 2);
+
+ for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) {
+ if (b2063_chantbl[i].channel == channel) {
+ chandata = &b2063_chantbl[i];
+ break;
+ }
+ }
+
+ if (B43_WARN_ON(!chandata))
+ return -EINVAL;
+
+ b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]);
+ b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]);
+ b43_radio_write(dev, B2063_LOGEN_BUF2, chandata->data[2]);
+ b43_radio_write(dev, B2063_LOGEN_RCCR1, chandata->data[3]);
+ b43_radio_write(dev, B2063_A_RX_1ST3, chandata->data[4]);
+ b43_radio_write(dev, B2063_A_RX_2ND1, chandata->data[5]);
+ b43_radio_write(dev, B2063_A_RX_2ND4, chandata->data[6]);
+ b43_radio_write(dev, B2063_A_RX_2ND7, chandata->data[7]);
+ b43_radio_write(dev, B2063_A_RX_PS6, chandata->data[8]);
+ b43_radio_write(dev, B2063_TX_RF_CTL2, chandata->data[9]);
+ b43_radio_write(dev, B2063_TX_RF_CTL5, chandata->data[10]);
+ b43_radio_write(dev, B2063_PA_CTL11, chandata->data[11]);
+
+ old_comm15 = b43_radio_read(dev, B2063_COMM15);
+ b43_radio_set(dev, B2063_COMM15, 0x1E);
+
+ if (chandata->freq > 4000) /* spec says 2484, but 4000 is safer */
+ vco_freq = chandata->freq << 1;
+ else
+ vco_freq = chandata->freq << 2;
+
+ freqref = crystal_freq * 3;
+ val1 = lpphy_qdiv_roundup(crystal_freq, 1000000, 16);
+ val2 = lpphy_qdiv_roundup(crystal_freq, 1000000 * div, 16);
+ val3 = lpphy_qdiv_roundup(vco_freq, 3, 16);
+ timeout = ((((8 * crystal_freq) / (div * 5000000)) + 1) >> 1) - 1;
+ b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB3, 0x2);
+ b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB6,
+ 0xFFF8, timeout >> 2);
+ b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7,
+ 0xFF9F,timeout << 5);
+
+ timeoutref = ((((8 * crystal_freq) / (div * (timeout + 1))) +
+ 999999) / 1000000) + 1;
+ b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB5, timeoutref);
+
+ count = lpphy_qdiv_roundup(val3, val2 + 16, 16);
+ count *= (timeout + 1) * (timeoutref + 1);
+ count--;
+ b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7,
+ 0xF0, count >> 8);
+ b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB8, count & 0xFF);
+
+ tmp1 = ((val3 * 62500) / freqref) << 4;
+ tmp2 = ((val3 * 62500) % freqref) << 4;
+ while (tmp2 >= freqref) {
+ tmp1++;
+ tmp2 -= freqref;
+ }
+ b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG1, 0xFFE0, tmp1 >> 4);
+ b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFE0F, tmp1 << 4);
+ b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFFF0, tmp1 >> 16);
+ b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG3, (tmp2 >> 8) & 0xFF);
+ b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG4, tmp2 & 0xFF);
+
+ b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF1, 0xB9);
+ b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF2, 0x88);
+ b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF3, 0x28);
+ b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF4, 0x63);
+
+ tmp3 = ((41 * (val3 - 3000)) /1200) + 27;
+ tmp4 = lpphy_qdiv_roundup(132000 * tmp1, 8451, 16);
+
+ if ((tmp4 + tmp3 - 1) / tmp3 > 60) {
+ scale = 1;
+ tmp5 = ((tmp4 + tmp3) / (tmp3 << 1)) - 8;
+ } else {
+ scale = 0;
+ tmp5 = ((tmp4 + (tmp3 >> 1)) / tmp3) - 8;
+ }
+ b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5);
+ b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6);
+
+ tmp6 = lpphy_qdiv_roundup(100 * val1, val3, 16);
+ tmp6 *= (tmp5 * 8) * (scale + 1);
+ if (tmp6 > 150)
+ tmp6 = 0;
+
+ b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6);
+ b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5);
+
+ b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4);
+ if (crystal_freq > 26000000)
+ b43_radio_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2);
+ else
+ b43_radio_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD);
+
+ if (val1 == 45)
+ b43_radio_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2);
+ else
+ b43_radio_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD);
+
+ b43_radio_set(dev, B2063_PLL_SP2, 0x3);
+ udelay(1);
+ b43_radio_mask(dev, B2063_PLL_SP2, 0xFFFC);
+ lpphy_b2063_vco_calib(dev);
+ b43_radio_write(dev, B2063_COMM15, old_comm15);
+
+ return 0;
+}
+
static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
unsigned int new_channel)
{
- //TODO
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ int err;
+
+ if (dev->phy.radio_ver == 0x2063) {
+ err = lpphy_b2063_tune(dev, new_channel);
+ if (err)
+ return err;
+ } else {
+ err = lpphy_b2062_tune(dev, new_channel);
+ if (err)
+ return err;
+ lpphy_set_analog_filter(dev, new_channel);
+ lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel));
+ }
+
+ lpphy->channel = new_channel;
+ b43_write16(dev, B43_MMIO_CHANNEL, new_channel);
+
return 0;
}
-static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev)
+static int b43_lpphy_op_init(struct b43_wldev *dev)
{
- if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
- return 1;
- return 36;
+ int err;
+
+ lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs?
+ lpphy_baseband_init(dev);
+ lpphy_radio_init(dev);
+ lpphy_calibrate_rc(dev);
+ err = b43_lpphy_op_switch_channel(dev, 7);
+ if (err) {
+ b43dbg(dev->wl, "Switch to channel 7 failed, error = %d.\n",
+ err);
+ }
+ lpphy_tx_pctl_init(dev);
+ lpphy_calibration(dev);
+ //TODO ACI init
+
+ return 0;
}
static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
{
- //TODO
+ if (dev->phy.rev >= 2)
+ return; // rev2+ doesn't support antenna diversity
+
+ if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1))
+ return;
+
+ b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2);
+ b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1);
}
static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev)
@@ -524,7 +2228,6 @@ static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
return B43_TXPWR_RES_DONE;
}
-
const struct b43_phy_operations b43_phyops_lp = {
.allocate = b43_lpphy_op_allocate,
.free = b43_lpphy_op_free,
@@ -532,6 +2235,7 @@ const struct b43_phy_operations b43_phyops_lp = {
.init = b43_lpphy_op_init,
.phy_read = b43_lpphy_op_read,
.phy_write = b43_lpphy_op_write,
+ .phy_maskset = b43_lpphy_op_maskset,
.radio_read = b43_lpphy_op_radio_read,
.radio_write = b43_lpphy_op_radio_write,
.software_rfkill = b43_lpphy_op_software_rfkill,
diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h
index 18370b4ac38e..c3232c17b60a 100644
--- a/drivers/net/wireless/b43/phy_lp.h
+++ b/drivers/net/wireless/b43/phy_lp.h
@@ -273,12 +273,19 @@
#define B43_LPPHY_AFE_DDFS_POINTER_INIT B43_PHY_OFDM(0xB8) /* AFE DDFS pointer init */
#define B43_LPPHY_AFE_DDFS_INCR_INIT B43_PHY_OFDM(0xB9) /* AFE DDFS incr init */
#define B43_LPPHY_MRCNOISEREDUCTION B43_PHY_OFDM(0xBA) /* mrcNoiseReduction */
-#define B43_LPPHY_TRLOOKUP3 B43_PHY_OFDM(0xBB) /* TRLookup3 */
-#define B43_LPPHY_TRLOOKUP4 B43_PHY_OFDM(0xBC) /* TRLookup4 */
+#define B43_LPPHY_TR_LOOKUP_3 B43_PHY_OFDM(0xBB) /* TR Lookup 3 */
+#define B43_LPPHY_TR_LOOKUP_4 B43_PHY_OFDM(0xBC) /* TR Lookup 4 */
#define B43_LPPHY_RADAR_FIFO_STAT B43_PHY_OFDM(0xBD) /* Radar FIFO Status */
#define B43_LPPHY_GPIO_OUTEN B43_PHY_OFDM(0xBE) /* GPIO Out enable */
#define B43_LPPHY_GPIO_SELECT B43_PHY_OFDM(0xBF) /* GPIO Select */
#define B43_LPPHY_GPIO_OUT B43_PHY_OFDM(0xC0) /* GPIO Out */
+#define B43_LPPHY_4C3 B43_PHY_OFDM(0xC3) /* unknown, used during BB init */
+#define B43_LPPHY_4C4 B43_PHY_OFDM(0xC4) /* unknown, used during BB init */
+#define B43_LPPHY_4C5 B43_PHY_OFDM(0xC5) /* unknown, used during BB init */
+#define B43_LPPHY_TR_LOOKUP_5 B43_PHY_OFDM(0xC7) /* TR Lookup 5 */
+#define B43_LPPHY_TR_LOOKUP_6 B43_PHY_OFDM(0xC8) /* TR Lookup 6 */
+#define B43_LPPHY_TR_LOOKUP_7 B43_PHY_OFDM(0xC9) /* TR Lookup 7 */
+#define B43_LPPHY_TR_LOOKUP_8 B43_PHY_OFDM(0xCA) /* TR Lookup 8 */
@@ -818,14 +825,30 @@ struct b43_phy_lp {
enum b43_lpphy_txpctl_mode txpctl_mode;
/* Transmit isolation medium band */
- u8 tx_isolation_med_band; /* FIXME initial value? */
+ u8 tx_isolation_med_band;
/* Transmit isolation low band */
- u8 tx_isolation_low_band; /* FIXME initial value? */
+ u8 tx_isolation_low_band;
/* Transmit isolation high band */
- u8 tx_isolation_hi_band; /* FIXME initial value? */
+ u8 tx_isolation_hi_band;
+
+ /* Max transmit power medium band */
+ u16 max_tx_pwr_med_band;
+ /* Max transmit power low band */
+ u16 max_tx_pwr_low_band;
+ /* Max transmit power high band */
+ u16 max_tx_pwr_hi_band;
+
+ /* FIXME What are these used for? */
+ /* FIXME Is 15 the correct array size? */
+ u16 tx_max_rate[15];
+ u16 tx_max_ratel[15];
+ u16 tx_max_rateh[15];
+
+ /* Transmit power arrays */
+ s16 txpa[3], txpal[3], txpah[3];
/* Receive power offset */
- u8 rx_pwr_offset; /* FIXME initial value? */
+ u8 rx_pwr_offset;
/* TSSI transmit count */
u16 tssi_tx_count;
@@ -841,16 +864,16 @@ struct b43_phy_lp {
s8 tx_pwr_idx_over; /* FIXME initial value? */
/* RSSI vf */
- u8 rssi_vf; /* FIXME initial value? */
+ u8 rssi_vf;
/* RSSI vc */
- u8 rssi_vc; /* FIXME initial value? */
+ u8 rssi_vc;
/* RSSI gs */
- u8 rssi_gs; /* FIXME initial value? */
+ u8 rssi_gs;
/* RC cap */
u8 rc_cap; /* FIXME initial value? */
/* BX arch */
- u8 bx_arch; /* FIXME initial value? */
+ u8 bx_arch;
/* Full calibration channel */
u8 full_calib_chan; /* FIXME initial value? */
@@ -858,8 +881,23 @@ struct b43_phy_lp {
/* Transmit iqlocal best coeffs */
bool tx_iqloc_best_coeffs_valid;
u8 tx_iqloc_best_coeffs[11];
+
+ /* Used for "Save/Restore Dig Filt State" */
+ u16 dig_flt_state[9];
+
+ bool crs_usr_disable, crs_sys_disable;
+
+ unsigned int pdiv;
+
+ /* The channel we are tuned to */
+ u8 channel;
};
+enum tssi_mux_mode {
+ TSSI_MUX_PREPA,
+ TSSI_MUX_POSTPA,
+ TSSI_MUX_EXT,
+};
struct b43_phy_operations;
extern const struct b43_phy_operations b43_phyops_lp;
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index be7b5604947b..992318a78077 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -137,7 +137,8 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
b43_radio_mask(dev, B2055_MASTER1, 0xFFF3);
msleep(1);
- if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) {
+ if ((sprom->revision != 4) ||
+ !(sprom->boardflags_hi & B43_BFH_RSSIINV)) {
if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) ||
(binfo->type != 0x46D) ||
(binfo->rev < 0x41)) {
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
index 69138e8c1db6..3498b68385e7 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -32,9 +32,6 @@
#include <linux/delay.h>
-static void b43_pio_rx_work(struct work_struct *work);
-
-
static u16 generate_cookie(struct b43_pio_txqueue *q,
struct b43_pio_txpacket *pack)
{
@@ -144,7 +141,6 @@ static struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev,
q = kzalloc(sizeof(*q), GFP_KERNEL);
if (!q)
return NULL;
- spin_lock_init(&q->lock);
q->dev = dev;
q->rev = dev->dev->id.revision;
q->mmio_base = index_to_pioqueue_base(dev, index) +
@@ -179,12 +175,10 @@ static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev,
q = kzalloc(sizeof(*q), GFP_KERNEL);
if (!q)
return NULL;
- spin_lock_init(&q->lock);
q->dev = dev;
q->rev = dev->dev->id.revision;
q->mmio_base = index_to_pioqueue_base(dev, index) +
pio_rxqueue_offset(dev);
- INIT_WORK(&q->rx_work, b43_pio_rx_work);
/* Enable Direct FIFO RX (PIO) on the engine. */
b43_dma_direct_fifo_rx(dev, index, 1);
@@ -249,13 +243,6 @@ void b43_pio_free(struct b43_wldev *dev)
destroy_queue_tx(pio, tx_queue_AC_BK);
}
-void b43_pio_stop(struct b43_wldev *dev)
-{
- if (!b43_using_pio_transfers(dev))
- return;
- cancel_work_sync(&dev->pio.rx_queue->rx_work);
-}
-
int b43_pio_init(struct b43_wldev *dev)
{
struct b43_pio *pio = &dev->pio;
@@ -461,8 +448,8 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
cookie = generate_cookie(q, pack);
hdrlen = b43_txhdr_size(q->dev);
- err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data,
- skb->len, info, cookie);
+ err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb,
+ info, cookie);
if (err)
return err;
@@ -494,7 +481,6 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb)
{
struct b43_pio_txqueue *q;
struct ieee80211_hdr *hdr;
- unsigned long flags;
unsigned int hdrlen, total_len;
int err = 0;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -512,20 +498,18 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb)
q = select_queue_by_priority(dev, skb_get_queue_mapping(skb));
}
- spin_lock_irqsave(&q->lock, flags);
-
hdrlen = b43_txhdr_size(dev);
total_len = roundup(skb->len + hdrlen, 4);
if (unlikely(total_len > q->buffer_size)) {
err = -ENOBUFS;
b43dbg(dev->wl, "PIO: TX packet longer than queue.\n");
- goto out_unlock;
+ goto out;
}
if (unlikely(q->free_packet_slots == 0)) {
err = -ENOBUFS;
b43warn(dev->wl, "PIO: TX packet overflow.\n");
- goto out_unlock;
+ goto out;
}
B43_WARN_ON(q->buffer_used > q->buffer_size);
@@ -534,7 +518,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb)
err = -EBUSY;
ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
q->stopped = 1;
- goto out_unlock;
+ goto out;
}
/* Assign the queue number to the ring (if not already done before)
@@ -548,11 +532,11 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb)
* anymore and must not transmit it unencrypted. */
dev_kfree_skb_any(skb);
err = 0;
- goto out_unlock;
+ goto out;
}
if (unlikely(err)) {
b43err(dev->wl, "PIO transmission failure\n");
- goto out_unlock;
+ goto out;
}
q->nr_tx_packets++;
@@ -564,13 +548,10 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb)
q->stopped = 1;
}
-out_unlock:
- spin_unlock_irqrestore(&q->lock, flags);
-
+out:
return err;
}
-/* Called with IRQs disabled. */
void b43_pio_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status)
{
@@ -584,8 +565,6 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
return;
B43_WARN_ON(!pack);
- spin_lock(&q->lock); /* IRQs are already disabled. */
-
info = IEEE80211_SKB_CB(pack->skb);
b43_fill_txstatus_report(dev, info, status);
@@ -603,8 +582,6 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
ieee80211_wake_queue(dev->wl->hw, q->queue_prio);
q->stopped = 0;
}
-
- spin_unlock(&q->lock);
}
void b43_pio_get_tx_stats(struct b43_wldev *dev,
@@ -612,17 +589,14 @@ void b43_pio_get_tx_stats(struct b43_wldev *dev,
{
const int nr_queues = dev->wl->hw->queues;
struct b43_pio_txqueue *q;
- unsigned long flags;
int i;
for (i = 0; i < nr_queues; i++) {
q = select_queue_by_priority(dev, i);
- spin_lock_irqsave(&q->lock, flags);
stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots;
stats[i].limit = B43_PIO_MAX_NR_TXPACKETS;
stats[i].count = q->nr_tx_packets;
- spin_unlock_irqrestore(&q->lock, flags);
}
}
@@ -760,37 +734,23 @@ rx_error:
return 1;
}
-/* RX workqueue. We can sleep, yay! */
-static void b43_pio_rx_work(struct work_struct *work)
+void b43_pio_rx(struct b43_pio_rxqueue *q)
{
- struct b43_pio_rxqueue *q = container_of(work, struct b43_pio_rxqueue,
- rx_work);
- unsigned int budget = 50;
+ unsigned int count = 0;
bool stop;
- do {
- spin_lock_irq(&q->lock);
+ while (1) {
stop = (pio_rx_frame(q) == 0);
- spin_unlock_irq(&q->lock);
- cond_resched();
if (stop)
break;
- } while (--budget);
-}
-
-/* Called with IRQs disabled. */
-void b43_pio_rx(struct b43_pio_rxqueue *q)
-{
- /* Due to latency issues we must run the RX path in
- * a workqueue to be able to schedule between packets. */
- queue_work(q->dev->wl->hw->workqueue, &q->rx_work);
+ cond_resched();
+ if (WARN_ON_ONCE(++count > 10000))
+ break;
+ }
}
static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q)
{
- unsigned long flags;
-
- spin_lock_irqsave(&q->lock, flags);
if (q->rev >= 8) {
b43_piotx_write32(q, B43_PIO8_TXCTL,
b43_piotx_read32(q, B43_PIO8_TXCTL)
@@ -800,14 +760,10 @@ static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q)
b43_piotx_read16(q, B43_PIO_TXCTL)
| B43_PIO_TXCTL_SUSPREQ);
}
- spin_unlock_irqrestore(&q->lock, flags);
}
static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q)
{
- unsigned long flags;
-
- spin_lock_irqsave(&q->lock, flags);
if (q->rev >= 8) {
b43_piotx_write32(q, B43_PIO8_TXCTL,
b43_piotx_read32(q, B43_PIO8_TXCTL)
@@ -817,7 +773,6 @@ static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q)
b43_piotx_read16(q, B43_PIO_TXCTL)
& ~B43_PIO_TXCTL_SUSPREQ);
}
- spin_unlock_irqrestore(&q->lock, flags);
}
void b43_pio_tx_suspend(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h
index 6c174c91ca20..7dd649c9ddad 100644
--- a/drivers/net/wireless/b43/pio.h
+++ b/drivers/net/wireless/b43/pio.h
@@ -70,7 +70,6 @@ struct b43_pio_txpacket {
struct b43_pio_txqueue {
struct b43_wldev *dev;
- spinlock_t lock;
u16 mmio_base;
/* The device queue buffer size in bytes. */
@@ -103,12 +102,8 @@ struct b43_pio_txqueue {
struct b43_pio_rxqueue {
struct b43_wldev *dev;
- spinlock_t lock;
u16 mmio_base;
- /* Work to reduce latency issues on RX. */
- struct work_struct rx_work;
-
/* Shortcut to the 802.11 core revision. This is to
* avoid horrible pointer dereferencing in the fastpaths. */
u8 rev;
@@ -162,7 +157,6 @@ static inline void b43_piorx_write32(struct b43_pio_rxqueue *q,
int b43_pio_init(struct b43_wldev *dev);
-void b43_pio_stop(struct b43_wldev *dev);
void b43_pio_free(struct b43_wldev *dev);
int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb);
diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c
index 5adaa3692d75..f1ae4e05a32c 100644
--- a/drivers/net/wireless/b43/sysfs.c
+++ b/drivers/net/wireless/b43/sysfs.c
@@ -94,7 +94,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev,
const char *buf, size_t count)
{
struct b43_wldev *wldev = dev_to_b43_wldev(dev);
- unsigned long flags;
int err;
int mode;
@@ -120,7 +119,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev,
}
mutex_lock(&wldev->wl->mutex);
- spin_lock_irqsave(&wldev->wl->irq_lock, flags);
if (wldev->phy.ops->interf_mitigation) {
err = wldev->phy.ops->interf_mitigation(wldev, mode);
@@ -132,7 +130,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev,
err = -ENOSYS;
mmiowb();
- spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
mutex_unlock(&wldev->wl->mutex);
return err ? err : count;
diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c
index 4ea734dce218..61027ee84fb5 100644
--- a/drivers/net/wireless/b43/tables_lpphy.c
+++ b/drivers/net/wireless/b43/tables_lpphy.c
@@ -1,9 +1,10 @@
/*
Broadcom B43 wireless driver
- IEEE 802.11g LP-PHY and radio device data tables
+ IEEE 802.11a/g LP-PHY and radio device data tables
Copyright (c) 2009 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2009 Gábor Stefanik <netrolller.3d@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -28,22 +29,22 @@
#include "phy_lp.h"
-/* Entry of the 2062 radio init table */
-struct b2062_init_tab_entry {
+/* Entry of the 2062/2063 radio init table */
+struct b206x_init_tab_entry {
u16 offset;
u16 value_a;
u16 value_g;
u8 flags;
};
-#define B2062_FLAG_A 0x01 /* Flag: Init in A mode */
-#define B2062_FLAG_G 0x02 /* Flag: Init in G mode */
+#define B206X_FLAG_A 0x01 /* Flag: Init in A mode */
+#define B206X_FLAG_G 0x02 /* Flag: Init in G mode */
-static const struct b2062_init_tab_entry b2062_init_tab[] = {
+static const struct b206x_init_tab_entry b2062_init_tab[] = {
/* { .offset = B2062_N_COMM1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = 0x0001, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_N_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_N_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_N_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
@@ -56,42 +57,42 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = {
/* { .offset = B2062_N_COMM14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_COMM15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_PDN_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_N_PDN_CTL1, .value_a = 0x0000, .value_g = 0x00CA, .flags = B2062_FLAG_G, },
+ { .offset = B2062_N_PDN_CTL1, .value_a = 0x0000, .value_g = 0x00CA, .flags = B206X_FLAG_G, },
/* { .offset = B2062_N_PDN_CTL2, .value_a = 0x0018, .value_g = 0x0018, .flags = 0, }, */
- { .offset = B2062_N_PDN_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_N_PDN_CTL4, .value_a = 0x0015, .value_g = 0x002A, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_N_PDN_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_N_PDN_CTL4, .value_a = 0x0015, .value_g = 0x002A, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_N_GEN_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_IQ_CALIB, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */
- { .offset = B2062_N_LGENC, .value_a = 0x00DB, .value_g = 0x00FF, .flags = B2062_FLAG_A, },
+ { .offset = B2062_N_LGENC, .value_a = 0x00DB, .value_g = 0x00FF, .flags = B206X_FLAG_A, },
/* { .offset = B2062_N_LGENA_LPF, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */
/* { .offset = B2062_N_LGENA_BIAS0, .value_a = 0x0041, .value_g = 0x0041, .flags = 0, }, */
/* { .offset = B2062_N_LGNEA_BIAS1, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */
/* { .offset = B2062_N_LGENA_CTL0, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */
/* { .offset = B2062_N_LGENA_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_LGENA_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_N_LGENA_TUNE0, .value_a = 0x00DD, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_N_LGENA_TUNE0, .value_a = 0x00DD, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_N_LGENA_TUNE1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_N_LGENA_TUNE2, .value_a = 0x00DD, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_N_LGENA_TUNE3, .value_a = 0x0077, .value_g = 0x00B5, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_N_LGENA_CTL3, .value_a = 0x0000, .value_g = 0x00FF, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_N_LGENA_TUNE2, .value_a = 0x00DD, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_N_LGENA_TUNE3, .value_a = 0x0077, .value_g = 0x00B5, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_N_LGENA_CTL3, .value_a = 0x0000, .value_g = 0x00FF, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_N_LGENA_CTL4, .value_a = 0x001F, .value_g = 0x001F, .flags = 0, }, */
/* { .offset = B2062_N_LGENA_CTL5, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */
/* { .offset = B2062_N_LGENA_CTL6, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */
- { .offset = B2062_N_LGENA_CTL7, .value_a = 0x0033, .value_g = 0x0033, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_N_LGENA_CTL7, .value_a = 0x0033, .value_g = 0x0033, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_N_RXA_CTL0, .value_a = 0x0009, .value_g = 0x0009, .flags = 0, }, */
- { .offset = B2062_N_RXA_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = B2062_FLAG_G, },
+ { .offset = B2062_N_RXA_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, },
/* { .offset = B2062_N_RXA_CTL2, .value_a = 0x0018, .value_g = 0x0018, .flags = 0, }, */
/* { .offset = B2062_N_RXA_CTL3, .value_a = 0x0027, .value_g = 0x0027, .flags = 0, }, */
/* { .offset = B2062_N_RXA_CTL4, .value_a = 0x0028, .value_g = 0x0028, .flags = 0, }, */
/* { .offset = B2062_N_RXA_CTL5, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */
/* { .offset = B2062_N_RXA_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_RXA_CTL7, .value_a = 0x0008, .value_g = 0x0008, .flags = 0, }, */
- { .offset = B2062_N_RXBB_CTL0, .value_a = 0x0082, .value_g = 0x0080, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_N_RXBB_CTL0, .value_a = 0x0082, .value_g = 0x0080, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_N_RXBB_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_RXBB_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_RXBB_GAIN0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_N_RXBB_GAIN1, .value_a = 0x0004, .value_g = 0x0004, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_N_RXBB_GAIN2, .value_a = 0x0000, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_N_RXBB_GAIN1, .value_a = 0x0004, .value_g = 0x0004, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_N_RXBB_GAIN2, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_N_RXBB_GAIN3, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */
/* { .offset = B2062_N_RXBB_RSSI0, .value_a = 0x0043, .value_g = 0x0043, .flags = 0, }, */
/* { .offset = B2062_N_RXBB_RSSI1, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */
@@ -112,8 +113,8 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = {
/* { .offset = B2062_N_TX_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_TX_CTL2, .value_a = 0x0084, .value_g = 0x0084, .flags = 0, }, */
/* { .offset = B2062_N_TX_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_N_TX_CTL4, .value_a = 0x0003, .value_g = 0x0003, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_N_TX_CTL5, .value_a = 0x0002, .value_g = 0x0002, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_N_TX_CTL4, .value_a = 0x0003, .value_g = 0x0003, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_N_TX_CTL5, .value_a = 0x0002, .value_g = 0x0002, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_N_TX_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_TX_CTL7, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */
/* { .offset = B2062_N_TX_CTL8, .value_a = 0x0082, .value_g = 0x0082, .flags = 0, }, */
@@ -121,7 +122,7 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = {
/* { .offset = B2062_N_TX_CTL_A, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_N_TX_GC2G, .value_a = 0x00FF, .value_g = 0x00FF, .flags = 0, }, */
/* { .offset = B2062_N_TX_GC5G, .value_a = 0x00FF, .value_g = 0x00FF, .flags = 0, }, */
- { .offset = B2062_N_TX_TUNE, .value_a = 0x0088, .value_g = 0x001B, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_N_TX_TUNE, .value_a = 0x0088, .value_g = 0x001B, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_N_TX_PAD, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */
/* { .offset = B2062_N_TX_PGA, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */
/* { .offset = B2062_N_TX_PADAUX, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */
@@ -150,7 +151,7 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = {
/* { .offset = B2062_S_RADIO_ID_CODE, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_S_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_S_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_S_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
@@ -162,24 +163,24 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = {
/* { .offset = B2062_S_COMM13, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_COMM14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_COMM15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_S_PDS_CTL0, .value_a = 0x00FF, .value_g = 0x00FF, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_S_PDS_CTL0, .value_a = 0x00FF, .value_g = 0x00FF, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_S_PDS_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_PDS_CTL2, .value_a = 0x008E, .value_g = 0x008E, .flags = 0, }, */
/* { .offset = B2062_S_PDS_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_BG_CTL0, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */
/* { .offset = B2062_S_BG_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_BG_CTL2, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */
- { .offset = B2062_S_LGENG_CTL0, .value_a = 0x00F8, .value_g = 0x00D8, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_LGENG_CTL1, .value_a = 0x003C, .value_g = 0x0024, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_S_LGENG_CTL0, .value_a = 0x00F8, .value_g = 0x00D8, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_LGENG_CTL1, .value_a = 0x003C, .value_g = 0x0024, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_S_LGENG_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_LGENG_CTL3, .value_a = 0x0041, .value_g = 0x0041, .flags = 0, }, */
/* { .offset = B2062_S_LGENG_CTL4, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */
/* { .offset = B2062_S_LGENG_CTL5, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */
/* { .offset = B2062_S_LGENG_CTL6, .value_a = 0x0022, .value_g = 0x0022, .flags = 0, }, */
/* { .offset = B2062_S_LGENG_CTL7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_S_LGENG_CTL8, .value_a = 0x0088, .value_g = 0x0080, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_S_LGENG_CTL8, .value_a = 0x0088, .value_g = 0x0080, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_S_LGENG_CTL9, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */
- { .offset = B2062_S_LGENG_CTL10, .value_a = 0x0088, .value_g = 0x0080, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_S_LGENG_CTL10, .value_a = 0x0088, .value_g = 0x0080, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_S_LGENG_CTL11, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_REFPLL_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_REFPLL_CTL1, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */
@@ -198,41 +199,41 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = {
/* { .offset = B2062_S_REFPLL_CTL14, .value_a = 0x0075, .value_g = 0x0075, .flags = 0, }, */
/* { .offset = B2062_S_REFPLL_CTL15, .value_a = 0x00B4, .value_g = 0x00B4, .flags = 0, }, */
/* { .offset = B2062_S_REFPLL_CTL16, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_S_RFPLL_CTL0, .value_a = 0x0098, .value_g = 0x0098, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL1, .value_a = 0x0010, .value_g = 0x0010, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL0, .value_a = 0x0098, .value_g = 0x0098, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL1, .value_a = 0x0010, .value_g = 0x0010, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_S_RFPLL_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_RFPLL_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_RFPLL_CTL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_S_RFPLL_CTL5, .value_a = 0x0043, .value_g = 0x0043, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL6, .value_a = 0x0047, .value_g = 0x0047, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL7, .value_a = 0x000C, .value_g = 0x000C, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL8, .value_a = 0x0011, .value_g = 0x0011, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL9, .value_a = 0x0011, .value_g = 0x0011, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL10, .value_a = 0x000E, .value_g = 0x000E, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL11, .value_a = 0x0008, .value_g = 0x0008, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL12, .value_a = 0x0033, .value_g = 0x0033, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL13, .value_a = 0x000A, .value_g = 0x000A, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL14, .value_a = 0x0006, .value_g = 0x0006, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL5, .value_a = 0x0043, .value_g = 0x0043, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL6, .value_a = 0x0047, .value_g = 0x0047, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL7, .value_a = 0x000C, .value_g = 0x000C, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL8, .value_a = 0x0011, .value_g = 0x0011, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL9, .value_a = 0x0011, .value_g = 0x0011, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL10, .value_a = 0x000E, .value_g = 0x000E, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL11, .value_a = 0x0008, .value_g = 0x0008, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL12, .value_a = 0x0033, .value_g = 0x0033, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL13, .value_a = 0x000A, .value_g = 0x000A, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL14, .value_a = 0x0006, .value_g = 0x0006, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_S_RFPLL_CTL15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_RFPLL_CTL16, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_RFPLL_CTL17, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_S_RFPLL_CTL18, .value_a = 0x003E, .value_g = 0x003E, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL19, .value_a = 0x0013, .value_g = 0x0013, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL18, .value_a = 0x003E, .value_g = 0x003E, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL19, .value_a = 0x0013, .value_g = 0x0013, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_S_RFPLL_CTL20, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_S_RFPLL_CTL21, .value_a = 0x0062, .value_g = 0x0062, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL22, .value_a = 0x0007, .value_g = 0x0007, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL23, .value_a = 0x0016, .value_g = 0x0016, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL24, .value_a = 0x005C, .value_g = 0x005C, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL25, .value_a = 0x0095, .value_g = 0x0095, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL21, .value_a = 0x0062, .value_g = 0x0062, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL22, .value_a = 0x0007, .value_g = 0x0007, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL23, .value_a = 0x0016, .value_g = 0x0016, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL24, .value_a = 0x005C, .value_g = 0x005C, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL25, .value_a = 0x0095, .value_g = 0x0095, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_S_RFPLL_CTL26, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_RFPLL_CTL27, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_RFPLL_CTL28, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_RFPLL_CTL29, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_S_RFPLL_CTL30, .value_a = 0x00A0, .value_g = 0x00A0, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL31, .value_a = 0x0004, .value_g = 0x0004, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL30, .value_a = 0x00A0, .value_g = 0x00A0, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL31, .value_a = 0x0004, .value_g = 0x0004, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_S_RFPLL_CTL32, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
- { .offset = B2062_S_RFPLL_CTL33, .value_a = 0x00CC, .value_g = 0x00CC, .flags = B2062_FLAG_A | B2062_FLAG_G, },
- { .offset = B2062_S_RFPLL_CTL34, .value_a = 0x0007, .value_g = 0x0007, .flags = B2062_FLAG_A | B2062_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL33, .value_a = 0x00CC, .value_g = 0x00CC, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2062_S_RFPLL_CTL34, .value_a = 0x0007, .value_g = 0x0007, .flags = B206X_FLAG_A | B206X_FLAG_G, },
/* { .offset = B2062_S_RXG_CNT0, .value_a = 0x0010, .value_g = 0x0010, .flags = 0, }, */
/* { .offset = B2062_S_RXG_CNT1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_RXG_CNT2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
@@ -241,7 +242,7 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = {
/* { .offset = B2062_S_RXG_CNT5, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */
/* { .offset = B2062_S_RXG_CNT6, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */
/* { .offset = B2062_S_RXG_CNT7, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */
- { .offset = B2062_S_RXG_CNT8, .value_a = 0x000F, .value_g = 0x000F, .flags = B2062_FLAG_A, },
+ { .offset = B2062_S_RXG_CNT8, .value_a = 0x000F, .value_g = 0x000F, .flags = B206X_FLAG_A, },
/* { .offset = B2062_S_RXG_CNT9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
/* { .offset = B2062_S_RXG_CNT10, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */
/* { .offset = B2062_S_RXG_CNT11, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
@@ -253,19 +254,337 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = {
/* { .offset = B2062_S_RXG_CNT17, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */
};
+static const struct b206x_init_tab_entry b2063_init_tab[] = {
+ { .offset = B2063_COMM1, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, },
+ /* { .offset = B2063_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_COMM4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_COMM8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_COMM9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_COMM10, .value_a = 0x0001, .value_g = 0x0000, .flags = B206X_FLAG_A, },
+ /* { .offset = B2063_COMM11, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_COMM12, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_COMM13, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_COMM14, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */
+ /* { .offset = B2063_COMM15, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */
+ { .offset = B2063_COMM16, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, },
+ { .offset = B2063_COMM17, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, },
+ { .offset = B2063_COMM18, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, },
+ { .offset = B2063_COMM19, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, },
+ { .offset = B2063_COMM20, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, },
+ { .offset = B2063_COMM21, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, },
+ { .offset = B2063_COMM22, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, },
+ { .offset = B2063_COMM23, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, },
+ { .offset = B2063_COMM24, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, },
+ /* { .offset = B2063_PWR_SWITCH_CTL, .value_a = 0x007f, .value_g = 0x007f, .flags = 0, }, */
+ /* { .offset = B2063_PLL_SP1, .value_a = 0x003f, .value_g = 0x003f, .flags = 0, }, */
+ /* { .offset = B2063_PLL_SP2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_LOGEN_SP1, .value_a = 0x00e8, .value_g = 0x00d4, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2063_LOGEN_SP2, .value_a = 0x00a7, .value_g = 0x0053, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_LOGEN_SP3, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */
+ { .offset = B2063_LOGEN_SP4, .value_a = 0x00f0, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_LOGEN_SP5, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */
+ { .offset = B2063_G_RX_SP1, .value_a = 0x001f, .value_g = 0x005e, .flags = B206X_FLAG_G, },
+ { .offset = B2063_G_RX_SP2, .value_a = 0x007f, .value_g = 0x007e, .flags = B206X_FLAG_G, },
+ { .offset = B2063_G_RX_SP3, .value_a = 0x0030, .value_g = 0x00f0, .flags = B206X_FLAG_G, },
+ /* { .offset = B2063_G_RX_SP4, .value_a = 0x0035, .value_g = 0x0035, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_SP5, .value_a = 0x003f, .value_g = 0x003f, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_SP6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_G_RX_SP7, .value_a = 0x007f, .value_g = 0x007f, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_G_RX_SP8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_SP9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_G_RX_SP10, .value_a = 0x000c, .value_g = 0x000c, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_G_RX_SP11, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_A_RX_SP1, .value_a = 0x003c, .value_g = 0x003f, .flags = B206X_FLAG_A, },
+ { .offset = B2063_A_RX_SP2, .value_a = 0x00fc, .value_g = 0x00fe, .flags = B206X_FLAG_A, },
+ /* { .offset = B2063_A_RX_SP3, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_SP4, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_SP5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_SP6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_A_RX_SP7, .value_a = 0x0008, .value_g = 0x0008, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_RX_BB_SP1, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */
+ /* { .offset = B2063_RX_BB_SP2, .value_a = 0x0022, .value_g = 0x0022, .flags = 0, }, */
+ /* { .offset = B2063_RX_BB_SP3, .value_a = 0x00a8, .value_g = 0x00a8, .flags = 0, }, */
+ { .offset = B2063_RX_BB_SP4, .value_a = 0x0060, .value_g = 0x0060, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_RX_BB_SP5, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */
+ /* { .offset = B2063_RX_BB_SP6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_RX_BB_SP7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_RX_BB_SP8, .value_a = 0x0030, .value_g = 0x0030, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_TX_RF_SP1, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_SP2, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */
+ { .offset = B2063_TX_RF_SP3, .value_a = 0x000c, .value_g = 0x000b, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2063_TX_RF_SP4, .value_a = 0x0010, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_TX_RF_SP5, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_SP6, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_SP7, .value_a = 0x0068, .value_g = 0x0068, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_SP8, .value_a = 0x0068, .value_g = 0x0068, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_SP9, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_SP10, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_SP11, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_SP12, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_SP13, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_SP14, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_SP15, .value_a = 0x00c0, .value_g = 0x00c0, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_SP16, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_SP17, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */
+ { .offset = B2063_PA_SP1, .value_a = 0x003d, .value_g = 0x00fd, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_PA_SP2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */
+ /* { .offset = B2063_PA_SP3, .value_a = 0x0096, .value_g = 0x0096, .flags = 0, }, */
+ /* { .offset = B2063_PA_SP4, .value_a = 0x005a, .value_g = 0x005a, .flags = 0, }, */
+ /* { .offset = B2063_PA_SP5, .value_a = 0x007f, .value_g = 0x007f, .flags = 0, }, */
+ /* { .offset = B2063_PA_SP6, .value_a = 0x007f, .value_g = 0x007f, .flags = 0, }, */
+ /* { .offset = B2063_PA_SP7, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */
+ { .offset = B2063_TX_BB_SP1, .value_a = 0x0002, .value_g = 0x0002, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_TX_BB_SP2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_TX_BB_SP3, .value_a = 0x0030, .value_g = 0x0030, .flags = 0, }, */
+ /* { .offset = B2063_REG_SP1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_BANDGAP_CTL1, .value_a = 0x0056, .value_g = 0x0056, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_BANDGAP_CTL2, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */
+ /* { .offset = B2063_LPO_CTL1, .value_a = 0x000e, .value_g = 0x000e, .flags = 0, }, */
+ /* { .offset = B2063_RC_CALIB_CTL1, .value_a = 0x007e, .value_g = 0x007e, .flags = 0, }, */
+ /* { .offset = B2063_RC_CALIB_CTL2, .value_a = 0x0015, .value_g = 0x0015, .flags = 0, }, */
+ /* { .offset = B2063_RC_CALIB_CTL3, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */
+ /* { .offset = B2063_RC_CALIB_CTL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_RC_CALIB_CTL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_RC_CALIB_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_RC_CALIB_CTL7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_RC_CALIB_CTL8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_RC_CALIB_CTL9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_RC_CALIB_CTL10, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_CALNRST, .value_a = 0x0004, .value_g = 0x0004, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_IN_PLL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_IN_PLL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_CP1, .value_a = 0x00cf, .value_g = 0x00cf, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_CP2, .value_a = 0x0059, .value_g = 0x0059, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_CP3, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_CP4, .value_a = 0x0042, .value_g = 0x0042, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_LF1, .value_a = 0x00db, .value_g = 0x00db, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_LF2, .value_a = 0x0094, .value_g = 0x0094, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_LF3, .value_a = 0x0028, .value_g = 0x0028, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_LF4, .value_a = 0x0063, .value_g = 0x0063, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_SG1, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_SG2, .value_a = 0x00d3, .value_g = 0x00d3, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_SG3, .value_a = 0x00b1, .value_g = 0x00b1, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_SG4, .value_a = 0x003b, .value_g = 0x003b, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_SG5, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_VCO1, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */
+ { .offset = B2063_PLL_JTAG_PLL_VCO2, .value_a = 0x00f7, .value_g = 0x00f7, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB3, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB5, .value_a = 0x0009, .value_g = 0x0009, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB6, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB7, .value_a = 0x0016, .value_g = 0x0016, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB8, .value_a = 0x006b, .value_g = 0x006b, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB10, .value_a = 0x00b3, .value_g = 0x00b3, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_XTAL_12, .value_a = 0x0004, .value_g = 0x0004, .flags = 0, }, */
+ /* { .offset = B2063_PLL_JTAG_PLL_XTAL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_ACL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_ACL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_ACL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_ACL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_ACL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_INPUTS, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_WAITCNT, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_OVR1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_OVR2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_OVAL1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_OVAL2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_OVAL3, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_OVAL4, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_OVAL5, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_OVAL6, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_OVAL7, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_CALVLD1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_CALVLD2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_CVAL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_CVAL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_CVAL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_CVAL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_CVAL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_CVAL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LO_CALIB_CVAL7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_CALIB_EN, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_PEAKDET1, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_RCCR1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_VCOBUF1, .value_a = 0x0060, .value_g = 0x0060, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_MIXER1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_MIXER2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_BUF1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_BUF2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_DIV1, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_DIV2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_DIV3, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_CBUFRX1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_CBUFRX2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_CBUFTX1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_CBUFTX2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_IDAC1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_SPARE1, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_SPARE2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_LOGEN_SPARE3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_1ST1, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_1ST2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_1ST3, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_2ND1, .value_a = 0x0030, .value_g = 0x0030, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_2ND2, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_2ND3, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_2ND4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_2ND5, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_2ND6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_2ND7, .value_a = 0x0035, .value_g = 0x0035, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_2ND8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_PS1, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_PS2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_PS3, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_PS4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_PS5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_MIX1, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_MIX2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_G_RX_MIX3, .value_a = 0x0071, .value_g = 0x0071, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2063_G_RX_MIX4, .value_a = 0x0071, .value_g = 0x0071, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_G_RX_MIX5, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_MIX6, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_MIX7, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_MIX8, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_PDET1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_SPARES1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_SPARES2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_G_RX_SPARES3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_1ST1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_A_RX_1ST2, .value_a = 0x00f0, .value_g = 0x0030, .flags = B206X_FLAG_A, },
+ /* { .offset = B2063_A_RX_1ST3, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_1ST4, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_1ST5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_2ND1, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_2ND2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_2ND3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_2ND4, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_2ND5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_2ND6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_2ND7, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_PS1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_PS2, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_PS3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_PS4, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_PS5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_A_RX_PS6, .value_a = 0x0077, .value_g = 0x0077, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_A_RX_MIX1, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_MIX2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_MIX3, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */
+ { .offset = B2063_A_RX_MIX4, .value_a = 0x0003, .value_g = 0x0003, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2063_A_RX_MIX5, .value_a = 0x000f, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ { .offset = B2063_A_RX_MIX6, .value_a = 0x000f, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_A_RX_MIX7, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_MIX8, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_PWRDET1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_SPARE1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_SPARE2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_A_RX_SPARE3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_RX_TIA_CTL1, .value_a = 0x0077, .value_g = 0x0077, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_RX_TIA_CTL2, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */
+ { .offset = B2063_RX_TIA_CTL3, .value_a = 0x0077, .value_g = 0x0077, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_RX_TIA_CTL4, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */
+ /* { .offset = B2063_RX_TIA_CTL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_RX_TIA_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_RX_BB_CTL1, .value_a = 0x0074, .value_g = 0x0074, .flags = 0, }, */
+ { .offset = B2063_RX_BB_CTL2, .value_a = 0x0004, .value_g = 0x0004, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_RX_BB_CTL3, .value_a = 0x00a2, .value_g = 0x00a2, .flags = 0, }, */
+ /* { .offset = B2063_RX_BB_CTL4, .value_a = 0x00aa, .value_g = 0x00aa, .flags = 0, }, */
+ /* { .offset = B2063_RX_BB_CTL5, .value_a = 0x0024, .value_g = 0x0024, .flags = 0, }, */
+ /* { .offset = B2063_RX_BB_CTL6, .value_a = 0x00a9, .value_g = 0x00a9, .flags = 0, }, */
+ /* { .offset = B2063_RX_BB_CTL7, .value_a = 0x0028, .value_g = 0x0028, .flags = 0, }, */
+ /* { .offset = B2063_RX_BB_CTL8, .value_a = 0x0010, .value_g = 0x0010, .flags = 0, }, */
+ /* { .offset = B2063_RX_BB_CTL9, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_CTL1, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_IDAC_LO_RF_I, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_IDAC_LO_RF_Q, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_IDAC_LO_BB_I, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_IDAC_LO_BB_Q, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_CTL2, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_CTL3, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_CTL4, .value_a = 0x00b8, .value_g = 0x00b8, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_CTL5, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_CTL6, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_CTL7, .value_a = 0x0078, .value_g = 0x0078, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_CTL8, .value_a = 0x00c0, .value_g = 0x00c0, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_CTL9, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_CTL10, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_CTL14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_TX_RF_CTL15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_PA_CTL1, .value_a = 0x0000, .value_g = 0x0004, .flags = B206X_FLAG_A, },
+ /* { .offset = B2063_PA_CTL2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */
+ /* { .offset = B2063_PA_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_PA_CTL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_PA_CTL5, .value_a = 0x0096, .value_g = 0x0096, .flags = 0, }, */
+ /* { .offset = B2063_PA_CTL6, .value_a = 0x0077, .value_g = 0x0077, .flags = 0, }, */
+ /* { .offset = B2063_PA_CTL7, .value_a = 0x005a, .value_g = 0x005a, .flags = 0, }, */
+ /* { .offset = B2063_PA_CTL8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_PA_CTL9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_PA_CTL10, .value_a = 0x0021, .value_g = 0x0021, .flags = 0, }, */
+ /* { .offset = B2063_PA_CTL11, .value_a = 0x0070, .value_g = 0x0070, .flags = 0, }, */
+ /* { .offset = B2063_PA_CTL12, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_PA_CTL13, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_TX_BB_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_TX_BB_CTL2, .value_a = 0x00b3, .value_g = 0x00b3, .flags = 0, }, */
+ /* { .offset = B2063_TX_BB_CTL3, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */
+ /* { .offset = B2063_TX_BB_CTL4, .value_a = 0x000b, .value_g = 0x000b, .flags = 0, }, */
+ /* { .offset = B2063_GPIO_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ { .offset = B2063_VREG_CTL1, .value_a = 0x0003, .value_g = 0x0003, .flags = B206X_FLAG_A | B206X_FLAG_G, },
+ /* { .offset = B2063_AMUX_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_IQ_CALIB_GVAR, .value_a = 0x00b3, .value_g = 0x00b3, .flags = 0, }, */
+ /* { .offset = B2063_IQ_CALIB_CTL1, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */
+ /* { .offset = B2063_IQ_CALIB_CTL2, .value_a = 0x0030, .value_g = 0x0030, .flags = 0, }, */
+ /* { .offset = B2063_TEMPSENSE_CTL1, .value_a = 0x0046, .value_g = 0x0046, .flags = 0, }, */
+ /* { .offset = B2063_TEMPSENSE_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_TX_RX_LOOPBACK1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_TX_RX_LOOPBACK2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */
+ /* { .offset = B2063_EXT_TSSI_CTL1, .value_a = 0x0021, .value_g = 0x0021, .flags = 0, }, */
+ /* { .offset = B2063_EXT_TSSI_CTL2, .value_a = 0x0023, .value_g = 0x0023, .flags = 0, }, */
+ /* { .offset = B2063_AFE_CTL , .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */
+};
+
void b2062_upload_init_table(struct b43_wldev *dev)
{
- const struct b2062_init_tab_entry *e;
+ const struct b206x_init_tab_entry *e;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(b2062_init_tab); i++) {
e = &b2062_init_tab[i];
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
- if (!(e->flags & B2062_FLAG_G))
+ if (!(e->flags & B206X_FLAG_G))
continue;
b43_radio_write(dev, e->offset, e->value_g);
} else {
- if (!(e->flags & B2062_FLAG_A))
+ if (!(e->flags & B206X_FLAG_A))
+ continue;
+ b43_radio_write(dev, e->offset, e->value_a);
+ }
+ }
+}
+
+void b2063_upload_init_table(struct b43_wldev *dev)
+{
+ const struct b206x_init_tab_entry *e;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(b2063_init_tab); i++) {
+ e = &b2063_init_tab[i];
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ if (!(e->flags & B206X_FLAG_G))
+ continue;
+ b43_radio_write(dev, e->offset, e->value_g);
+ } else {
+ if (!(e->flags & B206X_FLAG_A))
continue;
b43_radio_write(dev, e->offset, e->value_a);
}
@@ -306,30 +625,35 @@ u32 b43_lptab_read(struct b43_wldev *dev, u32 offset)
void b43_lptab_read_bulk(struct b43_wldev *dev, u32 offset,
unsigned int nr_elements, void *_data)
{
- u32 type, value;
+ u32 type;
u8 *data = _data;
unsigned int i;
type = offset & B43_LPTAB_TYPEMASK;
+ offset &= ~B43_LPTAB_TYPEMASK;
+ B43_WARN_ON(offset > 0xFFFF);
+
+ b43_phy_write(dev, B43_LPPHY_TABLE_ADDR, offset);
+
for (i = 0; i < nr_elements; i++) {
- value = b43_lptab_read(dev, offset);
switch (type) {
case B43_LPTAB_8BIT:
- *data = value;
+ *data = b43_phy_read(dev, B43_LPPHY_TABLEDATALO) & 0xFF;
data++;
break;
case B43_LPTAB_16BIT:
- *((u16 *)data) = value;
+ *((u16 *)data) = b43_phy_read(dev, B43_LPPHY_TABLEDATALO);
data += 2;
break;
case B43_LPTAB_32BIT:
- *((u32 *)data) = value;
+ *((u32 *)data) = b43_phy_read(dev, B43_LPPHY_TABLEDATAHI);
+ *((u32 *)data) <<= 16;
+ *((u32 *)data) |= b43_phy_read(dev, B43_LPPHY_TABLEDATALO);
data += 4;
break;
default:
B43_WARN_ON(1);
}
- offset++;
}
}
@@ -370,25 +694,1764 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset,
unsigned int i;
type = offset & B43_LPTAB_TYPEMASK;
+ offset &= ~B43_LPTAB_TYPEMASK;
+ B43_WARN_ON(offset > 0xFFFF);
+
+ b43_phy_write(dev, B43_LPPHY_TABLE_ADDR, offset);
+
for (i = 0; i < nr_elements; i++) {
switch (type) {
case B43_LPTAB_8BIT:
value = *data;
data++;
+ B43_WARN_ON(value & ~0xFF);
+ b43_phy_write(dev, B43_LPPHY_TABLEDATALO, value);
break;
case B43_LPTAB_16BIT:
value = *((u16 *)data);
data += 2;
+ B43_WARN_ON(value & ~0xFFFF);
+ b43_phy_write(dev, B43_LPPHY_TABLEDATALO, value);
break;
case B43_LPTAB_32BIT:
value = *((u32 *)data);
data += 4;
+ b43_phy_write(dev, B43_LPPHY_TABLEDATAHI, value >> 16);
+ b43_phy_write(dev, B43_LPPHY_TABLEDATALO, value);
break;
default:
B43_WARN_ON(1);
- value = 0;
}
- b43_lptab_write(dev, offset, value);
- offset++;
+ }
+}
+
+static const u8 lpphy_min_sig_sq_table[] = {
+ 0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xcf, 0xcd,
+ 0xca, 0xc7, 0xc4, 0xc1, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+ 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x00,
+ 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+ 0xbe, 0xbe, 0xbe, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd,
+ 0xcf, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
+};
+
+static const u16 lpphy_rev01_noise_scale_table[] = {
+ 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
+ 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
+ 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0x00a4,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4c00, 0x2d36,
+ 0x0000, 0x0000, 0x4c00, 0x2d36,
+};
+
+static const u16 lpphy_rev2plus_noise_scale_table[] = {
+ 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
+ 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
+ 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x0000,
+ 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
+ 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
+ 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
+ 0x00a4,
+};
+
+static const u16 lpphy_crs_gain_nft_table[] = {
+ 0x0366, 0x036a, 0x036f, 0x0364, 0x0367, 0x036d, 0x0374, 0x037f, 0x036f,
+ 0x037b, 0x038a, 0x0378, 0x0367, 0x036d, 0x0375, 0x0381, 0x0374, 0x0381,
+ 0x0392, 0x03a9, 0x03c4, 0x03e1, 0x0001, 0x001f, 0x0040, 0x005e, 0x007f,
+ 0x009e, 0x00bd, 0x00dd, 0x00fd, 0x011d, 0x013d,
+};
+
+static const u16 lpphy_rev01_filter_control_table[] = {
+ 0xa0fc, 0x10fc, 0x10db, 0x20b7, 0xff93, 0x10bf, 0x109b, 0x2077, 0xff53,
+ 0x0127,
+};
+
+static const u32 lpphy_rev2plus_filter_control_table[] = {
+ 0x000141fc, 0x000021fc, 0x000021b7, 0x0000416f, 0x0001ff27, 0x0000217f,
+ 0x00002137, 0x000040ef, 0x0001fea7, 0x0000024f,
+};
+
+static const u32 lpphy_rev01_ps_control_table[] = {
+ 0x00010000, 0x000000a0, 0x00040000, 0x00000048, 0x08080101, 0x00000080,
+ 0x08080101, 0x00000040, 0x08080101, 0x000000c0, 0x08a81501, 0x000000c0,
+ 0x0fe8fd01, 0x000000c0, 0x08300105, 0x000000c0, 0x08080201, 0x000000c0,
+ 0x08280205, 0x000000c0, 0xe80802fe, 0x000000c7, 0x28080206, 0x000000c0,
+ 0x08080202, 0x000000c0, 0x0ba87602, 0x000000c0, 0x1068013d, 0x000000c0,
+ 0x10280105, 0x000000c0, 0x08880102, 0x000000c0, 0x08280106, 0x000000c0,
+ 0xe80801fd, 0x000000c7, 0xa8080115, 0x000000c0,
+};
+
+static const u32 lpphy_rev2plus_ps_control_table[] = {
+ 0x00e38e08, 0x00e08e38, 0x00000000, 0x00000000, 0x00000000, 0x00002080,
+ 0x00006180, 0x00003002, 0x00000040, 0x00002042, 0x00180047, 0x00080043,
+ 0x00000041, 0x000020c1, 0x00046006, 0x00042002, 0x00040000, 0x00002003,
+ 0x00180006, 0x00080002,
+};
+
+static const u8 lpphy_pll_fraction_table[] = {
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+};
+
+static const u16 lpphy_iqlo_cal_table[] = {
+ 0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002,
+ 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600,
+ 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006,
+ 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const u16 lpphy_rev0_ofdm_cck_gain_table[] = {
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001, 0x5001,
+ 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055, 0x2065, 0x2075,
+ 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d, 0x135d, 0x055d, 0x155d,
+ 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d, 0x755d,
+};
+
+static const u16 lpphy_rev1_ofdm_cck_gain_table[] = {
+ 0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001, 0x5001,
+ 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055, 0x2065, 0x2075,
+ 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d, 0x135d, 0x055d, 0x155d,
+ 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d, 0x755d,
+};
+
+static const u16 lpphy_gain_delta_table[] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const u32 lpphy_tx_power_control_table[] = {
+ 0x00000050, 0x0000004f, 0x0000004e, 0x0000004d, 0x0000004c, 0x0000004b,
+ 0x0000004a, 0x00000049, 0x00000048, 0x00000047, 0x00000046, 0x00000045,
+ 0x00000044, 0x00000043, 0x00000042, 0x00000041, 0x00000040, 0x0000003f,
+ 0x0000003e, 0x0000003d, 0x0000003c, 0x0000003b, 0x0000003a, 0x00000039,
+ 0x00000038, 0x00000037, 0x00000036, 0x00000035, 0x00000034, 0x00000033,
+ 0x00000032, 0x00000031, 0x00000030, 0x0000002f, 0x0000002e, 0x0000002d,
+ 0x0000002c, 0x0000002b, 0x0000002a, 0x00000029, 0x00000028, 0x00000027,
+ 0x00000026, 0x00000025, 0x00000024, 0x00000023, 0x00000022, 0x00000021,
+ 0x00000020, 0x0000001f, 0x0000001e, 0x0000001d, 0x0000001c, 0x0000001b,
+ 0x0000001a, 0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015,
+ 0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x000075a0, 0x000075a0, 0x000075a1, 0x000075a1, 0x000075a2, 0x000075a2,
+ 0x000075a3, 0x000075a3, 0x000074b0, 0x000074b0, 0x000074b1, 0x000074b1,
+ 0x000074b2, 0x000074b2, 0x000074b3, 0x000074b3, 0x00006d20, 0x00006d20,
+ 0x00006d21, 0x00006d21, 0x00006d22, 0x00006d22, 0x00006d23, 0x00006d23,
+ 0x00004660, 0x00004660, 0x00004661, 0x00004661, 0x00004662, 0x00004662,
+ 0x00004663, 0x00004663, 0x00003e60, 0x00003e60, 0x00003e61, 0x00003e61,
+ 0x00003e62, 0x00003e62, 0x00003e63, 0x00003e63, 0x00003660, 0x00003660,
+ 0x00003661, 0x00003661, 0x00003662, 0x00003662, 0x00003663, 0x00003663,
+ 0x00002e60, 0x00002e60, 0x00002e61, 0x00002e61, 0x00002e62, 0x00002e62,
+ 0x00002e63, 0x00002e63, 0x00002660, 0x00002660, 0x00002661, 0x00002661,
+ 0x00002662, 0x00002662, 0x00002663, 0x00002663, 0x000025e0, 0x000025e0,
+ 0x000025e1, 0x000025e1, 0x000025e2, 0x000025e2, 0x000025e3, 0x000025e3,
+ 0x00001de0, 0x00001de0, 0x00001de1, 0x00001de1, 0x00001de2, 0x00001de2,
+ 0x00001de3, 0x00001de3, 0x00001d60, 0x00001d60, 0x00001d61, 0x00001d61,
+ 0x00001d62, 0x00001d62, 0x00001d63, 0x00001d63, 0x00001560, 0x00001560,
+ 0x00001561, 0x00001561, 0x00001562, 0x00001562, 0x00001563, 0x00001563,
+ 0x00000d60, 0x00000d60, 0x00000d61, 0x00000d61, 0x00000d62, 0x00000d62,
+ 0x00000d63, 0x00000d63, 0x00000ce0, 0x00000ce0, 0x00000ce1, 0x00000ce1,
+ 0x00000ce2, 0x00000ce2, 0x00000ce3, 0x00000ce3, 0x00000e10, 0x00000e10,
+ 0x00000e11, 0x00000e11, 0x00000e12, 0x00000e12, 0x00000e13, 0x00000e13,
+ 0x00000bf0, 0x00000bf0, 0x00000bf1, 0x00000bf1, 0x00000bf2, 0x00000bf2,
+ 0x00000bf3, 0x00000bf3, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x000000ff, 0x000002fc,
+ 0x0000fa08, 0x00000305, 0x00000206, 0x00000304, 0x0000fb04, 0x0000fcff,
+ 0x000005fb, 0x0000fd01, 0x00000401, 0x00000006, 0x0000ff03, 0x000007fc,
+ 0x0000fc08, 0x00000203, 0x0000fffb, 0x00000600, 0x0000fa01, 0x0000fc03,
+ 0x0000fe06, 0x0000fe00, 0x00000102, 0x000007fd, 0x000004fb, 0x000006ff,
+ 0x000004fd, 0x0000fdfa, 0x000007fb, 0x0000fdfa, 0x0000fa06, 0x00000500,
+ 0x0000f902, 0x000007fa, 0x0000fafa, 0x00000500, 0x000007fa, 0x00000700,
+ 0x00000305, 0x000004ff, 0x00000801, 0x00000503, 0x000005f9, 0x00000404,
+ 0x0000fb08, 0x000005fd, 0x00000501, 0x00000405, 0x0000fb03, 0x000007fc,
+ 0x00000403, 0x00000303, 0x00000402, 0x0000faff, 0x0000fe05, 0x000005fd,
+ 0x0000fe01, 0x000007fa, 0x00000202, 0x00000504, 0x00000102, 0x000008fe,
+ 0x0000fa04, 0x0000fafc, 0x0000fe08, 0x000000f9, 0x000002fa, 0x000003fe,
+ 0x00000304, 0x000004f9, 0x00000100, 0x0000fd06, 0x000008fc, 0x00000701,
+ 0x00000504, 0x0000fdfe, 0x0000fdfc, 0x000003fe, 0x00000704, 0x000002fc,
+ 0x000004f9, 0x0000fdfd, 0x0000fa07, 0x00000205, 0x000003fd, 0x000005fb,
+ 0x000004f9, 0x00000804, 0x0000fc06, 0x0000fcf9, 0x00000100, 0x0000fe05,
+ 0x00000408, 0x0000fb02, 0x00000304, 0x000006fe, 0x000004fa, 0x00000305,
+ 0x000008fc, 0x00000102, 0x000001fd, 0x000004fc, 0x0000fe03, 0x00000701,
+ 0x000001fb, 0x000001f9, 0x00000206, 0x000006fd, 0x00000508, 0x00000700,
+ 0x00000304, 0x000005fe, 0x000005ff, 0x0000fa04, 0x00000303, 0x0000fefb,
+ 0x000007f9, 0x0000fefc, 0x000004fd, 0x000005fc, 0x0000fffd, 0x0000fc08,
+ 0x0000fbf9, 0x0000fd07, 0x000008fb, 0x0000fe02, 0x000006fb, 0x00000702,
+};
+
+static const u32 lpphy_gain_idx_table[] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x10000001, 0x00000000, 0x20000082, 0x00000000, 0x40000104, 0x00000000,
+ 0x60004207, 0x00000001, 0x7000838a, 0x00000001, 0xd021050d, 0x00000001,
+ 0xe041c683, 0x00000001, 0x50828805, 0x00000000, 0x80e34288, 0x00000000,
+ 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, 0x12064711, 0x00000001,
+ 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010, 0x11630915, 0x00000011,
+ 0x31c3ca1b, 0x00000011, 0xc1848a9c, 0x00000018, 0xf1e50da0, 0x00000018,
+ 0x22468e21, 0x00000019, 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019,
+ 0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329, 0x0000001a,
+ 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, 0x54aa152c, 0x0000001a,
+ 0x64ca55ad, 0x0000001a, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x10000001, 0x00000000, 0x20000082, 0x00000000,
+ 0x40000104, 0x00000000, 0x60004207, 0x00000001, 0x7000838a, 0x00000001,
+ 0xd021050d, 0x00000001, 0xe041c683, 0x00000001, 0x50828805, 0x00000000,
+ 0x80e34288, 0x00000000, 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000,
+ 0x12064711, 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010,
+ 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011, 0xc1848a9c, 0x00000018,
+ 0xf1e50da0, 0x00000018, 0x22468e21, 0x00000019, 0x4286d023, 0x00000019,
+ 0xa347d0a4, 0x00000019, 0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019,
+ 0x0408d329, 0x0000001a, 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a,
+ 0x54aa152c, 0x0000001a, 0x64ca55ad, 0x0000001a,
+};
+
+static const u16 lpphy_aux_gain_idx_table[] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0004, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0016,
+};
+
+static const u32 lpphy_gain_value_table[] = {
+ 0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb, 0x00000004,
+ 0x00000008, 0x0000000d, 0x00000001, 0x00000004, 0x00000007, 0x0000000a,
+ 0x0000000d, 0x00000010, 0x00000012, 0x00000015, 0x00000000, 0x00000006,
+ 0x0000000c, 0x00000000, 0x00000000, 0x00000000, 0x00000012, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x0000001e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000003, 0x00000006, 0x00000009, 0x0000000c, 0x0000000f,
+ 0x00000012, 0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009, 0x000000f1,
+ 0x00000000, 0x00000000,
+};
+
+static const u16 lpphy_gain_table[] = {
+ 0x0000, 0x0400, 0x0800, 0x0802, 0x0804, 0x0806, 0x0807, 0x0808, 0x080a,
+ 0x080b, 0x080c, 0x080e, 0x080f, 0x0810, 0x0812, 0x0813, 0x0814, 0x0816,
+ 0x0817, 0x081a, 0x081b, 0x081f, 0x0820, 0x0824, 0x0830, 0x0834, 0x0837,
+ 0x083b, 0x083f, 0x0840, 0x0844, 0x0857, 0x085b, 0x085f, 0x08d7, 0x08db,
+ 0x08df, 0x0957, 0x095b, 0x095f, 0x0b57, 0x0b5b, 0x0b5f, 0x0f5f, 0x135f,
+ 0x175f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const u32 lpphy_a0_gain_idx_table[] = {
+ 0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060, 0x00511065,
+ 0x004c806b, 0x0047d072, 0x00444078, 0x00400080, 0x003ca087, 0x0039408f,
+ 0x0035e098, 0x0032e0a1, 0x003030aa, 0x002d80b4, 0x002ae0bf, 0x002880ca,
+ 0x002640d6, 0x002410e3, 0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e,
+ 0x001b012f, 0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
+ 0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a, 0x000e523a,
+ 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd, 0x000ac2f8, 0x000a2325,
+ 0x00099355, 0x00091387, 0x000883bd, 0x000813f5, 0x0007a432, 0x00073471,
+ 0x0006c4b5, 0x000664fc, 0x00061547, 0x0005b598, 0x000565ec, 0x00051646,
+ 0x0004d6a5, 0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
+ 0x00036963, 0x000339f2, 0x00030a89, 0x0002db28,
+};
+
+static const u16 lpphy_a0_aux_gain_idx_table[] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0002, 0x0014, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0014,
+};
+
+static const u32 lpphy_a0_gain_value_table[] = {
+ 0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb, 0x00000004,
+ 0x00000008, 0x0000000d, 0x00000001, 0x00000004, 0x00000007, 0x0000000a,
+ 0x0000000d, 0x00000010, 0x00000012, 0x00000015, 0x00000000, 0x00000006,
+ 0x0000000c, 0x00000000, 0x00000000, 0x00000000, 0x00000012, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x0000001e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000003, 0x00000006, 0x00000009, 0x0000000c, 0x0000000f,
+ 0x00000012, 0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f, 0x000000f7,
+ 0x00000000, 0x00000000,
+};
+
+static const u16 lpphy_a0_gain_table[] = {
+ 0x0000, 0x0002, 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c,
+ 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, 0x0014, 0x0016, 0x0017, 0x001a,
+ 0x001b, 0x001f, 0x0020, 0x0024, 0x0030, 0x0034, 0x0037, 0x003b, 0x003f,
+ 0x0040, 0x0044, 0x0057, 0x005b, 0x005f, 0x00d7, 0x00db, 0x00df, 0x0157,
+ 0x015b, 0x015f, 0x0357, 0x035b, 0x035f, 0x075f, 0x0b5f, 0x0f5f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const u16 lpphy_sw_control_table[] = {
+ 0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028, 0x0128,
+ 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028, 0x0009, 0x0009,
+ 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0018, 0x0018, 0x0018,
+ 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0128, 0x0128, 0x0009, 0x0009,
+ 0x0028, 0x0028, 0x0028, 0x0028, 0x0128, 0x0128, 0x0009, 0x0009, 0x0028,
+ 0x0028, 0x0028, 0x0028, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
+ 0x0009, 0x0009, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
+ 0x0018,
+};
+
+static const u8 lpphy_hf_table[] = {
+ 0x4b, 0x36, 0x24, 0x18, 0x49, 0x34, 0x23, 0x17, 0x48,
+ 0x33, 0x23, 0x17, 0x48, 0x33, 0x23, 0x17,
+};
+
+static const u32 lpphy_papd_eps_table[] = {
+ 0x00000000, 0x00013ffc, 0x0001dff3, 0x0001bff0, 0x00023fe9, 0x00021fdf,
+ 0x00028fdf, 0x00033fd2, 0x00039fcb, 0x00043fc7, 0x0004efc2, 0x00055fb5,
+ 0x0005cfb0, 0x00063fa8, 0x00068fa3, 0x00071f98, 0x0007ef92, 0x00084f8b,
+ 0x0008df82, 0x00097f77, 0x0009df69, 0x000a3f62, 0x000adf57, 0x000b6f4c,
+ 0x000bff41, 0x000c9f39, 0x000cff30, 0x000dbf27, 0x000e4f1e, 0x000edf16,
+ 0x000f7f13, 0x00102f11, 0x00110f10, 0x0011df11, 0x0012ef15, 0x00143f1c,
+ 0x00158f27, 0x00172f35, 0x00193f47, 0x001baf5f, 0x001e6f7e, 0x0021cfa4,
+ 0x0025bfd2, 0x002a2008, 0x002fb047, 0x00360090, 0x003d40e0, 0x0045c135,
+ 0x004fb189, 0x005ae1d7, 0x0067221d, 0x0075025a, 0x007ff291, 0x007ff2bf,
+ 0x007ff2e3, 0x007ff2ff, 0x007ff315, 0x007ff329, 0x007ff33f, 0x007ff356,
+ 0x007ff36e, 0x007ff39c, 0x007ff441, 0x007ff506,
+};
+
+static const u32 lpphy_papd_mult_table[] = {
+ 0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060, 0x00511065,
+ 0x004c806b, 0x0047d072, 0x00444078, 0x00400080, 0x003ca087, 0x0039408f,
+ 0x0035e098, 0x0032e0a1, 0x003030aa, 0x002d80b4, 0x002ae0bf, 0x002880ca,
+ 0x002640d6, 0x002410e3, 0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e,
+ 0x001b012f, 0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
+ 0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a, 0x000e523a,
+ 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd, 0x000ac2f8, 0x000a2325,
+ 0x00099355, 0x00091387, 0x000883bd, 0x000813f5, 0x0007a432, 0x00073471,
+ 0x0006c4b5, 0x000664fc, 0x00061547, 0x0005b598, 0x000565ec, 0x00051646,
+ 0x0004d6a5, 0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
+ 0x00036963, 0x000339f2, 0x00030a89, 0x0002db28,
+};
+
+static struct lpphy_tx_gain_table_entry lpphy_rev0_nopa_tx_gain_table[] = {
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 152, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 147, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 143, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 139, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 135, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 131, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 128, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 124, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 121, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 117, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 114, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 111, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 107, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 104, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 101, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 99, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 96, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 93, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 90, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 88, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 85, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 83, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 81, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 78, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 76, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 74, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 71, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 56, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, },
+};
+
+static struct lpphy_tx_gain_table_entry lpphy_rev0_2ghz_tx_gain_table[] = {
+ { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 63, },
+ { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 71, },
+ { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 69, },
+ { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 67, },
+ { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 65, },
+ { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 63, },
+ { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 58, },
+ { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 65, },
+ { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 63, },
+ { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 67, },
+ { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 65, },
+ { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 63, },
+ { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 65, },
+ { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 63, },
+ { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 58, },
+ { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 57, },
+ { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 83, },
+ { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 81, },
+ { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 78, },
+ { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 76, },
+ { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 74, },
+ { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 72, },
+};
+
+static struct lpphy_tx_gain_table_entry lpphy_rev0_5ghz_tx_gain_table[] = {
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 99, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 96, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 93, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 90, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 88, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 85, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 83, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 81, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 78, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 76, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 74, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 55, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 56, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 55, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 71, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 56, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 73, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 71, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 56, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, },
+};
+
+static struct lpphy_tx_gain_table_entry lpphy_rev1_nopa_tx_gain_table[] = {
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 152, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 147, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 143, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 139, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 135, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 131, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 128, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 124, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 121, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 117, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 114, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 111, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 107, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 104, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 101, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 99, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 96, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 93, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 90, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 88, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 85, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 83, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 81, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 78, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 76, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 74, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 71, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 56, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, },
+};
+
+static struct lpphy_tx_gain_table_entry lpphy_rev1_2ghz_tx_gain_table[] = {
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 90, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 88, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 85, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 83, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 81, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 78, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 76, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 74, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 61, },
+ { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 72, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 70, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 68, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 66, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 64, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 62, },
+ { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 60, },
+};
+
+static struct lpphy_tx_gain_table_entry lpphy_rev1_5ghz_tx_gain_table[] = {
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 99, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 96, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 93, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 90, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 88, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 85, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 83, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 81, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 78, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 76, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 74, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 55, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 56, },
+ { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 55, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 71, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 56, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 72, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 73, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 71, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 56, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 58, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, },
+ { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 57, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 62, },
+ { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, },
+};
+
+static struct lpphy_tx_gain_table_entry lpphy_rev2_nopa_tx_gain_table[] = {
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 152, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 147, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 143, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 139, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 135, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 131, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 128, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 124, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 121, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 117, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 114, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 111, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 107, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 104, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 101, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 99, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 96, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 93, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 90, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 88, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 85, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 83, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 81, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 78, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 76, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 74, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 72, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 70, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 68, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 66, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 197, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 192, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 186, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 181, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 176, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 171, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 166, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 161, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 157, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 152, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 148, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 144, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 140, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 136, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 132, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 128, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 124, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 121, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 117, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 114, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 111, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 108, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 105, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 102, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 99, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 96, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 93, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 91, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 88, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 86, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 83, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 81, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 79, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 76, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 74, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 72, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 70, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 68, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 66, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 64, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 248, .pad = 64, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 248, .pad = 62, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 241, .pad = 62, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 241, .pad = 60, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 234, .pad = 60, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 234, .pad = 59, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 227, .pad = 59, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 227, .pad = 57, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 221, .pad = 57, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 221, .pad = 55, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 215, .pad = 55, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 215, .pad = 54, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 208, .pad = 54, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 208, .pad = 52, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 203, .pad = 52, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 203, .pad = 51, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 197, .pad = 51, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 197, .pad = 49, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 191, .pad = 49, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 191, .pad = 48, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 186, .pad = 48, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 186, .pad = 47, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 181, .pad = 47, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 181, .pad = 45, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 175, .pad = 45, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 175, .pad = 44, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 170, .pad = 44, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 170, .pad = 43, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 166, .pad = 43, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 166, .pad = 42, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 161, .pad = 42, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 161, .pad = 40, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 156, .pad = 40, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 156, .pad = 39, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 152, .pad = 39, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 152, .pad = 38, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 148, .pad = 38, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 148, .pad = 37, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 143, .pad = 37, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 143, .pad = 36, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 139, .pad = 36, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 139, .pad = 35, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 135, .pad = 35, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 135, .pad = 34, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 132, .pad = 34, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 132, .pad = 33, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 128, .pad = 33, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 128, .pad = 32, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 124, .pad = 32, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 124, .pad = 31, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 121, .pad = 31, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 121, .pad = 30, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 117, .pad = 30, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 117, .pad = 29, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 114, .pad = 29, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 114, .pad = 29, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 111, .pad = 29, .dac = 0, .bb_mult = 64, },
+};
+
+static struct lpphy_tx_gain_table_entry lpphy_rev2_2ghz_tx_gain_table[] = {
+ { .gm = 7, .pga = 99, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 96, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 93, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 90, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 88, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 85, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 83, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 81, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 78, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 76, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 74, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 72, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 70, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 68, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 66, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 62, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 62, .pad = 248, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 60, .pad = 248, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 60, .pad = 241, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 59, .pad = 241, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 59, .pad = 234, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 57, .pad = 234, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 57, .pad = 227, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 55, .pad = 227, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 55, .pad = 221, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 54, .pad = 221, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 54, .pad = 215, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 52, .pad = 215, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 52, .pad = 208, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 51, .pad = 208, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 51, .pad = 203, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 49, .pad = 203, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 49, .pad = 197, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 48, .pad = 197, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 48, .pad = 191, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 47, .pad = 191, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 47, .pad = 186, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 45, .pad = 186, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 45, .pad = 181, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 44, .pad = 181, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 44, .pad = 175, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 43, .pad = 175, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 43, .pad = 170, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 42, .pad = 170, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 42, .pad = 166, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 40, .pad = 166, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 40, .pad = 161, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 39, .pad = 161, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 39, .pad = 156, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 38, .pad = 156, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 38, .pad = 152, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 37, .pad = 152, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 37, .pad = 148, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 36, .pad = 148, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 36, .pad = 143, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 35, .pad = 143, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 35, .pad = 139, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 34, .pad = 139, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 34, .pad = 135, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 33, .pad = 135, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 33, .pad = 132, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 32, .pad = 132, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 32, .pad = 128, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 31, .pad = 128, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 31, .pad = 124, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 30, .pad = 124, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 30, .pad = 121, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 29, .pad = 121, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 29, .pad = 117, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 29, .pad = 117, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 29, .pad = 114, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 28, .pad = 114, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 28, .pad = 111, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 27, .pad = 111, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 27, .pad = 108, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 26, .pad = 108, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 26, .pad = 104, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 25, .pad = 104, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 25, .pad = 102, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 25, .pad = 102, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 25, .pad = 99, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 24, .pad = 99, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 24, .pad = 96, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 23, .pad = 96, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 23, .pad = 93, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 23, .pad = 93, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 23, .pad = 90, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 22, .pad = 90, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 22, .pad = 88, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 21, .pad = 88, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 21, .pad = 85, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 21, .pad = 85, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 21, .pad = 83, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 20, .pad = 83, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 20, .pad = 81, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 20, .pad = 81, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 20, .pad = 78, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 19, .pad = 78, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 19, .pad = 76, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 19, .pad = 76, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 19, .pad = 74, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 18, .pad = 74, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 18, .pad = 72, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 18, .pad = 72, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 18, .pad = 70, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 17, .pad = 70, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 17, .pad = 68, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 17, .pad = 68, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 17, .pad = 66, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 16, .pad = 66, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 16, .pad = 64, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 16, .pad = 64, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 16, .pad = 62, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 62, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 60, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 60, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 15, .pad = 59, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 14, .pad = 59, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 14, .pad = 57, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 14, .pad = 57, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 14, .pad = 55, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 14, .pad = 55, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 14, .pad = 54, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 13, .pad = 54, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 13, .pad = 52, .dac = 0, .bb_mult = 64, },
+ { .gm = 7, .pga = 13, .pad = 52, .dac = 0, .bb_mult = 64, },
+};
+
+static struct lpphy_tx_gain_table_entry lpphy_rev2_5ghz_tx_gain_table[] = {
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 152, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 147, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 143, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 139, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 135, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 131, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 128, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 124, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 121, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 117, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 114, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 111, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 107, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 104, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 101, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 99, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 96, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 93, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 90, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 88, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 85, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 83, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 81, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 78, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 76, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 74, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 72, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 70, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 68, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 66, },
+ { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 248, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 241, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 234, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 227, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 221, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 215, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 208, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 197, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 191, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 186, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 181, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 175, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 170, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 166, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 161, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 156, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 152, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 148, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 143, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 139, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 135, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 132, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 128, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 124, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 121, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 117, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 114, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 111, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 108, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 104, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 102, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 99, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 96, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 93, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 90, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 88, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 85, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 83, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 81, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 78, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 76, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 74, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 72, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 70, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 68, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 66, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 64, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 64, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 255, .pad = 62, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 248, .pad = 62, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 248, .pad = 60, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 241, .pad = 60, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 241, .pad = 59, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 234, .pad = 59, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 234, .pad = 57, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 227, .pad = 57, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 227, .pad = 55, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 221, .pad = 55, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 221, .pad = 54, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 215, .pad = 54, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 215, .pad = 52, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 208, .pad = 52, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 208, .pad = 51, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 203, .pad = 51, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 203, .pad = 49, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 197, .pad = 49, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 197, .pad = 48, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 191, .pad = 48, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 191, .pad = 47, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 186, .pad = 47, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 186, .pad = 45, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 181, .pad = 45, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 181, .pad = 44, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 175, .pad = 44, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 175, .pad = 43, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 170, .pad = 43, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 170, .pad = 42, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 166, .pad = 42, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 166, .pad = 40, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 161, .pad = 40, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 161, .pad = 39, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 156, .pad = 39, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 156, .pad = 38, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 152, .pad = 38, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 152, .pad = 37, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 148, .pad = 37, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 148, .pad = 36, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 143, .pad = 36, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 143, .pad = 35, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 139, .pad = 35, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 139, .pad = 34, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 135, .pad = 34, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 135, .pad = 33, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 132, .pad = 33, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 132, .pad = 32, .dac = 0, .bb_mult = 64, },
+ { .gm = 255, .pga = 128, .pad = 32, .dac = 0, .bb_mult = 64, },
+};
+
+void lpphy_rev0_1_table_init(struct b43_wldev *dev)
+{
+ B43_WARN_ON(dev->phy.rev >= 2);
+
+ b43_lptab_write_bulk(dev, B43_LPTAB8(2, 0),
+ ARRAY_SIZE(lpphy_min_sig_sq_table), lpphy_min_sig_sq_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(1, 0),
+ ARRAY_SIZE(lpphy_rev01_noise_scale_table), lpphy_rev01_noise_scale_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0),
+ ARRAY_SIZE(lpphy_crs_gain_nft_table), lpphy_crs_gain_nft_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(8, 0),
+ ARRAY_SIZE(lpphy_rev01_filter_control_table), lpphy_rev01_filter_control_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB32(9, 0),
+ ARRAY_SIZE(lpphy_rev01_ps_control_table), lpphy_rev01_ps_control_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0),
+ ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0),
+ ARRAY_SIZE(lpphy_iqlo_cal_table), lpphy_iqlo_cal_table);
+ if (dev->phy.rev == 0) {
+ b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0),
+ ARRAY_SIZE(lpphy_rev0_ofdm_cck_gain_table), lpphy_rev0_ofdm_cck_gain_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0),
+ ARRAY_SIZE(lpphy_rev0_ofdm_cck_gain_table), lpphy_rev0_ofdm_cck_gain_table);
+ } else {
+ b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0),
+ ARRAY_SIZE(lpphy_rev1_ofdm_cck_gain_table), lpphy_rev1_ofdm_cck_gain_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0),
+ ARRAY_SIZE(lpphy_rev1_ofdm_cck_gain_table), lpphy_rev1_ofdm_cck_gain_table);
+}
+ b43_lptab_write_bulk(dev, B43_LPTAB16(15, 0),
+ ARRAY_SIZE(lpphy_gain_delta_table), lpphy_gain_delta_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0),
+ ARRAY_SIZE(lpphy_tx_power_control_table), lpphy_tx_power_control_table);
+}
+
+void lpphy_rev2plus_table_init(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ int i;
+
+ B43_WARN_ON(dev->phy.rev < 2);
+
+ for (i = 0; i < 704; i++)
+ b43_lptab_write(dev, B43_LPTAB32(7, i), 0);
+
+ b43_lptab_write_bulk(dev, B43_LPTAB8(2, 0),
+ ARRAY_SIZE(lpphy_min_sig_sq_table), lpphy_min_sig_sq_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(1, 0),
+ ARRAY_SIZE(lpphy_rev2plus_noise_scale_table), lpphy_rev2plus_noise_scale_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB32(11, 0),
+ ARRAY_SIZE(lpphy_rev2plus_filter_control_table), lpphy_rev2plus_filter_control_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB32(12, 0),
+ ARRAY_SIZE(lpphy_rev2plus_ps_control_table), lpphy_rev2plus_ps_control_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB32(13, 0),
+ ARRAY_SIZE(lpphy_gain_idx_table), lpphy_gain_idx_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0),
+ ARRAY_SIZE(lpphy_aux_gain_idx_table), lpphy_aux_gain_idx_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(15, 0),
+ ARRAY_SIZE(lpphy_sw_control_table), lpphy_sw_control_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB8(16, 0),
+ ARRAY_SIZE(lpphy_hf_table), lpphy_hf_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB32(17, 0),
+ ARRAY_SIZE(lpphy_gain_value_table), lpphy_gain_value_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(18, 0),
+ ARRAY_SIZE(lpphy_gain_table), lpphy_gain_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0),
+ ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0),
+ ARRAY_SIZE(lpphy_iqlo_cal_table), lpphy_iqlo_cal_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB32(9, 0),
+ ARRAY_SIZE(lpphy_papd_eps_table), lpphy_papd_eps_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0),
+ ARRAY_SIZE(lpphy_papd_mult_table), lpphy_papd_mult_table);
+
+ if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
+ b43_lptab_write_bulk(dev, B43_LPTAB32(13, 0),
+ ARRAY_SIZE(lpphy_a0_gain_idx_table), lpphy_a0_gain_idx_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0),
+ ARRAY_SIZE(lpphy_a0_aux_gain_idx_table), lpphy_a0_aux_gain_idx_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB32(17, 0),
+ ARRAY_SIZE(lpphy_a0_gain_value_table), lpphy_a0_gain_value_table);
+ b43_lptab_write_bulk(dev, B43_LPTAB16(18, 0),
+ ARRAY_SIZE(lpphy_a0_gain_table), lpphy_a0_gain_table);
+ }
+}
+
+static void lpphy_rev0_1_write_gain_table(struct b43_wldev *dev, int offset,
+ struct lpphy_tx_gain_table_entry data)
+{
+ u32 tmp;
+
+ B43_WARN_ON(dev->phy.rev >= 2);
+
+ tmp = data.pad << 11;
+ tmp |= data.pga << 7;
+ tmp |= data.gm << 4;
+ tmp |= data.dac;
+ b43_lptab_write(dev, B43_LPTAB32(10, 0xC0 + offset), tmp);
+ tmp = data.bb_mult << 20;
+ b43_lptab_write(dev, B43_LPTAB32(10, 0x140 + offset), tmp);
+}
+
+static void lpphy_rev2plus_write_gain_table(struct b43_wldev *dev, int offset,
+ struct lpphy_tx_gain_table_entry data)
+{
+ u32 tmp;
+
+ B43_WARN_ON(dev->phy.rev < 2);
+
+ tmp = data.pad << 16;
+ tmp |= data.pga << 8;
+ tmp |= data.gm;
+ if (dev->phy.rev >= 3) {
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+ tmp |= 0x10 << 24;
+ else
+ tmp |= 0x70 << 24;
+ } else {
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+ tmp |= 0x14 << 24;
+ else
+ tmp |= 0x7F << 24;
+ }
+ b43_lptab_write(dev, B43_LPTAB32(7, 0xC0 + offset), tmp);
+ tmp = data.bb_mult << 20;
+ tmp |= data.dac << 28;
+ b43_lptab_write(dev, B43_LPTAB32(7, 0x140 + offset), tmp);
+}
+
+void lpphy_write_gain_table(struct b43_wldev *dev, int offset,
+ struct lpphy_tx_gain_table_entry data)
+{
+ if (dev->phy.rev >= 2)
+ lpphy_rev2plus_write_gain_table(dev, offset, data);
+ else
+ lpphy_rev0_1_write_gain_table(dev, offset, data);
+}
+
+void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count,
+ struct lpphy_tx_gain_table_entry *table)
+{
+ int i;
+
+ for (i = offset; i < count; i++)
+ lpphy_write_gain_table(dev, i, table[i]);
+}
+
+void lpphy_init_tx_gain_table(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+
+ switch (dev->phy.rev) {
+ case 0:
+ if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) ||
+ (bus->sprom.boardflags_lo & B43_BFL_HGPA))
+ lpphy_write_gain_table_bulk(dev, 0, 128,
+ lpphy_rev0_nopa_tx_gain_table);
+ else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ lpphy_write_gain_table_bulk(dev, 0, 128,
+ lpphy_rev0_2ghz_tx_gain_table);
+ else
+ lpphy_write_gain_table_bulk(dev, 0, 128,
+ lpphy_rev0_5ghz_tx_gain_table);
+ break;
+ case 1:
+ if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) ||
+ (bus->sprom.boardflags_lo & B43_BFL_HGPA))
+ lpphy_write_gain_table_bulk(dev, 0, 128,
+ lpphy_rev1_nopa_tx_gain_table);
+ else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ lpphy_write_gain_table_bulk(dev, 0, 128,
+ lpphy_rev1_2ghz_tx_gain_table);
+ else
+ lpphy_write_gain_table_bulk(dev, 0, 128,
+ lpphy_rev1_5ghz_tx_gain_table);
+ break;
+ default:
+ if (bus->sprom.boardflags_hi & B43_BFH_NOPA)
+ lpphy_write_gain_table_bulk(dev, 0, 128,
+ lpphy_rev2_nopa_tx_gain_table);
+ else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ lpphy_write_gain_table_bulk(dev, 0, 128,
+ lpphy_rev2_2ghz_tx_gain_table);
+ else
+ lpphy_write_gain_table_bulk(dev, 0, 128,
+ lpphy_rev2_5ghz_tx_gain_table);
}
}
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,
unsigned int nr_elements, const void *data);
void b2062_upload_init_table(struct b43_wldev *dev);
+void b2063_upload_init_table(struct b43_wldev *dev);
+struct lpphy_tx_gain_table_entry {
+ u8 gm, pga, pad, dac, bb_mult;
+};
+
+void lpphy_write_gain_table(struct b43_wldev *dev, int offset,
+ struct lpphy_tx_gain_table_entry data);
+void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count,
+ struct lpphy_tx_gain_table_entry *table);
+
+void lpphy_rev0_1_table_init(struct b43_wldev *dev);
+void lpphy_rev2plus_table_init(struct b43_wldev *dev);
+void lpphy_init_tx_gain_table(struct b43_wldev *dev);
#endif /* B43_TABLES_LPPHY_H_ */
diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c
index e1e20f69f6d7..97c79161c208 100644
--- a/drivers/net/wireless/b43/wa.c
+++ b/drivers/net/wireless/b43/wa.c
@@ -37,7 +37,7 @@ static void b43_wa_papd(struct b43_wldev *dev)
backup = b43_ofdmtab_read16(dev, B43_OFDMTAB_PWRDYN2, 0);
b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, 7);
b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 0, 0);
- b43_dummy_transmission(dev);
+ b43_dummy_transmission(dev, true, true);
b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, backup);
}
@@ -628,7 +628,7 @@ void b43_wa_all(struct b43_wldev *dev)
B43_WARN_ON(1);
}
b43_wa_boards_g(dev);
- } else { /* No N PHY support so far */
+ } else { /* No N PHY support so far, LP PHY is in phy_lp.c */
B43_WARN_ON(1);
}
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index 55f36a7254d9..14f541248b5c 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -180,11 +180,12 @@ static u8 b43_calc_fallback_rate(u8 bitrate)
/* Generate a TX data header. */
int b43_generate_txhdr(struct b43_wldev *dev,
u8 *_txhdr,
- const unsigned char *fragment_data,
- unsigned int fragment_len,
+ struct sk_buff *skb_frag,
struct ieee80211_tx_info *info,
u16 cookie)
{
+ const unsigned char *fragment_data = skb_frag->data;
+ unsigned int fragment_len = skb_frag->len;
struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
const struct b43_phy *phy = &dev->phy;
const struct ieee80211_hdr *wlhdr =
@@ -237,7 +238,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
int wlhdr_len;
size_t iv_len;
- B43_WARN_ON(key_idx >= dev->max_nr_keys);
+ B43_WARN_ON(key_idx >= ARRAY_SIZE(dev->key));
key = &(dev->key[key_idx]);
if (unlikely(!key->keyconf)) {
@@ -258,9 +259,26 @@ int b43_generate_txhdr(struct b43_wldev *dev,
mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
B43_TXH_MAC_KEYALG;
wlhdr_len = ieee80211_hdrlen(fctl);
- iv_len = min((size_t) info->control.hw_key->iv_len,
- ARRAY_SIZE(txhdr->iv));
- memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
+ if (key->algorithm == B43_SEC_ALGO_TKIP) {
+ u16 phase1key[5];
+ int i;
+ /* we give the phase1key and iv16 here, the key is stored in
+ * shm. With that the hardware can do phase 2 and encryption.
+ */
+ ieee80211_get_tkip_key(info->control.hw_key, skb_frag,
+ IEEE80211_TKIP_P1_KEY, (u8*)phase1key);
+ /* phase1key is in host endian. Copy to little-endian txhdr->iv. */
+ for (i = 0; i < 5; i++) {
+ txhdr->iv[i * 2 + 0] = phase1key[i];
+ txhdr->iv[i * 2 + 1] = phase1key[i] >> 8;
+ }
+ /* iv16 */
+ memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3);
+ } else {
+ iv_len = min((size_t) info->control.hw_key->iv_len,
+ ARRAY_SIZE(txhdr->iv));
+ memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
+ }
}
if (b43_is_old_txhdr_format(dev)) {
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp),
@@ -578,7 +596,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
* key index, but the ucode passed it slightly different.
*/
keyidx = b43_kidx_to_raw(dev, keyidx);
- B43_WARN_ON(keyidx >= dev->max_nr_keys);
+ B43_WARN_ON(keyidx >= ARRAY_SIZE(dev->key));
if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) {
wlhdr_len = ieee80211_hdrlen(fctl);
@@ -655,6 +673,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
status.freq = chanid + 2400;
break;
case B43_PHYTYPE_N:
+ case B43_PHYTYPE_LP:
/* chanid is the SHM channel cookie. Which is the plain
* channel number in b43. */
if (chanstat & B43_RX_CHAN_5GHZ) {
@@ -670,7 +689,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
goto drop;
}
- ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(dev->wl->hw, skb);
return;
drop:
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index 4fb2a190f7a7..3530de871873 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -176,8 +176,7 @@ size_t b43_txhdr_size(struct b43_wldev *dev)
int b43_generate_txhdr(struct b43_wldev *dev,
u8 * txhdr,
- const unsigned char *fragment_data,
- unsigned int fragment_len,
+ struct sk_buff *skb_frag,
struct ieee80211_tx_info *txctl, u16 cookie);
/* Transmit Status */
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index 2f90fb9f5367..866403415811 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -1366,15 +1366,25 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
ring = priority_to_txring(dev, skb_get_queue_mapping(skb));
spin_lock_irqsave(&ring->lock, flags);
B43legacy_WARN_ON(!ring->tx);
- if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
- b43legacywarn(dev->wl, "DMA queue overflow\n");
+
+ if (unlikely(ring->stopped)) {
+ /* We get here only because of a bug in mac80211.
+ * Because of a race, one packet may be queued after
+ * the queue is stopped, thus we got called when we shouldn't.
+ * For now, just refuse the transmit. */
+ if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
+ b43legacyerr(dev->wl, "Packet after queue stopped\n");
+ err = -ENOSPC;
+ goto out_unlock;
+ }
+
+ if (unlikely(WARN_ON(free_slots(ring) < SLOTS_PER_PACKET))) {
+ /* If we get here, we have a real error with the queue
+ * full, but queues not stopped. */
+ b43legacyerr(dev->wl, "DMA queue overflow\n");
err = -ENOSPC;
goto out_unlock;
}
- /* Check if the queue was stopped in mac80211,
- * but we got called nevertheless.
- * That would be a mac80211 bug. */
- B43legacy_BUG_ON(ring->stopped);
err = dma_tx_fragment(ring, skb);
if (unlikely(err == -ENOKEY)) {
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index c4973c1942bf..1d9223b3d4c4 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1252,7 +1252,7 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl)
wl->current_beacon = beacon;
wl->beacon0_uploaded = 0;
wl->beacon1_uploaded = 0;
- queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
+ ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
}
static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
@@ -2300,7 +2300,7 @@ out_requeue:
delay = msecs_to_jiffies(50);
else
delay = round_jiffies_relative(HZ * 15);
- queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay);
+ ieee80211_queue_delayed_work(wl->hw, &dev->periodic_work, delay);
out:
mutex_unlock(&wl->mutex);
}
@@ -2311,7 +2311,7 @@ static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev)
dev->periodic_state = 0;
INIT_DELAYED_WORK(work, b43legacy_periodic_work_handler);
- queue_delayed_work(dev->wl->hw->workqueue, work, 0);
+ ieee80211_queue_delayed_work(dev->wl->hw, work, 0);
}
/* Validate access to the chip (SHM) */
@@ -2836,9 +2836,7 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw,
static void b43legacy_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed,
- unsigned int *fflags,
- int mc_count,
- struct dev_addr_list *mc_list)
+ unsigned int *fflags,u64 multicast)
{
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
struct b43legacy_wldev *dev = wl->current_dev;
@@ -3108,16 +3106,20 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev)
bus->pcicore.dev->id.revision <= 5) {
/* IMCFGLO timeouts workaround. */
tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
- tmp &= ~SSB_IMCFGLO_REQTO;
- tmp &= ~SSB_IMCFGLO_SERTO;
switch (bus->bustype) {
case SSB_BUSTYPE_PCI:
case SSB_BUSTYPE_PCMCIA:
+ tmp &= ~SSB_IMCFGLO_REQTO;
+ tmp &= ~SSB_IMCFGLO_SERTO;
tmp |= 0x32;
break;
case SSB_BUSTYPE_SSB:
+ tmp &= ~SSB_IMCFGLO_REQTO;
+ tmp &= ~SSB_IMCFGLO_SERTO;
tmp |= 0x53;
break;
+ default:
+ break;
}
ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
}
@@ -3885,7 +3887,7 @@ void b43legacy_controller_restart(struct b43legacy_wldev *dev,
if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
return;
b43legacyinfo(dev->wl, "Controller RESET (%s) ...\n", reason);
- queue_work(dev->wl->hw->workqueue, &dev->restart_work);
+ ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index b8e39dd06e99..103f3c9e7f58 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -590,8 +590,8 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
chanstat);
}
- dev->stats.last_rx = jiffies;
- ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(dev->wl->hw, skb);
return;
drop:
diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h
index 2e9fb0f383fc..7f9d8d976aa8 100644
--- a/drivers/net/wireless/hostap/hostap_80211.h
+++ b/drivers/net/wireless/hostap/hostap_80211.h
@@ -3,6 +3,7 @@
#include <linux/types.h>
#include <linux/skbuff.h>
+#include <linux/netdevice.h>
struct hostap_ieee80211_mgmt {
__le16 frame_control;
@@ -85,8 +86,11 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
struct hostap_80211_rx_status *rx_stats);
void hostap_dump_tx_80211(const char *name, struct sk_buff *skb);
-int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev);
-int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev);
-int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
+netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb,
+ struct net_device *dev);
+netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb,
+ struct net_device *dev);
+netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb,
+ struct net_device *dev);
#endif /* HOSTAP_80211_H */
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index d313b005114e..90108b698f11 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -53,7 +53,8 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
/* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta)
* Convert Ethernet header into a suitable IEEE 802.11 header depending on
* device configuration. */
-int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
+netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
struct hostap_interface *iface;
local_info_t *local;
@@ -75,7 +76,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb "
"(len=%d)\n", dev->name, skb->len);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (local->ddev != dev) {
@@ -89,14 +90,14 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: prism2_tx: trying to use "
"AP device with Ethernet net dev\n", dev->name);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
} else {
if (local->iw_mode == IW_MODE_REPEAT) {
printk(KERN_DEBUG "%s: prism2_tx: trying to use "
"non-WDS link in Repeater mode\n", dev->name);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else if (local->iw_mode == IW_MODE_INFRA &&
(local->wds_type & HOSTAP_WDS_AP_CLIENT) &&
memcmp(skb->data + ETH_ALEN, dev->dev_addr,
@@ -210,13 +211,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb = skb_unshare(skb, GFP_ATOMIC);
if (skb == NULL) {
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
if (pskb_expand_head(skb, need_headroom, need_tailroom,
GFP_ATOMIC)) {
kfree_skb(skb);
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
} else if (skb_headroom(skb) < need_headroom) {
struct sk_buff *tmp = skb;
@@ -224,13 +225,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
kfree_skb(tmp);
if (skb == NULL) {
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
} else {
skb = skb_unshare(skb, GFP_ATOMIC);
if (skb == NULL) {
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -256,12 +257,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Send IEEE 802.11 encapsulated frame using the master radio device */
skb->dev = local->dev;
dev_queue_xmit(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* hard_start_xmit function for hostapd wlan#ap interfaces */
-int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
+netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
struct hostap_interface *iface;
local_info_t *local;
@@ -276,7 +278,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb "
"(len=%d)\n", dev->name, skb->len);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
iface->stats.tx_packets++;
@@ -301,7 +303,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Send IEEE 802.11 encapsulated frame using the master radio device */
skb->dev = local->dev;
dev_queue_xmit(skb);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -373,11 +375,12 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
/* hard_start_xmit function for master radio interface wifi#.
* AP processing (TX rate control, power save buffering, etc.).
* Use hardware TX function to send the frame. */
-int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
+netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
struct hostap_interface *iface;
local_info_t *local;
- int ret = NETDEV_TX_BUSY;
+ netdev_tx_t ret = NETDEV_TX_BUSY;
u16 fc;
struct hostap_tx_data tx;
ap_tx_ret tx_ret;
@@ -396,7 +399,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
"expected 0x%08x)\n",
dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC);
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
goto fail;
}
@@ -414,7 +417,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < 24) {
printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb "
"(len=%d)\n", dev->name, skb->len);
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
goto fail;
}
@@ -441,13 +444,13 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->name, meta->ethertype);
hostap_dump_tx_80211(dev->name, skb);
- ret = 0; /* drop packet */
+ ret = NETDEV_TX_OK; /* drop packet */
iface->stats.tx_dropped++;
goto fail;
}
break;
case AP_TX_DROP:
- ret = 0; /* drop packet */
+ ret = NETDEV_TX_OK; /* drop packet */
iface->stats.tx_dropped++;
goto fail;
case AP_TX_RETRY:
@@ -455,7 +458,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
case AP_TX_BUFFERED:
/* do not free skb here, it will be freed when the
* buffered frame is sent/timed out */
- ret = 0;
+ ret = NETDEV_TX_OK;
goto tx_exit;
}
@@ -501,7 +504,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
"frame (drop_unencrypted=1)\n", dev->name);
}
iface->stats.tx_dropped++;
- ret = 0;
+ ret = NETDEV_TX_OK;
goto fail;
}
@@ -510,7 +513,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb == NULL) {
printk(KERN_DEBUG "%s: TX - encryption failed\n",
dev->name);
- ret = 0;
+ ret = NETDEV_TX_OK;
goto fail;
}
meta = (struct hostap_skb_tx_data *) skb->cb;
@@ -519,23 +522,23 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
"expected 0x%08x) after hostap_tx_encrypt\n",
dev->name, meta->magic,
HOSTAP_SKB_TX_DATA_MAGIC);
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
goto fail;
}
}
if (local->func->tx == NULL || local->func->tx(skb, dev)) {
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
} else {
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_packets++;
iface->stats.tx_bytes += skb->len;
}
fail:
- if (!ret && skb)
+ if (ret == NETDEV_TX_OK && skb)
dev_kfree_skb(skb);
tx_exit:
if (tx.sta_ptr)
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 633740277352..ad8eab4a639b 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -666,7 +666,8 @@ static int prism2_config(struct pcmcia_device *link)
* irq structure is initialized.
*/
if (link->conf.Attributes & CONF_ENABLE_IRQ) {
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING |
+ IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = prism2_interrupt;
link->irq.Instance = dev;
diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig
index 85cc79995f6f..a8131384c6b9 100644
--- a/drivers/net/wireless/ipw2x00/Kconfig
+++ b/drivers/net/wireless/ipw2x00/Kconfig
@@ -4,7 +4,7 @@
config IPW2100
tristate "Intel PRO/Wireless 2100 Network Connection"
- depends on PCI && WLAN_80211
+ depends on PCI && WLAN_80211 && CFG80211
select WIRELESS_EXT
select FW_LOADER
select LIB80211
@@ -63,7 +63,7 @@ config IPW2100_DEBUG
config IPW2200
tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
- depends on PCI && WLAN_80211
+ depends on PCI && WLAN_80211 && CFG80211
select WIRELESS_EXT
select FW_LOADER
select LIB80211
@@ -150,7 +150,7 @@ config IPW2200_DEBUG
config LIBIPW
tristate
- depends on PCI && WLAN_80211
+ depends on PCI && WLAN_80211 && CFG80211
select WIRELESS_EXT
select CRYPTO
select CRYPTO_ARC4
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 742432388ca3..240cff1e6979 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -19,7 +19,7 @@
file called LICENSE.
Contact Information:
- James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
Portions of this file are based on the sample_* files provided by Wireless
@@ -185,7 +185,7 @@ MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
static int debug = 0;
-static int mode = 0;
+static int network_mode = 0;
static int channel = 0;
static int associate = 0;
static int disable = 0;
@@ -195,7 +195,7 @@ static struct ipw2100_fw ipw2100_firmware;
#include <linux/moduleparam.h>
module_param(debug, int, 0444);
-module_param(mode, int, 0444);
+module_param_named(mode, network_mode, int, 0444);
module_param(channel, int, 0444);
module_param(associate, int, 0444);
module_param(disable, int, 0444);
@@ -1673,7 +1673,7 @@ static int ipw2100_start_scan(struct ipw2100_priv *priv)
return err;
}
-static const struct ieee80211_geo ipw_geos[] = {
+static const struct libipw_geo ipw_geos[] = {
{ /* Restricted */
"---",
.bg_channels = 14,
@@ -1694,7 +1694,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
/* Age scan list entries found before suspend */
if (priv->suspend_time) {
- ieee80211_networks_age(priv->ieee, priv->suspend_time);
+ libipw_networks_age(priv->ieee, priv->suspend_time);
priv->suspend_time = 0;
}
@@ -1752,11 +1752,11 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
}
/* Initialize the geo */
- if (ieee80211_set_geo(priv->ieee, &ipw_geos[0])) {
+ if (libipw_set_geo(priv->ieee, &ipw_geos[0])) {
printk(KERN_WARNING DRV_NAME "Could not set geo\n");
return 0;
}
- priv->ieee->freq_band = IEEE80211_24GHZ_BAND;
+ priv->ieee->freq_band = LIBIPW_24GHZ_BAND;
lock = LOCK_NONE;
if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) {
@@ -1817,7 +1817,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
/* Called by register_netdev() */
static int ipw2100_net_init(struct net_device *dev)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
return ipw2100_up(priv, 1);
}
@@ -2340,8 +2340,8 @@ static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
*
* When packet is provided by the firmware, it contains the following:
*
- * . ieee80211_hdr
- * . ieee80211_snap_hdr
+ * . libipw_hdr
+ * . libipw_snap_hdr
*
* The size of the constructed ethernet
*
@@ -2396,7 +2396,7 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
}
static void isr_rx(struct ipw2100_priv *priv, int i,
- struct ieee80211_rx_stats *stats)
+ struct libipw_rx_stats *stats)
{
struct net_device *dev = priv->net_dev;
struct ipw2100_status *status = &priv->status_queue.drv[i];
@@ -2435,13 +2435,13 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
#ifdef IPW2100_RX_DEBUG
/* Make a copy of the frame so we can dump it to the logs if
- * ieee80211_rx fails */
+ * libipw_rx fails */
skb_copy_from_linear_data(packet->skb, packet_data,
min_t(u32, status->frame_size,
IPW_RX_NIC_BUFFER_LENGTH));
#endif
- if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
+ if (!libipw_rx(priv->ieee, packet->skb, stats)) {
#ifdef IPW2100_RX_DEBUG
IPW_DEBUG_DROP("%s: Non consumed packet:\n",
dev->name);
@@ -2449,7 +2449,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
#endif
dev->stats.rx_errors++;
- /* ieee80211_rx failed, so it didn't free the SKB */
+ /* libipw_rx failed, so it didn't free the SKB */
dev_kfree_skb_any(packet->skb);
packet->skb = NULL;
}
@@ -2470,7 +2470,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
#ifdef CONFIG_IPW2100_MONITOR
static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
- struct ieee80211_rx_stats *stats)
+ struct libipw_rx_stats *stats)
{
struct net_device *dev = priv->net_dev;
struct ipw2100_status *status = &priv->status_queue.drv[i];
@@ -2528,10 +2528,10 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr));
- if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
+ if (!libipw_rx(priv->ieee, packet->skb, stats)) {
dev->stats.rx_errors++;
- /* ieee80211_rx failed, so it didn't free the SKB */
+ /* libipw_rx failed, so it didn't free the SKB */
dev_kfree_skb_any(packet->skb);
packet->skb = NULL;
}
@@ -2615,7 +2615,7 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv)
u16 frame_type;
u32 r, w, i, s;
struct ipw2100_rx *u;
- struct ieee80211_rx_stats stats = {
+ struct libipw_rx_stats stats = {
.mac_time = jiffies,
};
@@ -2661,8 +2661,8 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv)
stats.mask = 0;
if (stats.rssi != 0)
- stats.mask |= IEEE80211_STATMASK_RSSI;
- stats.freq = IEEE80211_24GHZ_BAND;
+ stats.mask |= LIBIPW_STATMASK_RSSI;
+ stats.freq = LIBIPW_24GHZ_BAND;
IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n",
priv->net_dev->name, frame_types[frame_type],
@@ -2686,11 +2686,11 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv)
break;
}
#endif
- if (stats.len < sizeof(struct ieee80211_hdr_3addr))
+ if (stats.len < sizeof(struct libipw_hdr_3addr))
break;
switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
case IEEE80211_FTYPE_MGMT:
- ieee80211_rx_mgt(priv->ieee,
+ libipw_rx_mgt(priv->ieee,
&u->rx_data.header, &stats);
break;
@@ -2844,7 +2844,7 @@ static int __ipw2100_tx_process(struct ipw2100_priv *priv)
#ifdef CONFIG_IPW2100_DEBUG
{
- int i = txq->oldest;
+ i = txq->oldest;
IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
&txq->drv[i],
(u32) (txq->nic + i * sizeof(struct ipw2100_bd)),
@@ -2884,7 +2884,7 @@ static int __ipw2100_tx_process(struct ipw2100_priv *priv)
tbd->buf_length, PCI_DMA_TODEVICE);
}
- ieee80211_txb_free(packet->info.d_struct.txb);
+ libipw_txb_free(packet->info.d_struct.txb);
packet->info.d_struct.txb = NULL;
list_add_tail(element, &priv->tx_free_list);
@@ -3028,7 +3028,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
int next = txq->next;
int i = 0;
struct ipw2100_data_header *ipw_hdr;
- struct ieee80211_hdr_3addr *hdr;
+ struct libipw_hdr_3addr *hdr;
while (!list_empty(&priv->tx_pend_list)) {
/* if there isn't enough space in TBD queue, then
@@ -3062,7 +3062,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
packet->index = txq->next;
ipw_hdr = packet->info.d_struct.data;
- hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb->
+ hdr = (struct libipw_hdr_3addr *)packet->info.d_struct.txb->
fragments[0]->data;
if (priv->ieee->iw_mode == IW_MODE_INFRA) {
@@ -3086,7 +3086,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
if (packet->info.d_struct.txb->nr_frags > 1)
ipw_hdr->fragment_size =
packet->info.d_struct.txb->frag_size -
- IEEE80211_3ADDR_LEN;
+ LIBIPW_3ADDR_LEN;
else
ipw_hdr->fragment_size = 0;
@@ -3119,13 +3119,13 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
tbd->buf_length = packet->info.d_struct.txb->
- fragments[i]->len - IEEE80211_3ADDR_LEN;
+ fragments[i]->len - LIBIPW_3ADDR_LEN;
tbd->host_addr = pci_map_single(priv->pci_dev,
packet->info.d_struct.
txb->fragments[i]->
data +
- IEEE80211_3ADDR_LEN,
+ LIBIPW_3ADDR_LEN,
tbd->buf_length,
PCI_DMA_TODEVICE);
@@ -3330,10 +3330,10 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data)
return IRQ_NONE;
}
-static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev,
- int pri)
+static netdev_tx_t ipw2100_tx(struct libipw_txb *txb,
+ struct net_device *dev, int pri)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
struct list_head *element;
struct ipw2100_tx_packet *packet;
unsigned long flags;
@@ -3369,12 +3369,12 @@ static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev,
ipw2100_tx_send_data(priv);
spin_unlock_irqrestore(&priv->low_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
- fail_unlock:
+fail_unlock:
netif_stop_queue(dev);
spin_unlock_irqrestore(&priv->low_lock, flags);
- return 1;
+ return NETDEV_TX_BUSY;
}
static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
@@ -4488,7 +4488,7 @@ static void ipw2100_tx_initialize(struct ipw2100_priv *priv)
/* We simply drop any SKBs that have been queued for
* transmit */
if (priv->tx_buffers[i].info.d_struct.txb) {
- ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.
+ libipw_txb_free(priv->tx_buffers[i].info.d_struct.
txb);
priv->tx_buffers[i].info.d_struct.txb = NULL;
}
@@ -4527,7 +4527,7 @@ static void ipw2100_tx_free(struct ipw2100_priv *priv)
for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
if (priv->tx_buffers[i].info.d_struct.txb) {
- ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.
+ libipw_txb_free(priv->tx_buffers[i].info.d_struct.
txb);
priv->tx_buffers[i].info.d_struct.txb = NULL;
}
@@ -5558,9 +5558,9 @@ static void ipw2100_security_work(struct work_struct *work)
}
static void shim__set_security(struct net_device *dev,
- struct ieee80211_security *sec)
+ struct libipw_security *sec)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int i, force_update = 0;
mutex_lock(&priv->action_mutex);
@@ -5753,7 +5753,7 @@ static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
* method as well) to talk to the firmware */
static int ipw2100_set_address(struct net_device *dev, void *p)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
struct sockaddr *addr = p;
int err = 0;
@@ -5781,7 +5781,7 @@ static int ipw2100_set_address(struct net_device *dev, void *p)
static int ipw2100_open(struct net_device *dev)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
unsigned long flags;
IPW_DEBUG_INFO("dev->open\n");
@@ -5797,7 +5797,7 @@ static int ipw2100_open(struct net_device *dev)
static int ipw2100_close(struct net_device *dev)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
unsigned long flags;
struct list_head *element;
struct ipw2100_tx_packet *packet;
@@ -5818,7 +5818,7 @@ static int ipw2100_close(struct net_device *dev)
list_del(element);
DEC_STAT(&priv->tx_pend_stat);
- ieee80211_txb_free(packet->info.d_struct.txb);
+ libipw_txb_free(packet->info.d_struct.txb);
packet->info.d_struct.txb = NULL;
list_add_tail(element, &priv->tx_free_list);
@@ -5836,7 +5836,7 @@ static int ipw2100_close(struct net_device *dev)
*/
static void ipw2100_tx_timeout(struct net_device *dev)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
dev->stats.tx_errors++;
@@ -5861,8 +5861,8 @@ static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value)
static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value)
{
- struct ieee80211_device *ieee = priv->ieee;
- struct ieee80211_security sec = {
+ struct libipw_device *ieee = priv->ieee;
+ struct libipw_security sec = {
.flags = SEC_AUTH_MODE,
};
int ret = 0;
@@ -5907,7 +5907,7 @@ static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
static void ipw_ethtool_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
char fw_ver[64], ucode_ver[64];
strcpy(info->driver, DRV_NAME);
@@ -5924,7 +5924,7 @@ static void ipw_ethtool_get_drvinfo(struct net_device *dev,
static u32 ipw2100_ethtool_get_link(struct net_device *dev)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
}
@@ -6011,8 +6011,8 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv);
static const struct net_device_ops ipw2100_netdev_ops = {
.ndo_open = ipw2100_open,
.ndo_stop = ipw2100_close,
- .ndo_start_xmit = ieee80211_xmit,
- .ndo_change_mtu = ieee80211_change_mtu,
+ .ndo_start_xmit = libipw_xmit,
+ .ndo_change_mtu = libipw_change_mtu,
.ndo_init = ipw2100_net_init,
.ndo_tx_timeout = ipw2100_tx_timeout,
.ndo_set_mac_address = ipw2100_set_address,
@@ -6029,10 +6029,10 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
struct ipw2100_priv *priv;
struct net_device *dev;
- dev = alloc_ieee80211(sizeof(struct ipw2100_priv));
+ dev = alloc_ieee80211(sizeof(struct ipw2100_priv), 0);
if (!dev)
return NULL;
- priv = ieee80211_priv(dev);
+ priv = libipw_priv(dev);
priv->ieee = netdev_priv(dev);
priv->pci_dev = pci_dev;
priv->net_dev = dev;
@@ -6046,7 +6046,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
dev->netdev_ops = &ipw2100_netdev_ops;
dev->ethtool_ops = &ipw2100_ethtool_ops;
dev->wireless_handlers = &ipw2100_wx_handler_def;
- priv->wireless_data.ieee80211 = priv->ieee;
+ priv->wireless_data.libipw = priv->ieee;
dev->wireless_data = &priv->wireless_data;
dev->watchdog_timeo = 3 * HZ;
dev->irq = 0;
@@ -6076,7 +6076,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
priv->ieee->ieee802_1x = 1;
/* Set module parameters */
- switch (mode) {
+ switch (network_mode) {
case 1:
priv->ieee->iw_mode = IW_MODE_ADHOC;
break;
@@ -6202,7 +6202,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
return err;
}
- priv = ieee80211_priv(dev);
+ priv = libipw_priv(dev);
pci_set_master(pci_dev);
pci_set_drvdata(pci_dev, priv);
@@ -6342,7 +6342,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
sysfs_remove_group(&pci_dev->dev.kobj,
&ipw2100_attribute_group);
- free_ieee80211(dev);
+ free_ieee80211(dev, 0);
pci_set_drvdata(pci_dev, NULL);
}
@@ -6400,7 +6400,7 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
if (dev->base_addr)
iounmap((void __iomem *)dev->base_addr);
- free_ieee80211(dev);
+ free_ieee80211(dev, 0);
}
pci_release_regions(pci_dev);
@@ -6629,7 +6629,7 @@ static int ipw2100_wx_get_name(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
if (!(priv->status & STATUS_ASSOCIATED))
strcpy(wrqu->name, "unassociated");
else
@@ -6643,7 +6643,7 @@ static int ipw2100_wx_set_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
struct iw_freq *fwrq = &wrqu->freq;
int err = 0;
@@ -6693,7 +6693,7 @@ static int ipw2100_wx_get_freq(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->freq.e = 0;
@@ -6714,7 +6714,7 @@ static int ipw2100_wx_set_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0;
IPW_DEBUG_WX("SET Mode -> %d \n", wrqu->mode);
@@ -6757,7 +6757,7 @@ static int ipw2100_wx_get_mode(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->mode = priv->ieee->iw_mode;
IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode);
@@ -6792,7 +6792,7 @@ static int ipw2100_wx_get_range(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
struct iw_range *range = (struct iw_range *)extra;
u16 val;
int i, level;
@@ -6913,7 +6913,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0;
static const unsigned char any[] = {
@@ -6962,7 +6962,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
/* If we are associated, trying to associate, or have a statically
* configured BSSID then return that; otherwise return ANY */
@@ -6980,7 +6980,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
char *essid = ""; /* ANY */
int length = 0;
int err = 0;
@@ -7035,7 +7035,7 @@ static int ipw2100_wx_get_essid(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
DECLARE_SSID_BUF(ssid);
/* If we are associated, trying to associate, or have a statically
@@ -7063,7 +7063,7 @@ static int ipw2100_wx_set_nick(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
if (wrqu->data.length > IW_ESSID_MAX_SIZE)
return -E2BIG;
@@ -7085,7 +7085,7 @@ static int ipw2100_wx_get_nick(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->data.length = strlen(priv->nick);
memcpy(extra, priv->nick, wrqu->data.length);
@@ -7100,7 +7100,7 @@ static int ipw2100_wx_set_rate(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
u32 target_rate = wrqu->bitrate.value;
u32 rate;
int err = 0;
@@ -7140,7 +7140,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int val;
unsigned int len = sizeof(val);
int err = 0;
@@ -7192,7 +7192,7 @@ static int ipw2100_wx_set_rts(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int value, err;
/* Auto RTS not yet supported */
@@ -7231,7 +7231,7 @@ static int ipw2100_wx_get_rts(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
wrqu->rts.fixed = 1; /* no auto select */
@@ -7248,7 +7248,7 @@ static int ipw2100_wx_set_txpow(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0, value;
if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled))
@@ -7293,7 +7293,7 @@ static int ipw2100_wx_get_txpow(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
@@ -7320,7 +7320,7 @@ static int ipw2100_wx_set_frag(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
if (!wrqu->frag.fixed)
return -EINVAL;
@@ -7350,7 +7350,7 @@ static int ipw2100_wx_get_frag(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED;
wrqu->frag.fixed = 0; /* no auto select */
wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
@@ -7364,7 +7364,7 @@ static int ipw2100_wx_set_retry(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0;
if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
@@ -7412,7 +7412,7 @@ static int ipw2100_wx_get_retry(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->retry.disabled = 0; /* can't be disabled */
@@ -7440,7 +7440,7 @@ static int ipw2100_wx_set_scan(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0;
mutex_lock(&priv->action_mutex);
@@ -7472,8 +7472,8 @@ static int ipw2100_wx_get_scan(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
- return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra);
+ struct ipw2100_priv *priv = libipw_priv(dev);
+ return libipw_wx_get_scan(priv->ieee, info, wrqu, extra);
}
/*
@@ -7487,8 +7487,8 @@ static int ipw2100_wx_set_encode(struct net_device *dev,
* No check of STATUS_INITIALIZED required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
- return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
+ struct ipw2100_priv *priv = libipw_priv(dev);
+ return libipw_wx_set_encode(priv->ieee, info, wrqu, key);
}
static int ipw2100_wx_get_encode(struct net_device *dev,
@@ -7499,15 +7499,15 @@ static int ipw2100_wx_get_encode(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
- return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key);
+ struct ipw2100_priv *priv = libipw_priv(dev);
+ return libipw_wx_get_encode(priv->ieee, info, wrqu, key);
}
static int ipw2100_wx_set_power(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0;
mutex_lock(&priv->action_mutex);
@@ -7556,7 +7556,7 @@ static int ipw2100_wx_get_power(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
if (!(priv->power_mode & IPW_POWER_ENABLED))
wrqu->power.disabled = 1;
@@ -7580,8 +7580,8 @@ static int ipw2100_wx_set_genie(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
- struct ieee80211_device *ieee = priv->ieee;
+ struct ipw2100_priv *priv = libipw_priv(dev);
+ struct libipw_device *ieee = priv->ieee;
u8 *buf;
if (!ieee->wpa_enabled)
@@ -7615,8 +7615,8 @@ static int ipw2100_wx_get_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
- struct ieee80211_device *ieee = priv->ieee;
+ struct ipw2100_priv *priv = libipw_priv(dev);
+ struct libipw_device *ieee = priv->ieee;
if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
wrqu->data.length = 0;
@@ -7637,8 +7637,8 @@ static int ipw2100_wx_set_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
- struct ieee80211_device *ieee = priv->ieee;
+ struct ipw2100_priv *priv = libipw_priv(dev);
+ struct libipw_device *ieee = priv->ieee;
struct iw_param *param = &wrqu->param;
struct lib80211_crypt_data *crypt;
unsigned long flags;
@@ -7682,7 +7682,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev,
* can use this to determine if the CAP_PRIVACY_ON bit should
* be set.
*/
- struct ieee80211_security sec = {
+ struct libipw_security sec = {
.flags = SEC_ENABLED,
.enabled = param->value,
};
@@ -7730,8 +7730,8 @@ static int ipw2100_wx_get_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
- struct ieee80211_device *ieee = priv->ieee;
+ struct ipw2100_priv *priv = libipw_priv(dev);
+ struct libipw_device *ieee = priv->ieee;
struct lib80211_crypt_data *crypt;
struct iw_param *param = &wrqu->param;
int ret = 0;
@@ -7792,8 +7792,8 @@ static int ipw2100_wx_set_encodeext(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
- return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra);
+ struct ipw2100_priv *priv = libipw_priv(dev);
+ return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra);
}
/* SIOCGIWENCODEEXT */
@@ -7801,8 +7801,8 @@ static int ipw2100_wx_get_encodeext(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
- return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra);
+ struct ipw2100_priv *priv = libipw_priv(dev);
+ return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra);
}
/* SIOCSIWMLME */
@@ -7810,7 +7810,7 @@ static int ipw2100_wx_set_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
struct iw_mlme *mlme = (struct iw_mlme *)extra;
__le16 reason;
@@ -7841,7 +7841,7 @@ static int ipw2100_wx_set_promisc(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int *parms = (int *)extra;
int enable = (parms[0] > 0);
int err = 0;
@@ -7872,7 +7872,7 @@ static int ipw2100_wx_reset(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
if (priv->status & STATUS_INITIALIZED)
schedule_reset(priv);
return 0;
@@ -7884,7 +7884,7 @@ static int ipw2100_wx_set_powermode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0, mode = *(int *)extra;
mutex_lock(&priv->action_mutex);
@@ -7912,7 +7912,7 @@ static int ipw2100_wx_get_powermode(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int level = IPW_POWER_LEVEL(priv->power_mode);
s32 timeout, period;
@@ -7948,7 +7948,7 @@ static int ipw2100_wx_set_preamble(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int err, mode = *(int *)extra;
mutex_lock(&priv->action_mutex);
@@ -7981,7 +7981,7 @@ static int ipw2100_wx_get_preamble(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
if (priv->config & CFG_LONG_PREAMBLE)
snprintf(wrqu->name, IFNAMSIZ, "long (1)");
@@ -7996,7 +7996,7 @@ static int ipw2100_wx_set_crc_check(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
int err, mode = *(int *)extra;
mutex_lock(&priv->action_mutex);
@@ -8028,7 +8028,7 @@ static int ipw2100_wx_get_crc_check(struct net_device *dev,
* This can be called at any time. No action lock required
*/
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
if (priv->config & CFG_CRC_CHECK)
snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)");
@@ -8179,10 +8179,11 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
int rssi_qual;
int tx_qual;
int beacon_qual;
+ int quality;
- struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ipw2100_priv *priv = libipw_priv(dev);
struct iw_statistics *wstats;
- u32 rssi, quality, tx_retries, missed_beacons, tx_failures;
+ u32 rssi, tx_retries, missed_beacons, tx_failures;
u32 ord_len = sizeof(u32);
if (!priv)
@@ -8265,7 +8266,8 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
beacon_qual = (20 - missed_beacons) *
(PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
- quality = min(beacon_qual, min(tx_qual, rssi_qual));
+ quality = min(tx_qual, rssi_qual);
+ quality = min(beacon_qual, quality);
#ifdef CONFIG_IPW2100_DEBUG
if (beacon_qual == quality)
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h
index f183d951cd32..1eab0d698f4d 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.h
+++ b/drivers/net/wireless/ipw2x00/ipw2100.h
@@ -19,7 +19,7 @@
file called LICENSE.
Contact Information:
- James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
******************************************************************************/
@@ -46,7 +46,7 @@
#include <linux/workqueue.h>
#include <linux/mutex.h>
-#include "ieee80211.h"
+#include "libipw.h"
struct ipw2100_priv;
struct ipw2100_tx_packet;
@@ -343,7 +343,7 @@ struct ipw2100_tx_packet {
struct { /* DATA */
struct ipw2100_data_header *data;
dma_addr_t data_phys;
- struct ieee80211_txb *txb;
+ struct libipw_txb *txb;
} d_struct;
} info;
int jiffy_start;
@@ -492,7 +492,7 @@ struct ipw2100_priv {
int stop_hang_check; /* Set 1 when shutting down to kill hang_check */
int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */
- struct ieee80211_device *ieee;
+ struct libipw_device *ieee;
unsigned long status;
unsigned long config;
unsigned long capability;
@@ -788,7 +788,7 @@ struct ipw2100_priv {
#define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT 100 // 100 milli
#define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT 100 // 100 milli
-#define IPW_HEADER_802_11_SIZE sizeof(struct ieee80211_hdr_3addr)
+#define IPW_HEADER_802_11_SIZE sizeof(struct libipw_hdr_3addr)
#define IPW_MAX_80211_PAYLOAD_SIZE 2304U
#define IPW_MAX_802_11_PAYLOAD_LENGTH 2312
#define IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH 1536
@@ -803,13 +803,13 @@ struct ipw2100_priv {
IPW_802_11_FCS_LENGTH)
#define IPW_802_11_PAYLOAD_OFFSET \
- (sizeof(struct ieee80211_hdr_3addr) + \
- sizeof(struct ieee80211_snap_hdr))
+ (sizeof(struct libipw_hdr_3addr) + \
+ sizeof(struct libipw_snap_hdr))
struct ipw2100_rx {
union {
unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH];
- struct ieee80211_hdr_4addr header;
+ struct libipw_hdr_4addr header;
u32 status;
struct ipw2100_notification notification;
struct ipw2100_cmd_header command;
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index f593fbbb4e52..8d58e6ed4e7d 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -25,7 +25,7 @@
file called LICENSE.
Contact Information:
- James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
******************************************************************************/
@@ -83,13 +83,13 @@ MODULE_LICENSE("GPL");
static int cmdlog = 0;
static int debug = 0;
-static int channel = 0;
-static int mode = 0;
+static int default_channel = 0;
+static int network_mode = 0;
static u32 ipw_debug_level;
static int associate;
static int auto_create = 1;
-static int led = 0;
+static int led_support = 0;
static int disable = 0;
static int bt_coexist = 0;
static int hwcrypto = 0;
@@ -103,6 +103,25 @@ static int antenna = CFG_SYS_ANTENNA_BOTH;
static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */
#endif
+static struct ieee80211_rate ipw2200_rates[] = {
+ { .bitrate = 10 },
+ { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 60 },
+ { .bitrate = 90 },
+ { .bitrate = 120 },
+ { .bitrate = 180 },
+ { .bitrate = 240 },
+ { .bitrate = 360 },
+ { .bitrate = 480 },
+ { .bitrate = 540 }
+};
+
+#define ipw2200_a_rates (ipw2200_rates + 4)
+#define ipw2200_num_a_rates 8
+#define ipw2200_bg_rates (ipw2200_rates + 0)
+#define ipw2200_num_bg_rates 12
#ifdef CONFIG_IPW2200_QOS
static int qos_enable = 0;
@@ -111,7 +130,7 @@ static int qos_no_ack_mask = 0;
static int burst_duration_CCK = 0;
static int burst_duration_OFDM = 0;
-static struct ieee80211_qos_parameters def_qos_parameters_OFDM = {
+static struct libipw_qos_parameters def_qos_parameters_OFDM = {
{QOS_TX0_CW_MIN_OFDM, QOS_TX1_CW_MIN_OFDM, QOS_TX2_CW_MIN_OFDM,
QOS_TX3_CW_MIN_OFDM},
{QOS_TX0_CW_MAX_OFDM, QOS_TX1_CW_MAX_OFDM, QOS_TX2_CW_MAX_OFDM,
@@ -122,7 +141,7 @@ static struct ieee80211_qos_parameters def_qos_parameters_OFDM = {
QOS_TX2_TXOP_LIMIT_OFDM, QOS_TX3_TXOP_LIMIT_OFDM}
};
-static struct ieee80211_qos_parameters def_qos_parameters_CCK = {
+static struct libipw_qos_parameters def_qos_parameters_CCK = {
{QOS_TX0_CW_MIN_CCK, QOS_TX1_CW_MIN_CCK, QOS_TX2_CW_MIN_CCK,
QOS_TX3_CW_MIN_CCK},
{QOS_TX0_CW_MAX_CCK, QOS_TX1_CW_MAX_CCK, QOS_TX2_CW_MAX_CCK,
@@ -133,7 +152,7 @@ static struct ieee80211_qos_parameters def_qos_parameters_CCK = {
QOS_TX3_TXOP_LIMIT_CCK}
};
-static struct ieee80211_qos_parameters def_parameters_OFDM = {
+static struct libipw_qos_parameters def_parameters_OFDM = {
{DEF_TX0_CW_MIN_OFDM, DEF_TX1_CW_MIN_OFDM, DEF_TX2_CW_MIN_OFDM,
DEF_TX3_CW_MIN_OFDM},
{DEF_TX0_CW_MAX_OFDM, DEF_TX1_CW_MAX_OFDM, DEF_TX2_CW_MAX_OFDM,
@@ -144,7 +163,7 @@ static struct ieee80211_qos_parameters def_parameters_OFDM = {
DEF_TX2_TXOP_LIMIT_OFDM, DEF_TX3_TXOP_LIMIT_OFDM}
};
-static struct ieee80211_qos_parameters def_parameters_CCK = {
+static struct libipw_qos_parameters def_parameters_CCK = {
{DEF_TX0_CW_MIN_CCK, DEF_TX1_CW_MIN_CCK, DEF_TX2_CW_MIN_CCK,
DEF_TX3_CW_MIN_CCK},
{DEF_TX0_CW_MAX_CCK, DEF_TX1_CW_MAX_CCK, DEF_TX2_CW_MAX_CCK,
@@ -164,9 +183,9 @@ static int from_priority_to_tx_queue[] = {
static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv);
-static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters
+static int ipw_send_qos_params_command(struct ipw_priv *priv, struct libipw_qos_parameters
*qos_param);
-static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element
+static int ipw_send_qos_info_command(struct ipw_priv *priv, struct libipw_qos_information_element
*qos_param);
#endif /* CONFIG_IPW2200_QOS */
@@ -1830,7 +1849,7 @@ static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr,
break;
}
- if (ieee80211_is_valid_channel(priv->ieee, channel))
+ if (libipw_is_valid_channel(priv->ieee, channel))
priv->speed_scan[pos++] = channel;
else
IPW_WARNING("Skipping invalid channel request: %d\n",
@@ -1882,7 +1901,7 @@ static ssize_t show_channels(struct device *d,
char *buf)
{
struct ipw_priv *priv = dev_get_drvdata(d);
- const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
+ const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
int len = 0, i;
len = sprintf(&buf[len],
@@ -1892,14 +1911,14 @@ static ssize_t show_channels(struct device *d,
for (i = 0; i < geo->bg_channels; i++) {
len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n",
geo->bg[i].channel,
- geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT ?
+ geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT ?
" (radar spectrum)" : "",
- ((geo->bg[i].flags & IEEE80211_CH_NO_IBSS) ||
- (geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT))
+ ((geo->bg[i].flags & LIBIPW_CH_NO_IBSS) ||
+ (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT))
? "" : ", IBSS",
- geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY ?
+ geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY ?
"passive only" : "active/passive",
- geo->bg[i].flags & IEEE80211_CH_B_ONLY ?
+ geo->bg[i].flags & LIBIPW_CH_B_ONLY ?
"B" : "B/G");
}
@@ -1909,12 +1928,12 @@ static ssize_t show_channels(struct device *d,
for (i = 0; i < geo->a_channels; i++) {
len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n",
geo->a[i].channel,
- geo->a[i].flags & IEEE80211_CH_RADAR_DETECT ?
+ geo->a[i].flags & LIBIPW_CH_RADAR_DETECT ?
" (radar spectrum)" : "",
- ((geo->a[i].flags & IEEE80211_CH_NO_IBSS) ||
- (geo->a[i].flags & IEEE80211_CH_RADAR_DETECT))
+ ((geo->a[i].flags & LIBIPW_CH_NO_IBSS) ||
+ (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT))
? "" : ", IBSS",
- geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY ?
+ geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY ?
"passive only" : "active/passive");
}
@@ -2429,7 +2448,7 @@ static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power)
static int ipw_set_tx_power(struct ipw_priv *priv)
{
- const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
+ const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
struct ipw_tx_power tx_power;
s8 max_power;
int i;
@@ -2942,12 +2961,12 @@ static int ipw_fw_dma_wait(struct ipw_priv *priv)
static void ipw_remove_current_network(struct ipw_priv *priv)
{
struct list_head *element, *safe;
- struct ieee80211_network *network = NULL;
+ struct libipw_network *network = NULL;
unsigned long flags;
spin_lock_irqsave(&priv->ieee->lock, flags);
list_for_each_safe(element, safe, &priv->ieee->network_list) {
- network = list_entry(element, struct ieee80211_network, list);
+ network = list_entry(element, struct libipw_network, list);
if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
list_del(element);
list_add_tail(&network->list,
@@ -3765,7 +3784,7 @@ static void ipw_queue_tx_free_tfd(struct ipw_priv *priv,
le16_to_cpu(bd->u.data.chunk_len[i]),
PCI_DMA_TODEVICE);
if (txq->txb[txq->q.last_used]) {
- ieee80211_txb_free(txq->txb[txq->q.last_used]);
+ libipw_txb_free(txq->txb[txq->q.last_used]);
txq->txb[txq->q.last_used] = NULL;
}
}
@@ -4084,7 +4103,7 @@ static u32 ipw_get_max_rate(struct ipw_priv *priv)
/* If currently associated in B mode, restrict the maximum
* rate match to B rates */
if (priv->assoc_request.ieee_mode == IPW_B_MODE)
- mask &= IEEE80211_CCK_RATES_MASK;
+ mask &= LIBIPW_CCK_RATES_MASK;
/* TODO: Verify that the rate is supported by the current rates
* list. */
@@ -4092,29 +4111,29 @@ static u32 ipw_get_max_rate(struct ipw_priv *priv)
while (i && !(mask & i))
i >>= 1;
switch (i) {
- case IEEE80211_CCK_RATE_1MB_MASK:
+ case LIBIPW_CCK_RATE_1MB_MASK:
return 1000000;
- case IEEE80211_CCK_RATE_2MB_MASK:
+ case LIBIPW_CCK_RATE_2MB_MASK:
return 2000000;
- case IEEE80211_CCK_RATE_5MB_MASK:
+ case LIBIPW_CCK_RATE_5MB_MASK:
return 5500000;
- case IEEE80211_OFDM_RATE_6MB_MASK:
+ case LIBIPW_OFDM_RATE_6MB_MASK:
return 6000000;
- case IEEE80211_OFDM_RATE_9MB_MASK:
+ case LIBIPW_OFDM_RATE_9MB_MASK:
return 9000000;
- case IEEE80211_CCK_RATE_11MB_MASK:
+ case LIBIPW_CCK_RATE_11MB_MASK:
return 11000000;
- case IEEE80211_OFDM_RATE_12MB_MASK:
+ case LIBIPW_OFDM_RATE_12MB_MASK:
return 12000000;
- case IEEE80211_OFDM_RATE_18MB_MASK:
+ case LIBIPW_OFDM_RATE_18MB_MASK:
return 18000000;
- case IEEE80211_OFDM_RATE_24MB_MASK:
+ case LIBIPW_OFDM_RATE_24MB_MASK:
return 24000000;
- case IEEE80211_OFDM_RATE_36MB_MASK:
+ case LIBIPW_OFDM_RATE_36MB_MASK:
return 36000000;
- case IEEE80211_OFDM_RATE_48MB_MASK:
+ case LIBIPW_OFDM_RATE_48MB_MASK:
return 48000000;
- case IEEE80211_OFDM_RATE_54MB_MASK:
+ case LIBIPW_OFDM_RATE_54MB_MASK:
return 54000000;
}
@@ -4279,9 +4298,10 @@ static void ipw_gather_stats(struct ipw_priv *priv)
IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n",
signal_quality, rssi);
- quality = min(beacon_quality,
- min(rate_quality,
- min(tx_quality, min(rx_quality, signal_quality))));
+ quality = min(rx_quality, signal_quality);
+ quality = min(tx_quality, quality);
+ quality = min(rate_quality, quality);
+ quality = min(beacon_quality, quality);
if (quality == beacon_quality)
IPW_DEBUG_STATS("Quality (%d%%): Clamped to missed beacons.\n",
quality);
@@ -4425,7 +4445,6 @@ static void ipw_rx_notification(struct ipw_priv *priv,
{
DECLARE_SSID_BUF(ssid);
u16 size = le16_to_cpu(notif->size);
- notif->size = le16_to_cpu(notif->size);
IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size);
@@ -4480,11 +4499,11 @@ static void ipw_rx_notification(struct ipw_priv *priv,
== IEEE80211_STYPE_ASSOC_RESP)) {
if ((sizeof
(struct
- ieee80211_assoc_response)
+ libipw_assoc_response)
<= size)
&& (size <= 2314)) {
struct
- ieee80211_rx_stats
+ libipw_rx_stats
stats = {
.len = size - 1,
};
@@ -4492,10 +4511,10 @@ static void ipw_rx_notification(struct ipw_priv *priv,
IPW_DEBUG_QOS
("QoS Associate "
"size %d\n", size);
- ieee80211_rx_mgt(priv->
+ libipw_rx_mgt(priv->
ieee,
(struct
- ieee80211_hdr_4addr
+ libipw_hdr_4addr
*)
&notif->u.raw, &stats);
}
@@ -4551,11 +4570,11 @@ static void ipw_rx_notification(struct ipw_priv *priv,
case CMAS_INIT:{
if (priv->status & STATUS_AUTH) {
struct
- ieee80211_assoc_response
+ libipw_assoc_response
*resp;
resp =
(struct
- ieee80211_assoc_response
+ libipw_assoc_response
*)&notif->u.raw;
IPW_DEBUG(IPW_DL_NOTIF |
IPW_DL_STATE |
@@ -5241,33 +5260,33 @@ static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv)
static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate)
{
- rate &= ~IEEE80211_BASIC_RATE_MASK;
+ rate &= ~LIBIPW_BASIC_RATE_MASK;
if (ieee_mode == IEEE_A) {
switch (rate) {
- case IEEE80211_OFDM_RATE_6MB:
- return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ?
+ case LIBIPW_OFDM_RATE_6MB:
+ return priv->rates_mask & LIBIPW_OFDM_RATE_6MB_MASK ?
1 : 0;
- case IEEE80211_OFDM_RATE_9MB:
- return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ?
+ case LIBIPW_OFDM_RATE_9MB:
+ return priv->rates_mask & LIBIPW_OFDM_RATE_9MB_MASK ?
1 : 0;
- case IEEE80211_OFDM_RATE_12MB:
+ case LIBIPW_OFDM_RATE_12MB:
return priv->
- rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0;
- case IEEE80211_OFDM_RATE_18MB:
+ rates_mask & LIBIPW_OFDM_RATE_12MB_MASK ? 1 : 0;
+ case LIBIPW_OFDM_RATE_18MB:
return priv->
- rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0;
- case IEEE80211_OFDM_RATE_24MB:
+ rates_mask & LIBIPW_OFDM_RATE_18MB_MASK ? 1 : 0;
+ case LIBIPW_OFDM_RATE_24MB:
return priv->
- rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0;
- case IEEE80211_OFDM_RATE_36MB:
+ rates_mask & LIBIPW_OFDM_RATE_24MB_MASK ? 1 : 0;
+ case LIBIPW_OFDM_RATE_36MB:
return priv->
- rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0;
- case IEEE80211_OFDM_RATE_48MB:
+ rates_mask & LIBIPW_OFDM_RATE_36MB_MASK ? 1 : 0;
+ case LIBIPW_OFDM_RATE_48MB:
return priv->
- rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0;
- case IEEE80211_OFDM_RATE_54MB:
+ rates_mask & LIBIPW_OFDM_RATE_48MB_MASK ? 1 : 0;
+ case LIBIPW_OFDM_RATE_54MB:
return priv->
- rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0;
+ rates_mask & LIBIPW_OFDM_RATE_54MB_MASK ? 1 : 0;
default:
return 0;
}
@@ -5275,14 +5294,14 @@ static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate)
/* B and G mixed */
switch (rate) {
- case IEEE80211_CCK_RATE_1MB:
- return priv->rates_mask & IEEE80211_CCK_RATE_1MB_MASK ? 1 : 0;
- case IEEE80211_CCK_RATE_2MB:
- return priv->rates_mask & IEEE80211_CCK_RATE_2MB_MASK ? 1 : 0;
- case IEEE80211_CCK_RATE_5MB:
- return priv->rates_mask & IEEE80211_CCK_RATE_5MB_MASK ? 1 : 0;
- case IEEE80211_CCK_RATE_11MB:
- return priv->rates_mask & IEEE80211_CCK_RATE_11MB_MASK ? 1 : 0;
+ case LIBIPW_CCK_RATE_1MB:
+ return priv->rates_mask & LIBIPW_CCK_RATE_1MB_MASK ? 1 : 0;
+ case LIBIPW_CCK_RATE_2MB:
+ return priv->rates_mask & LIBIPW_CCK_RATE_2MB_MASK ? 1 : 0;
+ case LIBIPW_CCK_RATE_5MB:
+ return priv->rates_mask & LIBIPW_CCK_RATE_5MB_MASK ? 1 : 0;
+ case LIBIPW_CCK_RATE_11MB:
+ return priv->rates_mask & LIBIPW_CCK_RATE_11MB_MASK ? 1 : 0;
}
/* If we are limited to B modulations, bail at this point */
@@ -5291,29 +5310,29 @@ static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate)
/* G */
switch (rate) {
- case IEEE80211_OFDM_RATE_6MB:
- return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ? 1 : 0;
- case IEEE80211_OFDM_RATE_9MB:
- return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ? 1 : 0;
- case IEEE80211_OFDM_RATE_12MB:
- return priv->rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0;
- case IEEE80211_OFDM_RATE_18MB:
- return priv->rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0;
- case IEEE80211_OFDM_RATE_24MB:
- return priv->rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0;
- case IEEE80211_OFDM_RATE_36MB:
- return priv->rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0;
- case IEEE80211_OFDM_RATE_48MB:
- return priv->rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0;
- case IEEE80211_OFDM_RATE_54MB:
- return priv->rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0;
+ case LIBIPW_OFDM_RATE_6MB:
+ return priv->rates_mask & LIBIPW_OFDM_RATE_6MB_MASK ? 1 : 0;
+ case LIBIPW_OFDM_RATE_9MB:
+ return priv->rates_mask & LIBIPW_OFDM_RATE_9MB_MASK ? 1 : 0;
+ case LIBIPW_OFDM_RATE_12MB:
+ return priv->rates_mask & LIBIPW_OFDM_RATE_12MB_MASK ? 1 : 0;
+ case LIBIPW_OFDM_RATE_18MB:
+ return priv->rates_mask & LIBIPW_OFDM_RATE_18MB_MASK ? 1 : 0;
+ case LIBIPW_OFDM_RATE_24MB:
+ return priv->rates_mask & LIBIPW_OFDM_RATE_24MB_MASK ? 1 : 0;
+ case LIBIPW_OFDM_RATE_36MB:
+ return priv->rates_mask & LIBIPW_OFDM_RATE_36MB_MASK ? 1 : 0;
+ case LIBIPW_OFDM_RATE_48MB:
+ return priv->rates_mask & LIBIPW_OFDM_RATE_48MB_MASK ? 1 : 0;
+ case LIBIPW_OFDM_RATE_54MB:
+ return priv->rates_mask & LIBIPW_OFDM_RATE_54MB_MASK ? 1 : 0;
}
return 0;
}
static int ipw_compatible_rates(struct ipw_priv *priv,
- const struct ieee80211_network *network,
+ const struct libipw_network *network,
struct ipw_supported_rates *rates)
{
int num_rates, i;
@@ -5325,7 +5344,7 @@ static int ipw_compatible_rates(struct ipw_priv *priv,
if (!ipw_is_rate_in_mask(priv, network->mode,
network->rates[i])) {
- if (network->rates[i] & IEEE80211_BASIC_RATE_MASK) {
+ if (network->rates[i] & LIBIPW_BASIC_RATE_MASK) {
IPW_DEBUG_SCAN("Adding masked mandatory "
"rate %02X\n",
network->rates[i]);
@@ -5347,7 +5366,7 @@ static int ipw_compatible_rates(struct ipw_priv *priv,
for (i = 0; i < num_rates; i++) {
if (!ipw_is_rate_in_mask(priv, network->mode,
network->rates_ex[i])) {
- if (network->rates_ex[i] & IEEE80211_BASIC_RATE_MASK) {
+ if (network->rates_ex[i] & LIBIPW_BASIC_RATE_MASK) {
IPW_DEBUG_SCAN("Adding masked mandatory "
"rate %02X\n",
network->rates_ex[i]);
@@ -5383,73 +5402,73 @@ static void ipw_copy_rates(struct ipw_supported_rates *dest,
static void ipw_add_cck_scan_rates(struct ipw_supported_rates *rates,
u8 modulation, u32 rate_mask)
{
- u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ?
- IEEE80211_BASIC_RATE_MASK : 0;
+ u8 basic_mask = (LIBIPW_OFDM_MODULATION == modulation) ?
+ LIBIPW_BASIC_RATE_MASK : 0;
- if (rate_mask & IEEE80211_CCK_RATE_1MB_MASK)
+ if (rate_mask & LIBIPW_CCK_RATE_1MB_MASK)
rates->supported_rates[rates->num_rates++] =
- IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
+ LIBIPW_BASIC_RATE_MASK | LIBIPW_CCK_RATE_1MB;
- if (rate_mask & IEEE80211_CCK_RATE_2MB_MASK)
+ if (rate_mask & LIBIPW_CCK_RATE_2MB_MASK)
rates->supported_rates[rates->num_rates++] =
- IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
+ LIBIPW_BASIC_RATE_MASK | LIBIPW_CCK_RATE_2MB;
- if (rate_mask & IEEE80211_CCK_RATE_5MB_MASK)
+ if (rate_mask & LIBIPW_CCK_RATE_5MB_MASK)
rates->supported_rates[rates->num_rates++] = basic_mask |
- IEEE80211_CCK_RATE_5MB;
+ LIBIPW_CCK_RATE_5MB;
- if (rate_mask & IEEE80211_CCK_RATE_11MB_MASK)
+ if (rate_mask & LIBIPW_CCK_RATE_11MB_MASK)
rates->supported_rates[rates->num_rates++] = basic_mask |
- IEEE80211_CCK_RATE_11MB;
+ LIBIPW_CCK_RATE_11MB;
}
static void ipw_add_ofdm_scan_rates(struct ipw_supported_rates *rates,
u8 modulation, u32 rate_mask)
{
- u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ?
- IEEE80211_BASIC_RATE_MASK : 0;
+ u8 basic_mask = (LIBIPW_OFDM_MODULATION == modulation) ?
+ LIBIPW_BASIC_RATE_MASK : 0;
- if (rate_mask & IEEE80211_OFDM_RATE_6MB_MASK)
+ if (rate_mask & LIBIPW_OFDM_RATE_6MB_MASK)
rates->supported_rates[rates->num_rates++] = basic_mask |
- IEEE80211_OFDM_RATE_6MB;
+ LIBIPW_OFDM_RATE_6MB;
- if (rate_mask & IEEE80211_OFDM_RATE_9MB_MASK)
+ if (rate_mask & LIBIPW_OFDM_RATE_9MB_MASK)
rates->supported_rates[rates->num_rates++] =
- IEEE80211_OFDM_RATE_9MB;
+ LIBIPW_OFDM_RATE_9MB;
- if (rate_mask & IEEE80211_OFDM_RATE_12MB_MASK)
+ if (rate_mask & LIBIPW_OFDM_RATE_12MB_MASK)
rates->supported_rates[rates->num_rates++] = basic_mask |
- IEEE80211_OFDM_RATE_12MB;
+ LIBIPW_OFDM_RATE_12MB;
- if (rate_mask & IEEE80211_OFDM_RATE_18MB_MASK)
+ if (rate_mask & LIBIPW_OFDM_RATE_18MB_MASK)
rates->supported_rates[rates->num_rates++] =
- IEEE80211_OFDM_RATE_18MB;
+ LIBIPW_OFDM_RATE_18MB;
- if (rate_mask & IEEE80211_OFDM_RATE_24MB_MASK)
+ if (rate_mask & LIBIPW_OFDM_RATE_24MB_MASK)
rates->supported_rates[rates->num_rates++] = basic_mask |
- IEEE80211_OFDM_RATE_24MB;
+ LIBIPW_OFDM_RATE_24MB;
- if (rate_mask & IEEE80211_OFDM_RATE_36MB_MASK)
+ if (rate_mask & LIBIPW_OFDM_RATE_36MB_MASK)
rates->supported_rates[rates->num_rates++] =
- IEEE80211_OFDM_RATE_36MB;
+ LIBIPW_OFDM_RATE_36MB;
- if (rate_mask & IEEE80211_OFDM_RATE_48MB_MASK)
+ if (rate_mask & LIBIPW_OFDM_RATE_48MB_MASK)
rates->supported_rates[rates->num_rates++] =
- IEEE80211_OFDM_RATE_48MB;
+ LIBIPW_OFDM_RATE_48MB;
- if (rate_mask & IEEE80211_OFDM_RATE_54MB_MASK)
+ if (rate_mask & LIBIPW_OFDM_RATE_54MB_MASK)
rates->supported_rates[rates->num_rates++] =
- IEEE80211_OFDM_RATE_54MB;
+ LIBIPW_OFDM_RATE_54MB;
}
struct ipw_network_match {
- struct ieee80211_network *network;
+ struct libipw_network *network;
struct ipw_supported_rates rates;
};
static int ipw_find_adhoc_network(struct ipw_priv *priv,
struct ipw_network_match *match,
- struct ieee80211_network *network,
+ struct libipw_network *network,
int roaming)
{
struct ipw_supported_rates rates;
@@ -5570,7 +5589,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
}
/* Filter out any incompatible freq / mode combinations */
- if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
+ if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
"because of invalid frequency/mode "
"combination.\n",
@@ -5620,7 +5639,7 @@ static void ipw_merge_adhoc_network(struct work_struct *work)
DECLARE_SSID_BUF(ssid);
struct ipw_priv *priv =
container_of(work, struct ipw_priv, merge_networks);
- struct ieee80211_network *network = NULL;
+ struct libipw_network *network = NULL;
struct ipw_network_match match = {
.network = priv->assoc_network
};
@@ -5662,7 +5681,7 @@ static void ipw_merge_adhoc_network(struct work_struct *work)
static int ipw_best_network(struct ipw_priv *priv,
struct ipw_network_match *match,
- struct ieee80211_network *network, int roaming)
+ struct libipw_network *network, int roaming)
{
struct ipw_supported_rates rates;
DECLARE_SSID_BUF(ssid);
@@ -5796,7 +5815,7 @@ static int ipw_best_network(struct ipw_priv *priv,
}
/* Filter out any incompatible freq / mode combinations */
- if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
+ if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
"because of invalid frequency/mode "
"combination.\n",
@@ -5807,7 +5826,7 @@ static int ipw_best_network(struct ipw_priv *priv,
}
/* Filter out invalid channel in current GEO */
- if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) {
+ if (!libipw_is_valid_channel(priv->ieee, network->channel)) {
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
"because of invalid channel in current GEO\n",
print_ssid(ssid, network->ssid,
@@ -5853,9 +5872,9 @@ static int ipw_best_network(struct ipw_priv *priv,
}
static void ipw_adhoc_create(struct ipw_priv *priv,
- struct ieee80211_network *network)
+ struct libipw_network *network)
{
- const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
+ const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
int i;
/*
@@ -5870,25 +5889,25 @@ static void ipw_adhoc_create(struct ipw_priv *priv,
* FW fatal error.
*
*/
- switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) {
- case IEEE80211_52GHZ_BAND:
+ switch (libipw_is_valid_channel(priv->ieee, priv->channel)) {
+ case LIBIPW_52GHZ_BAND:
network->mode = IEEE_A;
- i = ieee80211_channel_to_index(priv->ieee, priv->channel);
+ i = libipw_channel_to_index(priv->ieee, priv->channel);
BUG_ON(i == -1);
- if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) {
+ if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY) {
IPW_WARNING("Overriding invalid channel\n");
priv->channel = geo->a[0].channel;
}
break;
- case IEEE80211_24GHZ_BAND:
+ case LIBIPW_24GHZ_BAND:
if (priv->ieee->mode & IEEE_G)
network->mode = IEEE_G;
else
network->mode = IEEE_B;
- i = ieee80211_channel_to_index(priv->ieee, priv->channel);
+ i = libipw_channel_to_index(priv->ieee, priv->channel);
BUG_ON(i == -1);
- if (geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY) {
+ if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) {
IPW_WARNING("Overriding invalid channel\n");
priv->channel = geo->bg[0].channel;
}
@@ -6115,70 +6134,71 @@ static void ipw_debug_config(struct ipw_priv *priv)
static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
{
/* TODO: Verify that this works... */
- struct ipw_fixed_rate fr = {
- .tx_rates = priv->rates_mask
- };
+ struct ipw_fixed_rate fr;
u32 reg;
u16 mask = 0;
+ u16 new_tx_rates = priv->rates_mask;
/* Identify 'current FW band' and match it with the fixed
* Tx rates */
switch (priv->ieee->freq_band) {
- case IEEE80211_52GHZ_BAND: /* A only */
+ case LIBIPW_52GHZ_BAND: /* A only */
/* IEEE_A */
- if (priv->rates_mask & ~IEEE80211_OFDM_RATES_MASK) {
+ if (priv->rates_mask & ~LIBIPW_OFDM_RATES_MASK) {
/* Invalid fixed rate mask */
IPW_DEBUG_WX
("invalid fixed rate mask in ipw_set_fixed_rate\n");
- fr.tx_rates = 0;
+ new_tx_rates = 0;
break;
}
- fr.tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A;
+ new_tx_rates >>= LIBIPW_OFDM_SHIFT_MASK_A;
break;
default: /* 2.4Ghz or Mixed */
/* IEEE_B */
if (mode == IEEE_B) {
- if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) {
+ if (new_tx_rates & ~LIBIPW_CCK_RATES_MASK) {
/* Invalid fixed rate mask */
IPW_DEBUG_WX
("invalid fixed rate mask in ipw_set_fixed_rate\n");
- fr.tx_rates = 0;
+ new_tx_rates = 0;
}
break;
}
/* IEEE_G */
- if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK |
- IEEE80211_OFDM_RATES_MASK)) {
+ if (new_tx_rates & ~(LIBIPW_CCK_RATES_MASK |
+ LIBIPW_OFDM_RATES_MASK)) {
/* Invalid fixed rate mask */
IPW_DEBUG_WX
("invalid fixed rate mask in ipw_set_fixed_rate\n");
- fr.tx_rates = 0;
+ new_tx_rates = 0;
break;
}
- if (IEEE80211_OFDM_RATE_6MB_MASK & fr.tx_rates) {
- mask |= (IEEE80211_OFDM_RATE_6MB_MASK >> 1);
- fr.tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK;
+ if (LIBIPW_OFDM_RATE_6MB_MASK & new_tx_rates) {
+ mask |= (LIBIPW_OFDM_RATE_6MB_MASK >> 1);
+ new_tx_rates &= ~LIBIPW_OFDM_RATE_6MB_MASK;
}
- if (IEEE80211_OFDM_RATE_9MB_MASK & fr.tx_rates) {
- mask |= (IEEE80211_OFDM_RATE_9MB_MASK >> 1);
- fr.tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK;
+ if (LIBIPW_OFDM_RATE_9MB_MASK & new_tx_rates) {
+ mask |= (LIBIPW_OFDM_RATE_9MB_MASK >> 1);
+ new_tx_rates &= ~LIBIPW_OFDM_RATE_9MB_MASK;
}
- if (IEEE80211_OFDM_RATE_12MB_MASK & fr.tx_rates) {
- mask |= (IEEE80211_OFDM_RATE_12MB_MASK >> 1);
- fr.tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK;
+ if (LIBIPW_OFDM_RATE_12MB_MASK & new_tx_rates) {
+ mask |= (LIBIPW_OFDM_RATE_12MB_MASK >> 1);
+ new_tx_rates &= ~LIBIPW_OFDM_RATE_12MB_MASK;
}
- fr.tx_rates |= mask;
+ new_tx_rates |= mask;
break;
}
+ fr.tx_rates = cpu_to_le16(new_tx_rates);
+
reg = ipw_read32(priv, IPW_MEM_FIXED_OVERRIDE);
ipw_write_reg32(priv, reg, *(u32 *) & fr);
}
@@ -6203,12 +6223,12 @@ static void ipw_add_scan_channels(struct ipw_priv *priv,
int scan_type)
{
int channel_index = 0;
- const struct ieee80211_geo *geo;
+ const struct libipw_geo *geo;
int i;
- geo = ieee80211_get_geo(priv->ieee);
+ geo = libipw_get_geo(priv->ieee);
- if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) {
+ if (priv->ieee->freq_band & LIBIPW_52GHZ_BAND) {
int start = channel_index;
for (i = 0; i < geo->a_channels; i++) {
if ((priv->status & STATUS_ASSOCIATED) &&
@@ -6218,7 +6238,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv,
scan->channels_list[channel_index] = geo->a[i].channel;
ipw_set_scan_type(scan, channel_index,
geo->a[i].
- flags & IEEE80211_CH_PASSIVE_ONLY ?
+ flags & LIBIPW_CH_PASSIVE_ONLY ?
IPW_SCAN_PASSIVE_FULL_DWELL_SCAN :
scan_type);
}
@@ -6230,11 +6250,11 @@ static void ipw_add_scan_channels(struct ipw_priv *priv,
}
}
- if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) {
+ if (priv->ieee->freq_band & LIBIPW_24GHZ_BAND) {
int start = channel_index;
if (priv->config & CFG_SPEED_SCAN) {
int index;
- u8 channels[IEEE80211_24GHZ_CHANNELS] = {
+ u8 channels[LIBIPW_24GHZ_CHANNELS] = {
/* nop out the list */
[0] = 0
};
@@ -6266,11 +6286,11 @@ static void ipw_add_scan_channels(struct ipw_priv *priv,
channel_index++;
scan->channels_list[channel_index] = channel;
index =
- ieee80211_channel_to_index(priv->ieee, channel);
+ libipw_channel_to_index(priv->ieee, channel);
ipw_set_scan_type(scan, channel_index,
geo->bg[index].
flags &
- IEEE80211_CH_PASSIVE_ONLY ?
+ LIBIPW_CH_PASSIVE_ONLY ?
IPW_SCAN_PASSIVE_FULL_DWELL_SCAN
: scan_type);
}
@@ -6285,7 +6305,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv,
ipw_set_scan_type(scan, channel_index,
geo->bg[i].
flags &
- IEEE80211_CH_PASSIVE_ONLY ?
+ LIBIPW_CH_PASSIVE_ONLY ?
IPW_SCAN_PASSIVE_FULL_DWELL_SCAN
: scan_type);
}
@@ -6352,7 +6372,7 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
}
memset(&scan, 0, sizeof(scan));
- scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
+ scan.full_scan_index = cpu_to_le32(libipw_get_scans(priv->ieee));
if (type == IW_SCAN_TYPE_PASSIVE) {
IPW_DEBUG_WX("use passive scanning\n");
@@ -6383,13 +6403,13 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
u8 channel;
u8 band = 0;
- switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) {
- case IEEE80211_52GHZ_BAND:
+ switch (libipw_is_valid_channel(priv->ieee, priv->channel)) {
+ case LIBIPW_52GHZ_BAND:
band = (u8) (IPW_A_MODE << 6) | 1;
channel = priv->channel;
break;
- case IEEE80211_24GHZ_BAND:
+ case LIBIPW_24GHZ_BAND:
band = (u8) (IPW_B_MODE << 6) | 1;
channel = priv->channel;
break;
@@ -6510,8 +6530,8 @@ static int ipw_wpa_enable(struct ipw_priv *priv, int value)
static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value)
{
- struct ieee80211_device *ieee = priv->ieee;
- struct ieee80211_security sec = {
+ struct libipw_device *ieee = priv->ieee;
+ struct libipw_security sec = {
.flags = SEC_AUTH_MODE,
};
int ret = 0;
@@ -6561,8 +6581,8 @@ static int ipw_wx_set_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
- struct ieee80211_device *ieee = priv->ieee;
+ struct ipw_priv *priv = libipw_priv(dev);
+ struct libipw_device *ieee = priv->ieee;
u8 *buf;
int err = 0;
@@ -6597,8 +6617,8 @@ static int ipw_wx_get_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
- struct ieee80211_device *ieee = priv->ieee;
+ struct ipw_priv *priv = libipw_priv(dev);
+ struct libipw_device *ieee = priv->ieee;
int err = 0;
if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
@@ -6640,8 +6660,8 @@ static int ipw_wx_set_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
- struct ieee80211_device *ieee = priv->ieee;
+ struct ipw_priv *priv = libipw_priv(dev);
+ struct libipw_device *ieee = priv->ieee;
struct iw_param *param = &wrqu->param;
struct lib80211_crypt_data *crypt;
unsigned long flags;
@@ -6692,7 +6712,7 @@ static int ipw_wx_set_auth(struct net_device *dev,
* can use this to determine if the CAP_PRIVACY_ON bit should
* be set.
*/
- struct ieee80211_security sec = {
+ struct libipw_security sec = {
.flags = SEC_ENABLED,
.enabled = param->value,
};
@@ -6740,8 +6760,8 @@ static int ipw_wx_get_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
- struct ieee80211_device *ieee = priv->ieee;
+ struct ipw_priv *priv = libipw_priv(dev);
+ struct libipw_device *ieee = priv->ieee;
struct lib80211_crypt_data *crypt;
struct iw_param *param = &wrqu->param;
int ret = 0;
@@ -6799,7 +6819,7 @@ static int ipw_wx_set_encodeext(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
if (hwcrypto) {
@@ -6821,7 +6841,7 @@ static int ipw_wx_set_encodeext(struct net_device *dev,
}
}
- return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra);
+ return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra);
}
/* SIOCGIWENCODEEXT */
@@ -6829,8 +6849,8 @@ static int ipw_wx_get_encodeext(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
- return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra);
+ struct ipw_priv *priv = libipw_priv(dev);
+ return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra);
}
/* SIOCSIWMLME */
@@ -6838,7 +6858,7 @@ static int ipw_wx_set_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
struct iw_mlme *mlme = (struct iw_mlme *)extra;
__le16 reason;
@@ -6888,9 +6908,9 @@ static u8 ipw_qos_current_mode(struct ipw_priv * priv)
*/
static int ipw_qos_handle_probe_response(struct ipw_priv *priv,
int active_network,
- struct ieee80211_network *network)
+ struct libipw_network *network)
{
- u32 size = sizeof(struct ieee80211_qos_parameters);
+ u32 size = sizeof(struct libipw_qos_parameters);
if (network->capability & WLAN_CAPABILITY_IBSS)
network->qos_data.active = network->qos_data.supported;
@@ -6948,12 +6968,12 @@ static int ipw_qos_handle_probe_response(struct ipw_priv *priv,
* IPW_CMD_QOS_PARAMETERS and IPW_CMD_WME_INFO
*/
static int ipw_qos_activate(struct ipw_priv *priv,
- struct ieee80211_qos_data *qos_network_data)
+ struct libipw_qos_data *qos_network_data)
{
int err;
- struct ieee80211_qos_parameters qos_parameters[QOS_QOS_SETS];
- struct ieee80211_qos_parameters *active_one = NULL;
- u32 size = sizeof(struct ieee80211_qos_parameters);
+ struct libipw_qos_parameters qos_parameters[QOS_QOS_SETS];
+ struct libipw_qos_parameters *active_one = NULL;
+ u32 size = sizeof(struct libipw_qos_parameters);
u32 burst_duration;
int i;
u8 type;
@@ -7014,7 +7034,7 @@ static int ipw_qos_activate(struct ipw_priv *priv,
IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n");
err = ipw_send_qos_params_command(priv,
- (struct ieee80211_qos_parameters *)
+ (struct libipw_qos_parameters *)
&(qos_parameters[0]));
if (err)
IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n");
@@ -7028,13 +7048,13 @@ static int ipw_qos_activate(struct ipw_priv *priv,
static int ipw_qos_set_info_element(struct ipw_priv *priv)
{
int ret = 0;
- struct ieee80211_qos_information_element qos_info;
+ struct libipw_qos_information_element qos_info;
if (priv == NULL)
return -1;
qos_info.elementID = QOS_ELEMENT_ID;
- qos_info.length = sizeof(struct ieee80211_qos_information_element) - 2;
+ qos_info.length = sizeof(struct libipw_qos_information_element) - 2;
qos_info.version = QOS_VERSION_1;
qos_info.ac_info = 0;
@@ -7054,11 +7074,11 @@ static int ipw_qos_set_info_element(struct ipw_priv *priv)
* Set the QoS parameter with the association request structure
*/
static int ipw_qos_association(struct ipw_priv *priv,
- struct ieee80211_network *network)
+ struct libipw_network *network)
{
int err = 0;
- struct ieee80211_qos_data *qos_data = NULL;
- struct ieee80211_qos_data ibss_data = {
+ struct libipw_qos_data *qos_data = NULL;
+ struct libipw_qos_data ibss_data = {
.supported = 1,
.active = 1,
};
@@ -7100,11 +7120,11 @@ static int ipw_qos_association(struct ipw_priv *priv,
* setting
*/
static int ipw_qos_association_resp(struct ipw_priv *priv,
- struct ieee80211_network *network)
+ struct libipw_network *network)
{
int ret = 0;
unsigned long flags;
- u32 size = sizeof(struct ieee80211_qos_parameters);
+ u32 size = sizeof(struct libipw_qos_parameters);
int set_qos_param = 0;
if ((priv == NULL) || (network == NULL) ||
@@ -7120,7 +7140,7 @@ static int ipw_qos_association_resp(struct ipw_priv *priv,
spin_lock_irqsave(&priv->ieee->lock, flags);
if (network->flags & NETWORK_HAS_QOS_PARAMETERS) {
memcpy(&priv->assoc_network->qos_data, &network->qos_data,
- sizeof(struct ieee80211_qos_data));
+ sizeof(struct libipw_qos_data));
priv->assoc_network->qos_data.active = 1;
if ((network->qos_data.old_param_count !=
network->qos_data.param_count)) {
@@ -7156,7 +7176,7 @@ static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv)
if ((priv == NULL))
return 0;
- if (!(priv->ieee->modulation & IEEE80211_OFDM_MODULATION))
+ if (!(priv->ieee->modulation & LIBIPW_OFDM_MODULATION))
ret = priv->qos_data.burst_duration_CCK;
else
ret = priv->qos_data.burst_duration_OFDM;
@@ -7208,8 +7228,8 @@ static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority)
static int ipw_is_qos_active(struct net_device *dev,
struct sk_buff *skb)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
- struct ieee80211_qos_data *qos_data = NULL;
+ struct ipw_priv *priv = libipw_priv(dev);
+ struct libipw_qos_data *qos_data = NULL;
int active, supported;
u8 *daddr = skb->data + ETH_ALEN;
int unicast = !is_multicast_ether_addr(daddr);
@@ -7264,9 +7284,6 @@ static void ipw_bg_qos_activate(struct work_struct *work)
struct ipw_priv *priv =
container_of(work, struct ipw_priv, qos_activate);
- if (priv == NULL)
- return;
-
mutex_lock(&priv->mutex);
if (priv->status & STATUS_ASSOCIATED)
@@ -7276,10 +7293,10 @@ static void ipw_bg_qos_activate(struct work_struct *work)
}
static int ipw_handle_probe_response(struct net_device *dev,
- struct ieee80211_probe_response *resp,
- struct ieee80211_network *network)
+ struct libipw_probe_response *resp,
+ struct libipw_network *network)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int active_network = ((priv->status & STATUS_ASSOCIATED) &&
(network == priv->assoc_network));
@@ -7289,10 +7306,10 @@ static int ipw_handle_probe_response(struct net_device *dev,
}
static int ipw_handle_beacon(struct net_device *dev,
- struct ieee80211_beacon *resp,
- struct ieee80211_network *network)
+ struct libipw_beacon *resp,
+ struct libipw_network *network)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int active_network = ((priv->status & STATUS_ASSOCIATED) &&
(network == priv->assoc_network));
@@ -7302,22 +7319,22 @@ static int ipw_handle_beacon(struct net_device *dev,
}
static int ipw_handle_assoc_response(struct net_device *dev,
- struct ieee80211_assoc_response *resp,
- struct ieee80211_network *network)
+ struct libipw_assoc_response *resp,
+ struct libipw_network *network)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
ipw_qos_association_resp(priv, network);
return 0;
}
-static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters
+static int ipw_send_qos_params_command(struct ipw_priv *priv, struct libipw_qos_parameters
*qos_param)
{
return ipw_send_cmd_pdu(priv, IPW_CMD_QOS_PARAMETERS,
sizeof(*qos_param) * 3, qos_param);
}
-static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element
+static int ipw_send_qos_info_command(struct ipw_priv *priv, struct libipw_qos_information_element
*qos_param)
{
return ipw_send_cmd_pdu(priv, IPW_CMD_WME_INFO, sizeof(*qos_param),
@@ -7327,7 +7344,7 @@ static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos
#endif /* CONFIG_IPW2200_QOS */
static int ipw_associate_network(struct ipw_priv *priv,
- struct ieee80211_network *network,
+ struct libipw_network *network,
struct ipw_supported_rates *rates, int roaming)
{
int err;
@@ -7509,7 +7526,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
static void ipw_roam(void *data)
{
struct ipw_priv *priv = data;
- struct ieee80211_network *network = NULL;
+ struct libipw_network *network = NULL;
struct ipw_network_match match = {
.network = priv->assoc_network
};
@@ -7584,7 +7601,7 @@ static int ipw_associate(void *data)
{
struct ipw_priv *priv = data;
- struct ieee80211_network *network = NULL;
+ struct libipw_network *network = NULL;
struct ipw_network_match match = {
.network = NULL
};
@@ -7638,8 +7655,8 @@ static int ipw_associate(void *data)
priv->config & CFG_STATIC_CHANNEL) {
/* Use oldest network if the free list is empty */
if (list_empty(&priv->ieee->network_free_list)) {
- struct ieee80211_network *oldest = NULL;
- struct ieee80211_network *target;
+ struct libipw_network *oldest = NULL;
+ struct libipw_network *target;
list_for_each_entry(target, &priv->ieee->network_list, list) {
if ((oldest == NULL) ||
@@ -7660,7 +7677,7 @@ static int ipw_associate(void *data)
}
element = priv->ieee->network_free_list.next;
- network = list_entry(element, struct ieee80211_network, list);
+ network = list_entry(element, struct libipw_network, list);
ipw_adhoc_create(priv, network);
rates = &priv->rates;
list_del(element);
@@ -7716,18 +7733,18 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv,
switch (priv->ieee->sec.level) {
case SEC_LEVEL_3:
/* Remove CCMP HDR */
- memmove(skb->data + IEEE80211_3ADDR_LEN,
- skb->data + IEEE80211_3ADDR_LEN + 8,
- skb->len - IEEE80211_3ADDR_LEN - 8);
+ memmove(skb->data + LIBIPW_3ADDR_LEN,
+ skb->data + LIBIPW_3ADDR_LEN + 8,
+ skb->len - LIBIPW_3ADDR_LEN - 8);
skb_trim(skb, skb->len - 16); /* CCMP_HDR_LEN + CCMP_MIC_LEN */
break;
case SEC_LEVEL_2:
break;
case SEC_LEVEL_1:
/* Remove IV */
- memmove(skb->data + IEEE80211_3ADDR_LEN,
- skb->data + IEEE80211_3ADDR_LEN + 4,
- skb->len - IEEE80211_3ADDR_LEN - 4);
+ memmove(skb->data + LIBIPW_3ADDR_LEN,
+ skb->data + LIBIPW_3ADDR_LEN + 4,
+ skb->len - LIBIPW_3ADDR_LEN - 4);
skb_trim(skb, skb->len - 8); /* IV + ICV */
break;
case SEC_LEVEL_0:
@@ -7741,10 +7758,10 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv,
static void ipw_handle_data_packet(struct ipw_priv *priv,
struct ipw_rx_mem_buffer *rxb,
- struct ieee80211_rx_stats *stats)
+ struct libipw_rx_stats *stats)
{
struct net_device *dev = priv->net_dev;
- struct ieee80211_hdr_4addr *hdr;
+ struct libipw_hdr_4addr *hdr;
struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
/* We received data from the HW, so stop the watchdog */
@@ -7774,15 +7791,15 @@ static void ipw_handle_data_packet(struct ipw_priv *priv,
IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
/* HW decrypt will not clear the WEP bit, MIC, PN, etc. */
- hdr = (struct ieee80211_hdr_4addr *)rxb->skb->data;
+ hdr = (struct libipw_hdr_4addr *)rxb->skb->data;
if (priv->ieee->iw_mode != IW_MODE_MONITOR &&
(is_multicast_ether_addr(hdr->addr1) ?
!priv->ieee->host_mc_decrypt : !priv->ieee->host_decrypt))
ipw_rebuild_decrypted_skb(priv, rxb->skb);
- if (!ieee80211_rx(priv->ieee, rxb->skb, stats))
+ if (!libipw_rx(priv->ieee, rxb->skb, stats))
dev->stats.rx_errors++;
- else { /* ieee80211_rx succeeded, so it now owns the SKB */
+ else { /* libipw_rx succeeded, so it now owns the SKB */
rxb->skb = NULL;
__ipw_led_activity_on(priv);
}
@@ -7791,7 +7808,7 @@ static void ipw_handle_data_packet(struct ipw_priv *priv,
#ifdef CONFIG_IPW2200_RADIOTAP
static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
struct ipw_rx_mem_buffer *rxb,
- struct ieee80211_rx_stats *stats)
+ struct libipw_rx_stats *stats)
{
struct net_device *dev = priv->net_dev;
struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
@@ -7867,7 +7884,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
/* Convert signal to DBM */
ipw_rt->rt_dbmsignal = antsignal;
- ipw_rt->rt_dbmnoise = frame->noise;
+ ipw_rt->rt_dbmnoise = (s8) le16_to_cpu(frame->noise);
/* Convert the channel data and set the flags */
ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel));
@@ -7937,9 +7954,9 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
- if (!ieee80211_rx(priv->ieee, rxb->skb, stats))
+ if (!libipw_rx(priv->ieee, rxb->skb, stats))
dev->stats.rx_errors++;
- else { /* ieee80211_rx succeeded, so it now owns the SKB */
+ else { /* libipw_rx succeeded, so it now owns the SKB */
rxb->skb = NULL;
/* no LED during capture */
}
@@ -7947,28 +7964,28 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
#endif
#ifdef CONFIG_IPW2200_PROMISCUOUS
-#define ieee80211_is_probe_response(fc) \
+#define libipw_is_probe_response(fc) \
((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && \
(fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP )
-#define ieee80211_is_management(fc) \
+#define libipw_is_management(fc) \
((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
-#define ieee80211_is_control(fc) \
+#define libipw_is_control(fc) \
((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
-#define ieee80211_is_data(fc) \
+#define libipw_is_data(fc) \
((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
-#define ieee80211_is_assoc_request(fc) \
+#define libipw_is_assoc_request(fc) \
((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ)
-#define ieee80211_is_reassoc_request(fc) \
+#define libipw_is_reassoc_request(fc) \
((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
struct ipw_rx_mem_buffer *rxb,
- struct ieee80211_rx_stats *stats)
+ struct libipw_rx_stats *stats)
{
struct net_device *dev = priv->prom_net_dev;
struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
@@ -7981,7 +7998,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
u16 channel = frame->received_channel;
u8 phy_flags = frame->antennaAndPhy;
s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM;
- s8 noise = frame->noise;
+ s8 noise = (s8) le16_to_cpu(frame->noise);
u8 rate = frame->rate;
short len = le16_to_cpu(pkt->u.frame.length);
struct sk_buff *skb;
@@ -8018,17 +8035,17 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
}
hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE;
- if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) {
+ if (libipw_is_management(le16_to_cpu(hdr->frame_control))) {
if (filter & IPW_PROM_NO_MGMT)
return;
if (filter & IPW_PROM_MGMT_HEADER_ONLY)
hdr_only = 1;
- } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) {
+ } else if (libipw_is_control(le16_to_cpu(hdr->frame_control))) {
if (filter & IPW_PROM_NO_CTL)
return;
if (filter & IPW_PROM_CTL_HEADER_ONLY)
hdr_only = 1;
- } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) {
+ } else if (libipw_is_data(le16_to_cpu(hdr->frame_control))) {
if (filter & IPW_PROM_NO_DATA)
return;
if (filter & IPW_PROM_DATA_HEADER_ONLY)
@@ -8046,7 +8063,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
ipw_rt = (void *)skb->data;
if (hdr_only)
- len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
+ len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_control));
memcpy(ipw_rt->payload, hdr, len);
@@ -8143,7 +8160,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
IPW_DEBUG_RX("Rx packet of %d bytes.\n", skb->len);
- if (!ieee80211_rx(priv->prom_priv->ieee, skb, stats)) {
+ if (!libipw_rx(priv->prom_priv->ieee, skb, stats)) {
dev->stats.rx_errors++;
dev_kfree_skb_any(skb);
}
@@ -8151,7 +8168,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
#endif
static int is_network_packet(struct ipw_priv *priv,
- struct ieee80211_hdr_4addr *header)
+ struct libipw_hdr_4addr *header)
{
/* Filter incoming packets to determine if they are targetted toward
* this network, discarding packets coming from ourselves */
@@ -8189,7 +8206,7 @@ static int is_network_packet(struct ipw_priv *priv,
#define IPW_PACKET_RETRY_TIME HZ
static int is_duplicate_packet(struct ipw_priv *priv,
- struct ieee80211_hdr_4addr *header)
+ struct libipw_hdr_4addr *header)
{
u16 sc = le16_to_cpu(header->seq_ctl);
u16 seq = WLAN_GET_SEQ_SEQ(sc);
@@ -8263,14 +8280,14 @@ static int is_duplicate_packet(struct ipw_priv *priv,
static void ipw_handle_mgmt_packet(struct ipw_priv *priv,
struct ipw_rx_mem_buffer *rxb,
- struct ieee80211_rx_stats *stats)
+ struct libipw_rx_stats *stats)
{
struct sk_buff *skb = rxb->skb;
struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)skb->data;
- struct ieee80211_hdr_4addr *header = (struct ieee80211_hdr_4addr *)
+ struct libipw_hdr_4addr *header = (struct libipw_hdr_4addr *)
(skb->data + IPW_RX_FRAME_SIZE);
- ieee80211_rx_mgt(priv->ieee, header, stats);
+ libipw_rx_mgt(priv->ieee, header, stats);
if (priv->ieee->iw_mode == IW_MODE_ADHOC &&
((WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) ==
@@ -8292,12 +8309,12 @@ static void ipw_handle_mgmt_packet(struct ipw_priv *priv,
/* Advance past the ipw packet header to the 802.11 frame */
skb_pull(skb, IPW_RX_FRAME_SIZE);
- /* Push the ieee80211_rx_stats before the 802.11 frame */
+ /* Push the libipw_rx_stats before the 802.11 frame */
memcpy(skb_push(skb, sizeof(*stats)), stats, sizeof(*stats));
skb->dev = priv->ieee->dev;
- /* Point raw at the ieee80211_stats */
+ /* Point raw at the libipw_stats */
skb_reset_mac_header(skb);
skb->pkt_type = PACKET_OTHERHOST;
@@ -8317,7 +8334,7 @@ static void ipw_rx(struct ipw_priv *priv)
{
struct ipw_rx_mem_buffer *rxb;
struct ipw_rx_packet *pkt;
- struct ieee80211_hdr_4addr *header;
+ struct libipw_hdr_4addr *header;
u32 r, w, i;
u8 network_packet;
u8 fill_rx = 0;
@@ -8348,11 +8365,11 @@ static void ipw_rx(struct ipw_priv *priv)
switch (pkt->header.message_type) {
case RX_FRAME_TYPE: /* 802.11 frame */ {
- struct ieee80211_rx_stats stats = {
+ struct libipw_rx_stats stats = {
.rssi = pkt->u.frame.rssi_dbm -
IPW_RSSI_TO_DBM,
.signal =
- le16_to_cpu(pkt->u.frame.rssi_dbm) -
+ pkt->u.frame.rssi_dbm -
IPW_RSSI_TO_DBM + 0x100,
.noise =
le16_to_cpu(pkt->u.frame.noise),
@@ -8363,19 +8380,19 @@ static void ipw_rx(struct ipw_priv *priv)
.freq =
(pkt->u.frame.
control & (1 << 0)) ?
- IEEE80211_24GHZ_BAND :
- IEEE80211_52GHZ_BAND,
+ LIBIPW_24GHZ_BAND :
+ LIBIPW_52GHZ_BAND,
.len = le16_to_cpu(pkt->u.frame.length),
};
if (stats.rssi != 0)
- stats.mask |= IEEE80211_STATMASK_RSSI;
+ stats.mask |= LIBIPW_STATMASK_RSSI;
if (stats.signal != 0)
- stats.mask |= IEEE80211_STATMASK_SIGNAL;
+ stats.mask |= LIBIPW_STATMASK_SIGNAL;
if (stats.noise != 0)
- stats.mask |= IEEE80211_STATMASK_NOISE;
+ stats.mask |= LIBIPW_STATMASK_NOISE;
if (stats.rate != 0)
- stats.mask |= IEEE80211_STATMASK_RATE;
+ stats.mask |= LIBIPW_STATMASK_RATE;
priv->rx_packets++;
@@ -8400,7 +8417,7 @@ static void ipw_rx(struct ipw_priv *priv)
#endif
header =
- (struct ieee80211_hdr_4addr *)(rxb->skb->
+ (struct libipw_hdr_4addr *)(rxb->skb->
data +
IPW_RX_FRAME_SIZE);
/* TODO: Check Ad-Hoc dest/source and make sure
@@ -8423,7 +8440,7 @@ static void ipw_rx(struct ipw_priv *priv)
le16_to_cpu(pkt->u.frame.length));
if (le16_to_cpu(pkt->u.frame.length) <
- ieee80211_get_hdrlen(le16_to_cpu(
+ libipw_get_hdrlen(le16_to_cpu(
header->frame_ctl))) {
IPW_DEBUG_DROP
("Received packet is too small. "
@@ -8534,7 +8551,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
/* We default to disabling the LED code as right now it causes
* too many systems to lock up... */
- if (!led)
+ if (!led_support)
priv->config |= CFG_NO_LED;
if (associate)
@@ -8556,10 +8573,10 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
IPW_DEBUG_INFO("Radio disabled.\n");
}
- if (channel != 0) {
+ if (default_channel != 0) {
priv->config |= CFG_STATIC_CHANNEL;
- priv->channel = channel;
- IPW_DEBUG_INFO("Bind to static channel %d\n", channel);
+ priv->channel = default_channel;
+ IPW_DEBUG_INFO("Bind to static channel %d\n", default_channel);
/* TODO: Validate that provided channel is in range */
}
#ifdef CONFIG_IPW2200_QOS
@@ -8567,7 +8584,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
burst_duration_CCK, burst_duration_OFDM);
#endif /* CONFIG_IPW2200_QOS */
- switch (mode) {
+ switch (network_mode) {
case 1:
priv->ieee->iw_mode = IW_MODE_ADHOC;
priv->net_dev->type = ARPHRD_ETHER;
@@ -8608,9 +8625,9 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
": Detected Intel PRO/Wireless 2915ABG Network "
"Connection\n");
priv->ieee->abg_true = 1;
- band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND;
- modulation = IEEE80211_OFDM_MODULATION |
- IEEE80211_CCK_MODULATION;
+ band = LIBIPW_52GHZ_BAND | LIBIPW_24GHZ_BAND;
+ modulation = LIBIPW_OFDM_MODULATION |
+ LIBIPW_CCK_MODULATION;
priv->adapter = IPW_2915ABG;
priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B;
} else {
@@ -8620,9 +8637,9 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
"Connection\n");
priv->ieee->abg_true = 0;
- band = IEEE80211_24GHZ_BAND;
- modulation = IEEE80211_OFDM_MODULATION |
- IEEE80211_CCK_MODULATION;
+ band = LIBIPW_24GHZ_BAND;
+ modulation = LIBIPW_OFDM_MODULATION |
+ LIBIPW_CCK_MODULATION;
priv->adapter = IPW_2200BG;
priv->ieee->mode = IEEE_G | IEEE_B;
}
@@ -8630,7 +8647,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
priv->ieee->freq_band = band;
priv->ieee->modulation = modulation;
- priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK;
+ priv->rates_mask = LIBIPW_DEFAULT_RATES_MASK;
priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
@@ -8656,24 +8673,6 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
*
*/
-static int ipw_wx_get_name(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = ieee80211_priv(dev);
- mutex_lock(&priv->mutex);
- if (priv->status & STATUS_RF_KILL_MASK)
- strcpy(wrqu->name, "radio off");
- else if (!(priv->status & STATUS_ASSOCIATED))
- strcpy(wrqu->name, "unassociated");
- else
- snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c",
- ipw_modes[priv->assoc_request.ieee_mode]);
- IPW_DEBUG_WX("Name: %s\n", wrqu->name);
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
static int ipw_set_channel(struct ipw_priv *priv, u8 channel)
{
if (channel == 0) {
@@ -8730,8 +8729,8 @@ static int ipw_wx_set_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
- const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
+ struct ipw_priv *priv = libipw_priv(dev);
+ const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
struct iw_freq *fwrq = &wrqu->freq;
int ret = 0, i;
u8 channel, flags;
@@ -8746,23 +8745,23 @@ static int ipw_wx_set_freq(struct net_device *dev,
}
/* if setting by freq convert to channel */
if (fwrq->e == 1) {
- channel = ieee80211_freq_to_channel(priv->ieee, fwrq->m);
+ channel = libipw_freq_to_channel(priv->ieee, fwrq->m);
if (channel == 0)
return -EINVAL;
} else
channel = fwrq->m;
- if (!(band = ieee80211_is_valid_channel(priv->ieee, channel)))
+ if (!(band = libipw_is_valid_channel(priv->ieee, channel)))
return -EINVAL;
if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- i = ieee80211_channel_to_index(priv->ieee, channel);
+ i = libipw_channel_to_index(priv->ieee, channel);
if (i == -1)
return -EINVAL;
- flags = (band == IEEE80211_24GHZ_BAND) ?
+ flags = (band == LIBIPW_24GHZ_BAND) ?
geo->bg[i].flags : geo->a[i].flags;
- if (flags & IEEE80211_CH_PASSIVE_ONLY) {
+ if (flags & LIBIPW_CH_PASSIVE_ONLY) {
IPW_DEBUG_WX("Invalid Ad-Hoc channel for 802.11a\n");
return -EINVAL;
}
@@ -8779,7 +8778,7 @@ static int ipw_wx_get_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
wrqu->freq.e = 0;
@@ -8790,16 +8789,16 @@ static int ipw_wx_get_freq(struct net_device *dev,
priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) {
int i;
- i = ieee80211_channel_to_index(priv->ieee, priv->channel);
+ i = libipw_channel_to_index(priv->ieee, priv->channel);
BUG_ON(i == -1);
wrqu->freq.e = 1;
- switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) {
- case IEEE80211_52GHZ_BAND:
+ switch (libipw_is_valid_channel(priv->ieee, priv->channel)) {
+ case LIBIPW_52GHZ_BAND:
wrqu->freq.m = priv->ieee->geo.a[i].freq * 100000;
break;
- case IEEE80211_24GHZ_BAND:
+ case LIBIPW_24GHZ_BAND:
wrqu->freq.m = priv->ieee->geo.bg[i].freq * 100000;
break;
@@ -8818,7 +8817,7 @@ static int ipw_wx_set_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int err = 0;
IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode);
@@ -8870,7 +8869,7 @@ static int ipw_wx_get_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
mutex_lock(&priv->mutex);
wrqu->mode = priv->ieee->iw_mode;
IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode);
@@ -8899,9 +8898,9 @@ static int ipw_wx_get_range(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
struct iw_range *range = (struct iw_range *)extra;
- const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
+ const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
int i = 0, j;
wrqu->data.length = sizeof(*range);
@@ -8945,7 +8944,7 @@ static int ipw_wx_get_range(struct net_device *dev,
if (priv->ieee->mode & (IEEE_B | IEEE_G)) {
for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES; j++) {
if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
- (geo->bg[j].flags & IEEE80211_CH_PASSIVE_ONLY))
+ (geo->bg[j].flags & LIBIPW_CH_PASSIVE_ONLY))
continue;
range->freq[i].i = geo->bg[j].channel;
@@ -8958,7 +8957,7 @@ static int ipw_wx_get_range(struct net_device *dev,
if (priv->ieee->mode & IEEE_A) {
for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES; j++) {
if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
- (geo->a[j].flags & IEEE80211_CH_PASSIVE_ONLY))
+ (geo->a[j].flags & LIBIPW_CH_PASSIVE_ONLY))
continue;
range->freq[i].i = geo->a[j].channel;
@@ -8993,7 +8992,7 @@ static int ipw_wx_set_wap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
static const unsigned char any[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
@@ -9042,7 +9041,7 @@ static int ipw_wx_get_wap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
/* If we are associated, trying to associate, or have a statically
* configured BSSID then return that; otherwise return ANY */
@@ -9064,7 +9063,7 @@ static int ipw_wx_set_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int length;
DECLARE_SSID_BUF(ssid);
@@ -9110,7 +9109,7 @@ static int ipw_wx_get_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
DECLARE_SSID_BUF(ssid);
/* If we are associated, trying to associate, or have a statically
@@ -9136,7 +9135,7 @@ static int ipw_wx_set_nick(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
IPW_DEBUG_WX("Setting nick to '%s'\n", extra);
if (wrqu->data.length > IW_ESSID_MAX_SIZE)
@@ -9155,7 +9154,7 @@ static int ipw_wx_get_nick(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
IPW_DEBUG_WX("Getting nick\n");
mutex_lock(&priv->mutex);
wrqu->data.length = strlen(priv->nick);
@@ -9169,7 +9168,7 @@ static int ipw_wx_set_sens(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int err = 0;
IPW_DEBUG_WX("Setting roaming threshold to %d\n", wrqu->sens.value);
@@ -9199,7 +9198,7 @@ static int ipw_wx_get_sens(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
mutex_lock(&priv->mutex);
wrqu->sens.fixed = 1;
wrqu->sens.value = priv->roaming_threshold;
@@ -9216,7 +9215,7 @@ static int ipw_wx_set_rate(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
/* TODO: We should use semaphores or locks for access to priv */
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
u32 target_rate = wrqu->bitrate.value;
u32 fixed, mask;
@@ -9226,7 +9225,7 @@ static int ipw_wx_set_rate(struct net_device *dev,
if (target_rate == -1) {
fixed = 0;
- mask = IEEE80211_DEFAULT_RATES_MASK;
+ mask = LIBIPW_DEFAULT_RATES_MASK;
/* Now we should reassociate */
goto apply;
}
@@ -9235,62 +9234,62 @@ static int ipw_wx_set_rate(struct net_device *dev,
fixed = wrqu->bitrate.fixed;
if (target_rate == 1000000 || !fixed)
- mask |= IEEE80211_CCK_RATE_1MB_MASK;
+ mask |= LIBIPW_CCK_RATE_1MB_MASK;
if (target_rate == 1000000)
goto apply;
if (target_rate == 2000000 || !fixed)
- mask |= IEEE80211_CCK_RATE_2MB_MASK;
+ mask |= LIBIPW_CCK_RATE_2MB_MASK;
if (target_rate == 2000000)
goto apply;
if (target_rate == 5500000 || !fixed)
- mask |= IEEE80211_CCK_RATE_5MB_MASK;
+ mask |= LIBIPW_CCK_RATE_5MB_MASK;
if (target_rate == 5500000)
goto apply;
if (target_rate == 6000000 || !fixed)
- mask |= IEEE80211_OFDM_RATE_6MB_MASK;
+ mask |= LIBIPW_OFDM_RATE_6MB_MASK;
if (target_rate == 6000000)
goto apply;
if (target_rate == 9000000 || !fixed)
- mask |= IEEE80211_OFDM_RATE_9MB_MASK;
+ mask |= LIBIPW_OFDM_RATE_9MB_MASK;
if (target_rate == 9000000)
goto apply;
if (target_rate == 11000000 || !fixed)
- mask |= IEEE80211_CCK_RATE_11MB_MASK;
+ mask |= LIBIPW_CCK_RATE_11MB_MASK;
if (target_rate == 11000000)
goto apply;
if (target_rate == 12000000 || !fixed)
- mask |= IEEE80211_OFDM_RATE_12MB_MASK;
+ mask |= LIBIPW_OFDM_RATE_12MB_MASK;
if (target_rate == 12000000)
goto apply;
if (target_rate == 18000000 || !fixed)
- mask |= IEEE80211_OFDM_RATE_18MB_MASK;
+ mask |= LIBIPW_OFDM_RATE_18MB_MASK;
if (target_rate == 18000000)
goto apply;
if (target_rate == 24000000 || !fixed)
- mask |= IEEE80211_OFDM_RATE_24MB_MASK;
+ mask |= LIBIPW_OFDM_RATE_24MB_MASK;
if (target_rate == 24000000)
goto apply;
if (target_rate == 36000000 || !fixed)
- mask |= IEEE80211_OFDM_RATE_36MB_MASK;
+ mask |= LIBIPW_OFDM_RATE_36MB_MASK;
if (target_rate == 36000000)
goto apply;
if (target_rate == 48000000 || !fixed)
- mask |= IEEE80211_OFDM_RATE_48MB_MASK;
+ mask |= LIBIPW_OFDM_RATE_48MB_MASK;
if (target_rate == 48000000)
goto apply;
if (target_rate == 54000000 || !fixed)
- mask |= IEEE80211_OFDM_RATE_54MB_MASK;
+ mask |= LIBIPW_OFDM_RATE_54MB_MASK;
if (target_rate == 54000000)
goto apply;
@@ -9301,7 +9300,7 @@ static int ipw_wx_set_rate(struct net_device *dev,
IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n",
mask, fixed ? "fixed" : "sub-rates");
mutex_lock(&priv->mutex);
- if (mask == IEEE80211_DEFAULT_RATES_MASK) {
+ if (mask == LIBIPW_DEFAULT_RATES_MASK) {
priv->config &= ~CFG_FIXED_RATE;
ipw_set_fixed_rate(priv, priv->ieee->mode);
} else
@@ -9328,7 +9327,7 @@ static int ipw_wx_get_rate(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
mutex_lock(&priv->mutex);
wrqu->bitrate.value = priv->last_rate;
wrqu->bitrate.fixed = (priv->config & CFG_FIXED_RATE) ? 1 : 0;
@@ -9341,7 +9340,7 @@ static int ipw_wx_set_rts(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
mutex_lock(&priv->mutex);
if (wrqu->rts.disabled || !wrqu->rts.fixed)
priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
@@ -9364,7 +9363,7 @@ static int ipw_wx_get_rts(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
mutex_lock(&priv->mutex);
wrqu->rts.value = priv->rts_threshold;
wrqu->rts.fixed = 0; /* no auto select */
@@ -9378,7 +9377,7 @@ static int ipw_wx_set_txpow(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int err = 0;
mutex_lock(&priv->mutex);
@@ -9412,7 +9411,7 @@ static int ipw_wx_get_txpow(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
mutex_lock(&priv->mutex);
wrqu->power.value = priv->tx_power;
wrqu->power.fixed = 1;
@@ -9430,7 +9429,7 @@ static int ipw_wx_set_frag(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
mutex_lock(&priv->mutex);
if (wrqu->frag.disabled || !wrqu->frag.fixed)
priv->ieee->fts = DEFAULT_FTS;
@@ -9454,7 +9453,7 @@ static int ipw_wx_get_frag(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
mutex_lock(&priv->mutex);
wrqu->frag.value = priv->ieee->fts;
wrqu->frag.fixed = 0; /* no auto select */
@@ -9469,7 +9468,7 @@ static int ipw_wx_set_retry(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
return -EINVAL;
@@ -9502,7 +9501,7 @@ static int ipw_wx_get_retry(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
mutex_lock(&priv->mutex);
wrqu->retry.disabled = 0;
@@ -9533,7 +9532,7 @@ static int ipw_wx_set_scan(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
struct iw_scan_req *req = (struct iw_scan_req *)extra;
struct delayed_work *work = NULL;
@@ -9569,20 +9568,20 @@ static int ipw_wx_get_scan(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
- return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra);
+ struct ipw_priv *priv = libipw_priv(dev);
+ return libipw_wx_get_scan(priv->ieee, info, wrqu, extra);
}
static int ipw_wx_set_encode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *key)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int ret;
u32 cap = priv->capability;
mutex_lock(&priv->mutex);
- ret = ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
+ ret = libipw_wx_set_encode(priv->ieee, info, wrqu, key);
/* In IBSS mode, we need to notify the firmware to update
* the beacon info after we changed the capability. */
@@ -9599,15 +9598,15 @@ static int ipw_wx_get_encode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *key)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
- return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key);
+ struct ipw_priv *priv = libipw_priv(dev);
+ return libipw_wx_get_encode(priv->ieee, info, wrqu, key);
}
static int ipw_wx_set_power(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int err;
mutex_lock(&priv->mutex);
if (wrqu->power.disabled) {
@@ -9658,7 +9657,7 @@ static int ipw_wx_get_power(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
mutex_lock(&priv->mutex);
if (!(priv->power_mode & IPW_POWER_ENABLED))
wrqu->power.disabled = 1;
@@ -9675,7 +9674,7 @@ static int ipw_wx_set_powermode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int mode = *(int *)extra;
int err;
@@ -9701,7 +9700,7 @@ static int ipw_wx_get_powermode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int level = IPW_POWER_LEVEL(priv->power_mode);
char *p = extra;
@@ -9733,7 +9732,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int mode = *(int *)extra;
u8 band = 0, modulation = 0;
@@ -9745,8 +9744,8 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev,
if (priv->adapter == IPW_2915ABG) {
priv->ieee->abg_true = 1;
if (mode & IEEE_A) {
- band |= IEEE80211_52GHZ_BAND;
- modulation |= IEEE80211_OFDM_MODULATION;
+ band |= LIBIPW_52GHZ_BAND;
+ modulation |= LIBIPW_OFDM_MODULATION;
} else
priv->ieee->abg_true = 0;
} else {
@@ -9761,14 +9760,14 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev,
}
if (mode & IEEE_B) {
- band |= IEEE80211_24GHZ_BAND;
- modulation |= IEEE80211_CCK_MODULATION;
+ band |= LIBIPW_24GHZ_BAND;
+ modulation |= LIBIPW_CCK_MODULATION;
} else
priv->ieee->abg_true = 0;
if (mode & IEEE_G) {
- band |= IEEE80211_24GHZ_BAND;
- modulation |= IEEE80211_OFDM_MODULATION;
+ band |= LIBIPW_24GHZ_BAND;
+ modulation |= LIBIPW_OFDM_MODULATION;
} else
priv->ieee->abg_true = 0;
@@ -9798,7 +9797,7 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
mutex_lock(&priv->mutex);
switch (priv->ieee->mode) {
case IEEE_A:
@@ -9839,7 +9838,7 @@ static int ipw_wx_set_preamble(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int mode = *(int *)extra;
mutex_lock(&priv->mutex);
/* Switching from SHORT -> LONG requires a disassociation */
@@ -9872,7 +9871,7 @@ static int ipw_wx_get_preamble(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
mutex_lock(&priv->mutex);
if (priv->config & CFG_PREAMBLE_LONG)
snprintf(wrqu->name, IFNAMSIZ, "long (1)");
@@ -9887,7 +9886,7 @@ static int ipw_wx_set_monitor(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int *parms = (int *)extra;
int enable = (parms[0] > 0);
mutex_lock(&priv->mutex);
@@ -9921,7 +9920,7 @@ static int ipw_wx_reset(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
IPW_DEBUG_WX("RESET\n");
queue_work(priv->workqueue, &priv->adapter_restart);
return 0;
@@ -9931,7 +9930,7 @@ static int ipw_wx_sw_reset(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
union iwreq_data wrqu_sec = {
.encoding = {
.flags = IW_ENCODE_DISABLED,
@@ -9954,7 +9953,7 @@ static int ipw_wx_sw_reset(struct net_device *dev,
ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW);
mutex_unlock(&priv->mutex);
- ieee80211_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL);
+ libipw_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL);
mutex_lock(&priv->mutex);
if (!(priv->status & STATUS_RF_KILL_MASK)) {
@@ -9973,7 +9972,7 @@ static int ipw_wx_sw_reset(struct net_device *dev,
/* Rebase the WE IOCTLs to zero for the handler array */
#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT]
static iw_handler ipw_wx_handlers[] = {
- IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name,
+ IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname,
IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq,
IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq,
IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode,
@@ -10099,7 +10098,7 @@ static struct iw_handler_def ipw_wx_handler_def = {
*/
static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
struct iw_statistics *wstats;
wstats = &priv->wstats;
@@ -10180,13 +10179,13 @@ static int ipw_net_stop(struct net_device *dev)
todo:
modify to send one tfd per fragment instead of using chunking. otherwise
-we need to heavily modify the ieee80211_skb_to_txb.
+we need to heavily modify the libipw_skb_to_txb.
*/
-static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
+static int ipw_tx_skb(struct ipw_priv *priv, struct libipw_txb *txb,
int pri)
{
- struct ieee80211_hdr_3addrqos *hdr = (struct ieee80211_hdr_3addrqos *)
+ struct libipw_hdr_3addrqos *hdr = (struct libipw_hdr_3addrqos *)
txb->fragments[0]->data;
int i = 0;
struct tfd_frame *tfd;
@@ -10198,13 +10197,12 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
#endif
struct clx2_queue *q = &txq->q;
u8 id, hdr_len, unicast;
- u16 remaining_bytes;
int fc;
if (!(priv->status & STATUS_ASSOCIATED))
goto drop;
- hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+ hdr_len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
switch (priv->ieee->iw_mode) {
case IW_MODE_ADHOC:
unicast = !is_multicast_ether_addr(hdr->addr1);
@@ -10237,7 +10235,6 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
tfd->u.data.cmd_id = DINO_CMD_TX;
tfd->u.data.len = cpu_to_le16(txb->payload_size);
- remaining_bytes = txb->payload_size;
if (priv->assoc_request.ieee_mode == IPW_B_MODE)
tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_CCK;
@@ -10374,13 +10371,13 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
drop:
IPW_DEBUG_DROP("Silently dropping Tx packet.\n");
- ieee80211_txb_free(txb);
+ libipw_txb_free(txb);
return NETDEV_TX_OK;
}
static int ipw_net_is_queue_full(struct net_device *dev, int pri)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
#ifdef CONFIG_IPW2200_QOS
int tx_id = ipw_get_tx_queue_number(priv, pri);
struct clx2_tx_queue *txq = &priv->txq[tx_id];
@@ -10396,9 +10393,9 @@ static int ipw_net_is_queue_full(struct net_device *dev, int pri)
#ifdef CONFIG_IPW2200_PROMISCUOUS
static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
- struct ieee80211_txb *txb)
+ struct libipw_txb *txb)
{
- struct ieee80211_rx_stats dummystats;
+ struct libipw_rx_stats dummystats;
struct ieee80211_hdr *hdr;
u8 n;
u16 filter = priv->prom_priv->filter;
@@ -10411,17 +10408,17 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
/* Filtering of fragment chains is done agains the first fragment */
hdr = (void *)txb->fragments[0]->data;
- if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) {
+ if (libipw_is_management(le16_to_cpu(hdr->frame_control))) {
if (filter & IPW_PROM_NO_MGMT)
return;
if (filter & IPW_PROM_MGMT_HEADER_ONLY)
hdr_only = 1;
- } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) {
+ } else if (libipw_is_control(le16_to_cpu(hdr->frame_control))) {
if (filter & IPW_PROM_NO_CTL)
return;
if (filter & IPW_PROM_CTL_HEADER_ONLY)
hdr_only = 1;
- } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) {
+ } else if (libipw_is_data(le16_to_cpu(hdr->frame_control))) {
if (filter & IPW_PROM_NO_DATA)
return;
if (filter & IPW_PROM_DATA_HEADER_ONLY)
@@ -10436,7 +10433,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
if (hdr_only) {
hdr = (void *)src->data;
- len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
+ len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_control));
} else
len = src->len;
@@ -10470,18 +10467,18 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
skb_copy_from_linear_data(src, skb_put(dst, len), len);
- if (!ieee80211_rx(priv->prom_priv->ieee, dst, &dummystats))
+ if (!libipw_rx(priv->prom_priv->ieee, dst, &dummystats))
dev_kfree_skb_any(dst);
}
}
#endif
-static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb,
- struct net_device *dev, int pri)
+static netdev_tx_t ipw_net_hard_start_xmit(struct libipw_txb *txb,
+ struct net_device *dev, int pri)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
unsigned long flags;
- int ret;
+ netdev_tx_t ret;
IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size);
spin_lock_irqsave(&priv->lock, flags);
@@ -10506,7 +10503,7 @@ static void ipw_net_set_multicast_list(struct net_device *dev)
static int ipw_net_set_mac_address(struct net_device *dev, void *p)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
struct sockaddr *addr = p;
if (!is_valid_ether_addr(addr->sa_data))
@@ -10524,7 +10521,7 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p)
static void ipw_ethtool_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- struct ipw_priv *p = ieee80211_priv(dev);
+ struct ipw_priv *p = libipw_priv(dev);
char vers[64];
char date[32];
u32 len;
@@ -10545,7 +10542,7 @@ static void ipw_ethtool_get_drvinfo(struct net_device *dev,
static u32 ipw_ethtool_get_link(struct net_device *dev)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
return (priv->status & STATUS_ASSOCIATED) != 0;
}
@@ -10557,7 +10554,7 @@ static int ipw_ethtool_get_eeprom_len(struct net_device *dev)
static int ipw_ethtool_get_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom, u8 * bytes)
{
- struct ipw_priv *p = ieee80211_priv(dev);
+ struct ipw_priv *p = libipw_priv(dev);
if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
return -EINVAL;
@@ -10570,7 +10567,7 @@ static int ipw_ethtool_get_eeprom(struct net_device *dev,
static int ipw_ethtool_set_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom, u8 * bytes)
{
- struct ipw_priv *p = ieee80211_priv(dev);
+ struct ipw_priv *p = libipw_priv(dev);
int i;
if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
@@ -10786,9 +10783,9 @@ static int __devinit ipw_setup_deferred_work(struct ipw_priv *priv)
}
static void shim__set_security(struct net_device *dev,
- struct ieee80211_security *sec)
+ struct libipw_security *sec)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = libipw_priv(dev);
int i;
for (i = 0; i < 4; i++) {
if (sec->flags & (1 << i)) {
@@ -10873,21 +10870,21 @@ static int init_supported_rates(struct ipw_priv *priv,
memset(rates, 0, sizeof(*rates));
/* configure supported rates */
switch (priv->ieee->freq_band) {
- case IEEE80211_52GHZ_BAND:
+ case LIBIPW_52GHZ_BAND:
rates->ieee_mode = IPW_A_MODE;
rates->purpose = IPW_RATE_CAPABILITIES;
- ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION,
- IEEE80211_OFDM_DEFAULT_RATES_MASK);
+ ipw_add_ofdm_scan_rates(rates, LIBIPW_CCK_MODULATION,
+ LIBIPW_OFDM_DEFAULT_RATES_MASK);
break;
default: /* Mixed or 2.4Ghz */
rates->ieee_mode = IPW_G_MODE;
rates->purpose = IPW_RATE_CAPABILITIES;
- ipw_add_cck_scan_rates(rates, IEEE80211_CCK_MODULATION,
- IEEE80211_CCK_DEFAULT_RATES_MASK);
- if (priv->ieee->modulation & IEEE80211_OFDM_MODULATION) {
- ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION,
- IEEE80211_OFDM_DEFAULT_RATES_MASK);
+ ipw_add_cck_scan_rates(rates, LIBIPW_CCK_MODULATION,
+ LIBIPW_CCK_DEFAULT_RATES_MASK);
+ if (priv->ieee->modulation & LIBIPW_OFDM_MODULATION) {
+ ipw_add_ofdm_scan_rates(rates, LIBIPW_CCK_MODULATION,
+ LIBIPW_OFDM_DEFAULT_RATES_MASK);
}
break;
}
@@ -10993,7 +10990,7 @@ static int ipw_config(struct ipw_priv *priv)
* table.
*
*/
-static const struct ieee80211_geo ipw_geos[] = {
+static const struct libipw_geo ipw_geos[] = {
{ /* Restricted */
"---",
.bg_channels = 11,
@@ -11015,10 +11012,10 @@ static const struct ieee80211_geo ipw_geos[] = {
{5200, 40},
{5220, 44},
{5240, 48},
- {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
- {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
- {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
- {5320, 64, IEEE80211_CH_PASSIVE_ONLY}},
+ {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
+ {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
+ {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
+ {5320, 64, LIBIPW_CH_PASSIVE_ONLY}},
},
{ /* Rest of World */
@@ -11043,10 +11040,10 @@ static const struct ieee80211_geo ipw_geos[] = {
{5200, 40},
{5220, 44},
{5240, 48},
- {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
- {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
- {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
- {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
+ {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
+ {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
+ {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
+ {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
{5745, 149},
{5765, 153},
{5785, 157},
@@ -11066,15 +11063,15 @@ static const struct ieee80211_geo ipw_geos[] = {
{5200, 40},
{5220, 44},
{5240, 48},
- {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
- {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
- {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
- {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
- {5745, 149, IEEE80211_CH_PASSIVE_ONLY},
- {5765, 153, IEEE80211_CH_PASSIVE_ONLY},
- {5785, 157, IEEE80211_CH_PASSIVE_ONLY},
- {5805, 161, IEEE80211_CH_PASSIVE_ONLY},
- {5825, 165, IEEE80211_CH_PASSIVE_ONLY}},
+ {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
+ {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
+ {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
+ {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
+ {5745, 149, LIBIPW_CH_PASSIVE_ONLY},
+ {5765, 153, LIBIPW_CH_PASSIVE_ONLY},
+ {5785, 157, LIBIPW_CH_PASSIVE_ONLY},
+ {5805, 161, LIBIPW_CH_PASSIVE_ONLY},
+ {5825, 165, LIBIPW_CH_PASSIVE_ONLY}},
},
{ /* Custom Japan */
@@ -11111,21 +11108,21 @@ static const struct ieee80211_geo ipw_geos[] = {
{5200, 40},
{5220, 44},
{5240, 48},
- {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
- {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
- {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
- {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
- {5500, 100, IEEE80211_CH_PASSIVE_ONLY},
- {5520, 104, IEEE80211_CH_PASSIVE_ONLY},
- {5540, 108, IEEE80211_CH_PASSIVE_ONLY},
- {5560, 112, IEEE80211_CH_PASSIVE_ONLY},
- {5580, 116, IEEE80211_CH_PASSIVE_ONLY},
- {5600, 120, IEEE80211_CH_PASSIVE_ONLY},
- {5620, 124, IEEE80211_CH_PASSIVE_ONLY},
- {5640, 128, IEEE80211_CH_PASSIVE_ONLY},
- {5660, 132, IEEE80211_CH_PASSIVE_ONLY},
- {5680, 136, IEEE80211_CH_PASSIVE_ONLY},
- {5700, 140, IEEE80211_CH_PASSIVE_ONLY}},
+ {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
+ {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
+ {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
+ {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
+ {5500, 100, LIBIPW_CH_PASSIVE_ONLY},
+ {5520, 104, LIBIPW_CH_PASSIVE_ONLY},
+ {5540, 108, LIBIPW_CH_PASSIVE_ONLY},
+ {5560, 112, LIBIPW_CH_PASSIVE_ONLY},
+ {5580, 116, LIBIPW_CH_PASSIVE_ONLY},
+ {5600, 120, LIBIPW_CH_PASSIVE_ONLY},
+ {5620, 124, LIBIPW_CH_PASSIVE_ONLY},
+ {5640, 128, LIBIPW_CH_PASSIVE_ONLY},
+ {5660, 132, LIBIPW_CH_PASSIVE_ONLY},
+ {5680, 136, LIBIPW_CH_PASSIVE_ONLY},
+ {5700, 140, LIBIPW_CH_PASSIVE_ONLY}},
},
{ /* Custom Japan */
@@ -11135,7 +11132,7 @@ static const struct ieee80211_geo ipw_geos[] = {
{2427, 4}, {2432, 5}, {2437, 6},
{2442, 7}, {2447, 8}, {2452, 9},
{2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY}},
+ {2472, 13}, {2484, 14, LIBIPW_CH_B_ONLY}},
.a_channels = 4,
.a = {{5170, 34}, {5190, 38},
{5210, 42}, {5230, 46}},
@@ -11148,8 +11145,8 @@ static const struct ieee80211_geo ipw_geos[] = {
{2427, 4}, {2432, 5}, {2437, 6},
{2442, 7}, {2447, 8}, {2452, 9},
{2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY |
- IEEE80211_CH_PASSIVE_ONLY}},
+ {2472, 13}, {2484, 14, LIBIPW_CH_B_ONLY |
+ LIBIPW_CH_PASSIVE_ONLY}},
},
{ /* High Band */
@@ -11159,8 +11156,8 @@ static const struct ieee80211_geo ipw_geos[] = {
{2427, 4}, {2432, 5}, {2437, 6},
{2442, 7}, {2447, 8}, {2452, 9},
{2457, 10}, {2462, 11},
- {2467, 12, IEEE80211_CH_PASSIVE_ONLY},
- {2472, 13, IEEE80211_CH_PASSIVE_ONLY}},
+ {2467, 12, LIBIPW_CH_PASSIVE_ONLY},
+ {2472, 13, LIBIPW_CH_PASSIVE_ONLY}},
.a_channels = 4,
.a = {{5745, 149}, {5765, 153},
{5785, 157}, {5805, 161}},
@@ -11186,33 +11183,33 @@ static const struct ieee80211_geo ipw_geos[] = {
{2427, 4}, {2432, 5}, {2437, 6},
{2442, 7}, {2447, 8}, {2452, 9},
{2457, 10}, {2462, 11},
- {2467, 12, IEEE80211_CH_PASSIVE_ONLY},
- {2472, 13, IEEE80211_CH_PASSIVE_ONLY}},
+ {2467, 12, LIBIPW_CH_PASSIVE_ONLY},
+ {2472, 13, LIBIPW_CH_PASSIVE_ONLY}},
.a_channels = 24,
- .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY},
- {5200, 40, IEEE80211_CH_PASSIVE_ONLY},
- {5220, 44, IEEE80211_CH_PASSIVE_ONLY},
- {5240, 48, IEEE80211_CH_PASSIVE_ONLY},
- {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
- {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
- {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
- {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
- {5500, 100, IEEE80211_CH_PASSIVE_ONLY},
- {5520, 104, IEEE80211_CH_PASSIVE_ONLY},
- {5540, 108, IEEE80211_CH_PASSIVE_ONLY},
- {5560, 112, IEEE80211_CH_PASSIVE_ONLY},
- {5580, 116, IEEE80211_CH_PASSIVE_ONLY},
- {5600, 120, IEEE80211_CH_PASSIVE_ONLY},
- {5620, 124, IEEE80211_CH_PASSIVE_ONLY},
- {5640, 128, IEEE80211_CH_PASSIVE_ONLY},
- {5660, 132, IEEE80211_CH_PASSIVE_ONLY},
- {5680, 136, IEEE80211_CH_PASSIVE_ONLY},
- {5700, 140, IEEE80211_CH_PASSIVE_ONLY},
- {5745, 149, IEEE80211_CH_PASSIVE_ONLY},
- {5765, 153, IEEE80211_CH_PASSIVE_ONLY},
- {5785, 157, IEEE80211_CH_PASSIVE_ONLY},
- {5805, 161, IEEE80211_CH_PASSIVE_ONLY},
- {5825, 165, IEEE80211_CH_PASSIVE_ONLY}},
+ .a = {{5180, 36, LIBIPW_CH_PASSIVE_ONLY},
+ {5200, 40, LIBIPW_CH_PASSIVE_ONLY},
+ {5220, 44, LIBIPW_CH_PASSIVE_ONLY},
+ {5240, 48, LIBIPW_CH_PASSIVE_ONLY},
+ {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
+ {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
+ {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
+ {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
+ {5500, 100, LIBIPW_CH_PASSIVE_ONLY},
+ {5520, 104, LIBIPW_CH_PASSIVE_ONLY},
+ {5540, 108, LIBIPW_CH_PASSIVE_ONLY},
+ {5560, 112, LIBIPW_CH_PASSIVE_ONLY},
+ {5580, 116, LIBIPW_CH_PASSIVE_ONLY},
+ {5600, 120, LIBIPW_CH_PASSIVE_ONLY},
+ {5620, 124, LIBIPW_CH_PASSIVE_ONLY},
+ {5640, 128, LIBIPW_CH_PASSIVE_ONLY},
+ {5660, 132, LIBIPW_CH_PASSIVE_ONLY},
+ {5680, 136, LIBIPW_CH_PASSIVE_ONLY},
+ {5700, 140, LIBIPW_CH_PASSIVE_ONLY},
+ {5745, 149, LIBIPW_CH_PASSIVE_ONLY},
+ {5765, 153, LIBIPW_CH_PASSIVE_ONLY},
+ {5785, 157, LIBIPW_CH_PASSIVE_ONLY},
+ {5805, 161, LIBIPW_CH_PASSIVE_ONLY},
+ {5825, 165, LIBIPW_CH_PASSIVE_ONLY}},
},
{ /* Europe */
@@ -11223,19 +11220,19 @@ static const struct ieee80211_geo ipw_geos[] = {
{2442, 7}, {2447, 8}, {2452, 9},
{2457, 10}, {2462, 11}},
.a_channels = 13,
- .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY},
- {5200, 40, IEEE80211_CH_PASSIVE_ONLY},
- {5220, 44, IEEE80211_CH_PASSIVE_ONLY},
- {5240, 48, IEEE80211_CH_PASSIVE_ONLY},
- {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
- {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
- {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
- {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
- {5745, 149, IEEE80211_CH_PASSIVE_ONLY},
- {5765, 153, IEEE80211_CH_PASSIVE_ONLY},
- {5785, 157, IEEE80211_CH_PASSIVE_ONLY},
- {5805, 161, IEEE80211_CH_PASSIVE_ONLY},
- {5825, 165, IEEE80211_CH_PASSIVE_ONLY}},
+ .a = {{5180, 36, LIBIPW_CH_PASSIVE_ONLY},
+ {5200, 40, LIBIPW_CH_PASSIVE_ONLY},
+ {5220, 44, LIBIPW_CH_PASSIVE_ONLY},
+ {5240, 48, LIBIPW_CH_PASSIVE_ONLY},
+ {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
+ {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
+ {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
+ {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
+ {5745, 149, LIBIPW_CH_PASSIVE_ONLY},
+ {5765, 153, LIBIPW_CH_PASSIVE_ONLY},
+ {5785, 157, LIBIPW_CH_PASSIVE_ONLY},
+ {5805, 161, LIBIPW_CH_PASSIVE_ONLY},
+ {5825, 165, LIBIPW_CH_PASSIVE_ONLY}},
}
};
@@ -11246,7 +11243,7 @@ static int ipw_up(struct ipw_priv *priv)
/* Age scan list entries found before suspend */
if (priv->suspend_time) {
- ieee80211_networks_age(priv->ieee, priv->suspend_time);
+ libipw_networks_age(priv->ieee, priv->suspend_time);
priv->suspend_time = 0;
}
@@ -11291,7 +11288,7 @@ static int ipw_up(struct ipw_priv *priv)
priv->eeprom[EEPROM_COUNTRY_CODE + 2]);
j = 0;
}
- if (ieee80211_set_geo(priv->ieee, &ipw_geos[j])) {
+ if (libipw_set_geo(priv->ieee, &ipw_geos[j])) {
IPW_WARNING("Could not set geography.");
return 0;
}
@@ -11419,16 +11416,100 @@ static void ipw_bg_down(struct work_struct *work)
/* Called by register_netdev() */
static int ipw_net_init(struct net_device *dev)
{
- struct ipw_priv *priv = ieee80211_priv(dev);
+ int i, rc = 0;
+ struct ipw_priv *priv = libipw_priv(dev);
+ const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
+ struct wireless_dev *wdev = &priv->ieee->wdev;
mutex_lock(&priv->mutex);
if (ipw_up(priv)) {
- mutex_unlock(&priv->mutex);
- return -EIO;
+ rc = -EIO;
+ goto out;
+ }
+
+ memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
+
+ /* fill-out priv->ieee->bg_band */
+ if (geo->bg_channels) {
+ struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
+
+ bg_band->band = IEEE80211_BAND_2GHZ;
+ bg_band->n_channels = geo->bg_channels;
+ bg_band->channels =
+ kzalloc(geo->bg_channels *
+ sizeof(struct ieee80211_channel), GFP_KERNEL);
+ /* translate geo->bg to bg_band.channels */
+ for (i = 0; i < geo->bg_channels; i++) {
+ bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
+ bg_band->channels[i].center_freq = geo->bg[i].freq;
+ bg_band->channels[i].hw_value = geo->bg[i].channel;
+ bg_band->channels[i].max_power = geo->bg[i].max_power;
+ if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
+ bg_band->channels[i].flags |=
+ IEEE80211_CHAN_PASSIVE_SCAN;
+ if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
+ bg_band->channels[i].flags |=
+ IEEE80211_CHAN_NO_IBSS;
+ if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
+ bg_band->channels[i].flags |=
+ IEEE80211_CHAN_RADAR;
+ /* No equivalent for LIBIPW_CH_80211H_RULES,
+ LIBIPW_CH_UNIFORM_SPREADING, or
+ LIBIPW_CH_B_ONLY... */
+ }
+ /* point at bitrate info */
+ bg_band->bitrates = ipw2200_bg_rates;
+ bg_band->n_bitrates = ipw2200_num_bg_rates;
+
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band;
+ }
+
+ /* fill-out priv->ieee->a_band */
+ if (geo->a_channels) {
+ struct ieee80211_supported_band *a_band = &priv->ieee->a_band;
+
+ a_band->band = IEEE80211_BAND_5GHZ;
+ a_band->n_channels = geo->a_channels;
+ a_band->channels =
+ kzalloc(geo->a_channels *
+ sizeof(struct ieee80211_channel), GFP_KERNEL);
+ /* translate geo->bg to a_band.channels */
+ for (i = 0; i < geo->a_channels; i++) {
+ a_band->channels[i].band = IEEE80211_BAND_2GHZ;
+ a_band->channels[i].center_freq = geo->a[i].freq;
+ a_band->channels[i].hw_value = geo->a[i].channel;
+ a_band->channels[i].max_power = geo->a[i].max_power;
+ if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY)
+ a_band->channels[i].flags |=
+ IEEE80211_CHAN_PASSIVE_SCAN;
+ if (geo->a[i].flags & LIBIPW_CH_NO_IBSS)
+ a_band->channels[i].flags |=
+ IEEE80211_CHAN_NO_IBSS;
+ if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT)
+ a_band->channels[i].flags |=
+ IEEE80211_CHAN_RADAR;
+ /* No equivalent for LIBIPW_CH_80211H_RULES,
+ LIBIPW_CH_UNIFORM_SPREADING, or
+ LIBIPW_CH_B_ONLY... */
+ }
+ /* point at bitrate info */
+ a_band->bitrates = ipw2200_a_rates;
+ a_band->n_bitrates = ipw2200_num_a_rates;
+
+ wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = a_band;
+ }
+
+ set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
+
+ /* With that information in place, we can now register the wiphy... */
+ if (wiphy_register(wdev->wiphy)) {
+ rc = -EIO;
+ goto out;
}
+out:
mutex_unlock(&priv->mutex);
- return 0;
+ return rc;
}
/* PCI driver stuff */
@@ -11450,11 +11531,11 @@ static struct pci_device_id card_ids[] = {
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0},
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0},
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
- {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
- {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
- {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
+ {PCI_VDEVICE(INTEL, 0x104f), 0},
+ {PCI_VDEVICE(INTEL, 0x4220), 0}, /* BG */
+ {PCI_VDEVICE(INTEL, 0x4221), 0}, /* BG */
+ {PCI_VDEVICE(INTEL, 0x4223), 0}, /* ABG */
+ {PCI_VDEVICE(INTEL, 0x4224), 0}, /* ABG */
/* required last entry */
{0,}
@@ -11498,7 +11579,7 @@ static struct attribute_group ipw_attribute_group = {
#ifdef CONFIG_IPW2200_PROMISCUOUS
static int ipw_prom_open(struct net_device *dev)
{
- struct ipw_prom_priv *prom_priv = ieee80211_priv(dev);
+ struct ipw_prom_priv *prom_priv = libipw_priv(dev);
struct ipw_priv *priv = prom_priv->priv;
IPW_DEBUG_INFO("prom dev->open\n");
@@ -11518,7 +11599,7 @@ static int ipw_prom_open(struct net_device *dev)
static int ipw_prom_stop(struct net_device *dev)
{
- struct ipw_prom_priv *prom_priv = ieee80211_priv(dev);
+ struct ipw_prom_priv *prom_priv = libipw_priv(dev);
struct ipw_priv *priv = prom_priv->priv;
IPW_DEBUG_INFO("prom dev->stop\n");
@@ -11535,7 +11616,8 @@ static int ipw_prom_stop(struct net_device *dev)
return 0;
}
-static int ipw_prom_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t ipw_prom_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
IPW_DEBUG_INFO("prom dev->xmit\n");
dev_kfree_skb(skb);
@@ -11546,7 +11628,7 @@ static const struct net_device_ops ipw_prom_netdev_ops = {
.ndo_open = ipw_prom_open,
.ndo_stop = ipw_prom_stop,
.ndo_start_xmit = ipw_prom_hard_start_xmit,
- .ndo_change_mtu = ieee80211_change_mtu,
+ .ndo_change_mtu = libipw_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
@@ -11558,11 +11640,11 @@ static int ipw_prom_alloc(struct ipw_priv *priv)
if (priv->prom_net_dev)
return -EPERM;
- priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv));
+ priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv), 1);
if (priv->prom_net_dev == NULL)
return -ENOMEM;
- priv->prom_priv = ieee80211_priv(priv->prom_net_dev);
+ priv->prom_priv = libipw_priv(priv->prom_net_dev);
priv->prom_priv->ieee = netdev_priv(priv->prom_net_dev);
priv->prom_priv->priv = priv;
@@ -11577,7 +11659,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv)
rc = register_netdev(priv->prom_net_dev);
if (rc) {
- free_ieee80211(priv->prom_net_dev);
+ free_ieee80211(priv->prom_net_dev, 1);
priv->prom_net_dev = NULL;
return rc;
}
@@ -11591,7 +11673,7 @@ static void ipw_prom_free(struct ipw_priv *priv)
return;
unregister_netdev(priv->prom_net_dev);
- free_ieee80211(priv->prom_net_dev);
+ free_ieee80211(priv->prom_net_dev, 1);
priv->prom_net_dev = NULL;
}
@@ -11604,8 +11686,8 @@ static const struct net_device_ops ipw_netdev_ops = {
.ndo_stop = ipw_net_stop,
.ndo_set_multicast_list = ipw_net_set_multicast_list,
.ndo_set_mac_address = ipw_net_set_mac_address,
- .ndo_start_xmit = ieee80211_xmit,
- .ndo_change_mtu = ieee80211_change_mtu,
+ .ndo_start_xmit = libipw_xmit,
+ .ndo_change_mtu = libipw_change_mtu,
.ndo_validate_addr = eth_validate_addr,
};
@@ -11619,13 +11701,13 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
struct ipw_priv *priv;
int i;
- net_dev = alloc_ieee80211(sizeof(struct ipw_priv));
+ net_dev = alloc_ieee80211(sizeof(struct ipw_priv), 0);
if (net_dev == NULL) {
err = -ENOMEM;
goto out;
}
- priv = ieee80211_priv(net_dev);
+ priv = libipw_priv(net_dev);
priv->ieee = netdev_priv(net_dev);
priv->net_dev = net_dev;
@@ -11767,7 +11849,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
out_free_ieee80211:
- free_ieee80211(priv->net_dev);
+ free_ieee80211(priv->net_dev, 0);
out:
return err;
}
@@ -11834,7 +11916,7 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev)
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
- free_ieee80211(priv->net_dev);
+ free_ieee80211(priv->net_dev, 0);
free_firmware();
}
@@ -11963,13 +12045,13 @@ MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
module_param(auto_create, int, 0444);
MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
-module_param(led, int, 0444);
+module_param_named(led, led_support, int, 0444);
MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)");
module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
-module_param(channel, int, 0444);
+module_param_named(channel, default_channel, int, 0444);
MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
#ifdef CONFIG_IPW2200_PROMISCUOUS
@@ -11995,10 +12077,10 @@ MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value");
#endif /* CONFIG_IPW2200_QOS */
#ifdef CONFIG_IPW2200_MONITOR
-module_param(mode, int, 0444);
+module_param_named(mode, network_mode, int, 0444);
MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
#else
-module_param(mode, int, 0444);
+module_param_named(mode, network_mode, int, 0444);
MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)");
#endif
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h
index 05e8ccf01c5f..bf0eeb2e873a 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.h
+++ b/drivers/net/wireless/ipw2x00/ipw2200.h
@@ -19,7 +19,7 @@
file called LICENSE.
Contact Information:
- James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
******************************************************************************/
@@ -55,7 +55,7 @@
#include <linux/workqueue.h>
-#include "ieee80211.h"
+#include "libipw.h"
/* Authentication and Association States */
enum connection_manager_assoc_states {
@@ -365,8 +365,8 @@ enum connection_manager_assoc_states {
/* QoS sturctures */
struct ipw_qos_info {
int qos_enable;
- struct ieee80211_qos_parameters *def_qos_parm_OFDM;
- struct ieee80211_qos_parameters *def_qos_parm_CCK;
+ struct libipw_qos_parameters *def_qos_parm_OFDM;
+ struct libipw_qos_parameters *def_qos_parm_CCK;
u32 burst_duration_CCK;
u32 burst_duration_OFDM;
u16 qos_no_ack_mask;
@@ -534,7 +534,7 @@ typedef void destructor_func(const void *);
struct clx2_tx_queue {
struct clx2_queue q;
struct tfd_frame *bd;
- struct ieee80211_txb **txb;
+ struct libipw_txb **txb;
};
/*
@@ -1144,7 +1144,7 @@ enum ipw_prom_filter {
struct ipw_priv;
struct ipw_prom_priv {
struct ipw_priv *priv;
- struct ieee80211_device *ieee;
+ struct libipw_device *ieee;
enum ipw_prom_filter filter;
int tx_packets;
int rx_packets;
@@ -1175,7 +1175,7 @@ struct ipw_rt_hdr {
struct ipw_priv {
/* ieee device used by generic ieee processing code */
- struct ieee80211_device *ieee;
+ struct libipw_device *ieee;
spinlock_t lock;
spinlock_t irq_lock;
@@ -1222,7 +1222,7 @@ struct ipw_priv {
u32 roaming_threshold;
struct ipw_associate assoc_request;
- struct ieee80211_network *assoc_network;
+ struct libipw_network *assoc_network;
unsigned long ts_scan_abort;
struct ipw_supported_rates rates;
diff --git a/drivers/net/wireless/ipw2x00/ieee80211.h b/drivers/net/wireless/ipw2x00/libipw.h
index 70755c1336d5..bf45391172f3 100644
--- a/drivers/net/wireless/ipw2x00/ieee80211.h
+++ b/drivers/net/wireless/ipw2x00/libipw.h
@@ -20,21 +20,22 @@
*
* API Version History
* 1.0.x -- Initial version
- * 1.1.x -- Added radiotap, QoS, TIM, ieee80211_geo APIs,
+ * 1.1.x -- Added radiotap, QoS, TIM, libipw_geo APIs,
* various structure changes, and crypto API init method
*/
-#ifndef IEEE80211_H
-#define IEEE80211_H
+#ifndef LIBIPW_H
+#define LIBIPW_H
#include <linux/if_ether.h> /* ETH_ALEN */
#include <linux/kernel.h> /* ARRAY_SIZE */
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/lib80211.h>
+#include <net/cfg80211.h>
-#define IEEE80211_VERSION "git-1.1.13"
+#define LIBIPW_VERSION "git-1.1.13"
-#define IEEE80211_DATA_LEN 2304
+#define LIBIPW_DATA_LEN 2304
/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
6.2.1.1.2.
@@ -43,35 +44,35 @@
represents the 2304 bytes of real data, plus a possible 8 bytes of
WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
-#define IEEE80211_1ADDR_LEN 10
-#define IEEE80211_2ADDR_LEN 16
-#define IEEE80211_3ADDR_LEN 24
-#define IEEE80211_4ADDR_LEN 30
-#define IEEE80211_FCS_LEN 4
-#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)
-#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+#define LIBIPW_1ADDR_LEN 10
+#define LIBIPW_2ADDR_LEN 16
+#define LIBIPW_3ADDR_LEN 24
+#define LIBIPW_4ADDR_LEN 30
+#define LIBIPW_FCS_LEN 4
+#define LIBIPW_HLEN (LIBIPW_4ADDR_LEN)
+#define LIBIPW_FRAME_LEN (LIBIPW_DATA_LEN + LIBIPW_HLEN)
#define MIN_FRAG_THRESHOLD 256U
#define MAX_FRAG_THRESHOLD 2346U
/* QOS control */
-#define IEEE80211_QCTL_TID 0x000F
+#define LIBIPW_QCTL_TID 0x000F
/* debug macros */
#ifdef CONFIG_LIBIPW_DEBUG
-extern u32 ieee80211_debug_level;
-#define IEEE80211_DEBUG(level, fmt, args...) \
-do { if (ieee80211_debug_level & (level)) \
+extern u32 libipw_debug_level;
+#define LIBIPW_DEBUG(level, fmt, args...) \
+do { if (libipw_debug_level & (level)) \
printk(KERN_DEBUG "ieee80211: %c %s " fmt, \
in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
-static inline bool ieee80211_ratelimit_debug(u32 level)
+static inline bool libipw_ratelimit_debug(u32 level)
{
- return (ieee80211_debug_level & level) && net_ratelimit();
+ return (libipw_debug_level & level) && net_ratelimit();
}
#else
-#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
-static inline bool ieee80211_ratelimit_debug(u32 level)
+#define LIBIPW_DEBUG(level, fmt, args...) do {} while (0)
+static inline bool libipw_ratelimit_debug(u32 level)
{
return false;
}
@@ -83,51 +84,51 @@ static inline bool ieee80211_ratelimit_debug(u32 level)
* If you are defining a new debug classification, simply add it to the #define
* list here in the form of:
*
- * #define IEEE80211_DL_xxxx VALUE
+ * #define LIBIPW_DL_xxxx VALUE
*
* shifting value to the left one bit from the previous entry. xxxx should be
* the name of the classification (for example, WEP)
*
- * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your
- * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want
+ * You then need to either add a LIBIPW_xxxx_DEBUG() macro definition for your
+ * classification, or use LIBIPW_DEBUG(LIBIPW_DL_xxxx, ...) whenever you want
* to send output to that classification.
*
* To add your debug level to the list of levels seen when you perform
*
* % cat /proc/net/ieee80211/debug_level
*
- * you simply need to add your entry to the ieee80211_debug_level array.
+ * you simply need to add your entry to the libipw_debug_level array.
*
* If you do not see debug_level in /proc/net/ieee80211 then you do not have
* CONFIG_LIBIPW_DEBUG defined in your kernel configuration
*
*/
-#define IEEE80211_DL_INFO (1<<0)
-#define IEEE80211_DL_WX (1<<1)
-#define IEEE80211_DL_SCAN (1<<2)
-#define IEEE80211_DL_STATE (1<<3)
-#define IEEE80211_DL_MGMT (1<<4)
-#define IEEE80211_DL_FRAG (1<<5)
-#define IEEE80211_DL_DROP (1<<7)
-
-#define IEEE80211_DL_TX (1<<8)
-#define IEEE80211_DL_RX (1<<9)
-#define IEEE80211_DL_QOS (1<<31)
-
-#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a)
-#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a)
-#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a)
-
-#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a)
-#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a)
-#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a)
-#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a)
-#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a)
-#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a)
-#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a)
-#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a)
-#define IEEE80211_DEBUG_QOS(f, a...) IEEE80211_DEBUG(IEEE80211_DL_QOS, f, ## a)
+#define LIBIPW_DL_INFO (1<<0)
+#define LIBIPW_DL_WX (1<<1)
+#define LIBIPW_DL_SCAN (1<<2)
+#define LIBIPW_DL_STATE (1<<3)
+#define LIBIPW_DL_MGMT (1<<4)
+#define LIBIPW_DL_FRAG (1<<5)
+#define LIBIPW_DL_DROP (1<<7)
+
+#define LIBIPW_DL_TX (1<<8)
+#define LIBIPW_DL_RX (1<<9)
+#define LIBIPW_DL_QOS (1<<31)
+
+#define LIBIPW_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a)
+#define LIBIPW_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a)
+#define LIBIPW_DEBUG_INFO(f, a...) LIBIPW_DEBUG(LIBIPW_DL_INFO, f, ## a)
+
+#define LIBIPW_DEBUG_WX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_WX, f, ## a)
+#define LIBIPW_DEBUG_SCAN(f, a...) LIBIPW_DEBUG(LIBIPW_DL_SCAN, f, ## a)
+#define LIBIPW_DEBUG_STATE(f, a...) LIBIPW_DEBUG(LIBIPW_DL_STATE, f, ## a)
+#define LIBIPW_DEBUG_MGMT(f, a...) LIBIPW_DEBUG(LIBIPW_DL_MGMT, f, ## a)
+#define LIBIPW_DEBUG_FRAG(f, a...) LIBIPW_DEBUG(LIBIPW_DL_FRAG, f, ## a)
+#define LIBIPW_DEBUG_DROP(f, a...) LIBIPW_DEBUG(LIBIPW_DL_DROP, f, ## a)
+#define LIBIPW_DEBUG_TX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_TX, f, ## a)
+#define LIBIPW_DEBUG_RX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_RX, f, ## a)
+#define LIBIPW_DEBUG_QOS(f, a...) LIBIPW_DEBUG(LIBIPW_DL_QOS, f, ## a)
#include <linux/netdevice.h>
#include <linux/if_arp.h> /* ARPHRD_ETHER */
@@ -146,7 +147,7 @@ static inline bool ieee80211_ratelimit_debug(u32 level)
#define P80211_OUI_LEN 3
-struct ieee80211_snap_hdr {
+struct libipw_snap_hdr {
u8 dsap; /* always 0xAA */
u8 ssap; /* always 0xAA */
@@ -155,7 +156,7 @@ struct ieee80211_snap_hdr {
} __attribute__ ((packed));
-#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+#define SNAP_SIZE sizeof(struct libipw_snap_hdr)
#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS)
#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
@@ -164,74 +165,74 @@ struct ieee80211_snap_hdr {
#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-#define IEEE80211_STATMASK_SIGNAL (1<<0)
-#define IEEE80211_STATMASK_RSSI (1<<1)
-#define IEEE80211_STATMASK_NOISE (1<<2)
-#define IEEE80211_STATMASK_RATE (1<<3)
-#define IEEE80211_STATMASK_WEMASK 0x7
-
-#define IEEE80211_CCK_MODULATION (1<<0)
-#define IEEE80211_OFDM_MODULATION (1<<1)
-
-#define IEEE80211_24GHZ_BAND (1<<0)
-#define IEEE80211_52GHZ_BAND (1<<1)
-
-#define IEEE80211_CCK_RATE_1MB 0x02
-#define IEEE80211_CCK_RATE_2MB 0x04
-#define IEEE80211_CCK_RATE_5MB 0x0B
-#define IEEE80211_CCK_RATE_11MB 0x16
-#define IEEE80211_OFDM_RATE_6MB 0x0C
-#define IEEE80211_OFDM_RATE_9MB 0x12
-#define IEEE80211_OFDM_RATE_12MB 0x18
-#define IEEE80211_OFDM_RATE_18MB 0x24
-#define IEEE80211_OFDM_RATE_24MB 0x30
-#define IEEE80211_OFDM_RATE_36MB 0x48
-#define IEEE80211_OFDM_RATE_48MB 0x60
-#define IEEE80211_OFDM_RATE_54MB 0x6C
-#define IEEE80211_BASIC_RATE_MASK 0x80
-
-#define IEEE80211_CCK_RATE_1MB_MASK (1<<0)
-#define IEEE80211_CCK_RATE_2MB_MASK (1<<1)
-#define IEEE80211_CCK_RATE_5MB_MASK (1<<2)
-#define IEEE80211_CCK_RATE_11MB_MASK (1<<3)
-#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4)
-#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5)
-#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6)
-#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7)
-#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8)
-#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9)
-#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10)
-#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11)
-
-#define IEEE80211_CCK_RATES_MASK 0x0000000F
-#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \
- IEEE80211_CCK_RATE_2MB_MASK)
-#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \
- IEEE80211_CCK_RATE_5MB_MASK | \
- IEEE80211_CCK_RATE_11MB_MASK)
-
-#define IEEE80211_OFDM_RATES_MASK 0x00000FF0
-#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \
- IEEE80211_OFDM_RATE_12MB_MASK | \
- IEEE80211_OFDM_RATE_24MB_MASK)
-#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \
- IEEE80211_OFDM_RATE_9MB_MASK | \
- IEEE80211_OFDM_RATE_18MB_MASK | \
- IEEE80211_OFDM_RATE_36MB_MASK | \
- IEEE80211_OFDM_RATE_48MB_MASK | \
- IEEE80211_OFDM_RATE_54MB_MASK)
-#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \
- IEEE80211_CCK_DEFAULT_RATES_MASK)
-
-#define IEEE80211_NUM_OFDM_RATES 8
-#define IEEE80211_NUM_CCK_RATES 4
-#define IEEE80211_OFDM_SHIFT_MASK_A 4
+#define LIBIPW_STATMASK_SIGNAL (1<<0)
+#define LIBIPW_STATMASK_RSSI (1<<1)
+#define LIBIPW_STATMASK_NOISE (1<<2)
+#define LIBIPW_STATMASK_RATE (1<<3)
+#define LIBIPW_STATMASK_WEMASK 0x7
+
+#define LIBIPW_CCK_MODULATION (1<<0)
+#define LIBIPW_OFDM_MODULATION (1<<1)
+
+#define LIBIPW_24GHZ_BAND (1<<0)
+#define LIBIPW_52GHZ_BAND (1<<1)
+
+#define LIBIPW_CCK_RATE_1MB 0x02
+#define LIBIPW_CCK_RATE_2MB 0x04
+#define LIBIPW_CCK_RATE_5MB 0x0B
+#define LIBIPW_CCK_RATE_11MB 0x16
+#define LIBIPW_OFDM_RATE_6MB 0x0C
+#define LIBIPW_OFDM_RATE_9MB 0x12
+#define LIBIPW_OFDM_RATE_12MB 0x18
+#define LIBIPW_OFDM_RATE_18MB 0x24
+#define LIBIPW_OFDM_RATE_24MB 0x30
+#define LIBIPW_OFDM_RATE_36MB 0x48
+#define LIBIPW_OFDM_RATE_48MB 0x60
+#define LIBIPW_OFDM_RATE_54MB 0x6C
+#define LIBIPW_BASIC_RATE_MASK 0x80
+
+#define LIBIPW_CCK_RATE_1MB_MASK (1<<0)
+#define LIBIPW_CCK_RATE_2MB_MASK (1<<1)
+#define LIBIPW_CCK_RATE_5MB_MASK (1<<2)
+#define LIBIPW_CCK_RATE_11MB_MASK (1<<3)
+#define LIBIPW_OFDM_RATE_6MB_MASK (1<<4)
+#define LIBIPW_OFDM_RATE_9MB_MASK (1<<5)
+#define LIBIPW_OFDM_RATE_12MB_MASK (1<<6)
+#define LIBIPW_OFDM_RATE_18MB_MASK (1<<7)
+#define LIBIPW_OFDM_RATE_24MB_MASK (1<<8)
+#define LIBIPW_OFDM_RATE_36MB_MASK (1<<9)
+#define LIBIPW_OFDM_RATE_48MB_MASK (1<<10)
+#define LIBIPW_OFDM_RATE_54MB_MASK (1<<11)
+
+#define LIBIPW_CCK_RATES_MASK 0x0000000F
+#define LIBIPW_CCK_BASIC_RATES_MASK (LIBIPW_CCK_RATE_1MB_MASK | \
+ LIBIPW_CCK_RATE_2MB_MASK)
+#define LIBIPW_CCK_DEFAULT_RATES_MASK (LIBIPW_CCK_BASIC_RATES_MASK | \
+ LIBIPW_CCK_RATE_5MB_MASK | \
+ LIBIPW_CCK_RATE_11MB_MASK)
+
+#define LIBIPW_OFDM_RATES_MASK 0x00000FF0
+#define LIBIPW_OFDM_BASIC_RATES_MASK (LIBIPW_OFDM_RATE_6MB_MASK | \
+ LIBIPW_OFDM_RATE_12MB_MASK | \
+ LIBIPW_OFDM_RATE_24MB_MASK)
+#define LIBIPW_OFDM_DEFAULT_RATES_MASK (LIBIPW_OFDM_BASIC_RATES_MASK | \
+ LIBIPW_OFDM_RATE_9MB_MASK | \
+ LIBIPW_OFDM_RATE_18MB_MASK | \
+ LIBIPW_OFDM_RATE_36MB_MASK | \
+ LIBIPW_OFDM_RATE_48MB_MASK | \
+ LIBIPW_OFDM_RATE_54MB_MASK)
+#define LIBIPW_DEFAULT_RATES_MASK (LIBIPW_OFDM_DEFAULT_RATES_MASK | \
+ LIBIPW_CCK_DEFAULT_RATES_MASK)
+
+#define LIBIPW_NUM_OFDM_RATES 8
+#define LIBIPW_NUM_CCK_RATES 4
+#define LIBIPW_OFDM_SHIFT_MASK_A 4
/* NOTE: This data is for statistical purposes; not all hardware provides this
* information for frames received.
- * For ieee80211_rx_mgt, you need to set at least the 'len' parameter.
+ * For libipw_rx_mgt, you need to set at least the 'len' parameter.
*/
-struct ieee80211_rx_stats {
+struct libipw_rx_stats {
u32 mac_time;
s8 rssi;
u8 signal;
@@ -250,9 +251,9 @@ struct ieee80211_rx_stats {
* three fragmented frames. This define can be increased to support more
* concurrent frames, but it should be noted that each entry can consume about
* 2 kB of RAM and increasing cache size will slow down frame reassembly. */
-#define IEEE80211_FRAG_CACHE_LEN 4
+#define LIBIPW_FRAG_CACHE_LEN 4
-struct ieee80211_frag_entry {
+struct libipw_frag_entry {
unsigned long first_frag_time;
unsigned int seq;
unsigned int last_frag;
@@ -261,7 +262,7 @@ struct ieee80211_frag_entry {
u8 dst_addr[ETH_ALEN];
};
-struct ieee80211_stats {
+struct libipw_stats {
unsigned int tx_unicast_frames;
unsigned int tx_multicast_frames;
unsigned int tx_fragments;
@@ -285,7 +286,7 @@ struct ieee80211_stats {
unsigned int rx_message_in_bad_msg_fragments;
};
-struct ieee80211_device;
+struct libipw_device;
#define SEC_KEY_1 (1<<0)
#define SEC_KEY_2 (1<<1)
@@ -314,7 +315,7 @@ struct ieee80211_device;
#define SCM_KEY_LEN 32
#define SCM_TEMPORAL_KEY_LENGTH 16
-struct ieee80211_security {
+struct libipw_security {
u16 active_key:2, enabled:1, unicast_uses_group:1, encrypt:1;
u8 auth_mode;
u8 encode_alg[WEP_KEYS];
@@ -341,14 +342,14 @@ Total: 28-2340 bytes
#define BEACON_PROBE_SSID_ID_POSITION 12
-struct ieee80211_hdr_1addr {
+struct libipw_hdr_1addr {
__le16 frame_ctl;
__le16 duration_id;
u8 addr1[ETH_ALEN];
u8 payload[0];
} __attribute__ ((packed));
-struct ieee80211_hdr_2addr {
+struct libipw_hdr_2addr {
__le16 frame_ctl;
__le16 duration_id;
u8 addr1[ETH_ALEN];
@@ -356,7 +357,7 @@ struct ieee80211_hdr_2addr {
u8 payload[0];
} __attribute__ ((packed));
-struct ieee80211_hdr_3addr {
+struct libipw_hdr_3addr {
__le16 frame_ctl;
__le16 duration_id;
u8 addr1[ETH_ALEN];
@@ -366,7 +367,7 @@ struct ieee80211_hdr_3addr {
u8 payload[0];
} __attribute__ ((packed));
-struct ieee80211_hdr_4addr {
+struct libipw_hdr_4addr {
__le16 frame_ctl;
__le16 duration_id;
u8 addr1[ETH_ALEN];
@@ -377,7 +378,7 @@ struct ieee80211_hdr_4addr {
u8 payload[0];
} __attribute__ ((packed));
-struct ieee80211_hdr_3addrqos {
+struct libipw_hdr_3addrqos {
__le16 frame_ctl;
__le16 duration_id;
u8 addr1[ETH_ALEN];
@@ -388,7 +389,7 @@ struct ieee80211_hdr_3addrqos {
__le16 qos_ctl;
} __attribute__ ((packed));
-struct ieee80211_info_element {
+struct libipw_info_element {
u8 id;
u8 len;
u8 data[0];
@@ -411,16 +412,16 @@ struct ieee80211_info_element {
u16 status;
*/
-struct ieee80211_auth {
- struct ieee80211_hdr_3addr header;
+struct libipw_auth {
+ struct libipw_hdr_3addr header;
__le16 algorithm;
__le16 transaction;
__le16 status;
/* challenge */
- struct ieee80211_info_element info_element[0];
+ struct libipw_info_element info_element[0];
} __attribute__ ((packed));
-struct ieee80211_channel_switch {
+struct libipw_channel_switch {
u8 id;
u8 len;
u8 mode;
@@ -428,73 +429,73 @@ struct ieee80211_channel_switch {
u8 count;
} __attribute__ ((packed));
-struct ieee80211_action {
- struct ieee80211_hdr_3addr header;
+struct libipw_action {
+ struct libipw_hdr_3addr header;
u8 category;
u8 action;
union {
- struct ieee80211_action_exchange {
+ struct libipw_action_exchange {
u8 token;
- struct ieee80211_info_element info_element[0];
+ struct libipw_info_element info_element[0];
} exchange;
- struct ieee80211_channel_switch channel_switch;
+ struct libipw_channel_switch channel_switch;
} format;
} __attribute__ ((packed));
-struct ieee80211_disassoc {
- struct ieee80211_hdr_3addr header;
+struct libipw_disassoc {
+ struct libipw_hdr_3addr header;
__le16 reason;
} __attribute__ ((packed));
/* Alias deauth for disassoc */
-#define ieee80211_deauth ieee80211_disassoc
+#define libipw_deauth libipw_disassoc
-struct ieee80211_probe_request {
- struct ieee80211_hdr_3addr header;
+struct libipw_probe_request {
+ struct libipw_hdr_3addr header;
/* SSID, supported rates */
- struct ieee80211_info_element info_element[0];
+ struct libipw_info_element info_element[0];
} __attribute__ ((packed));
-struct ieee80211_probe_response {
- struct ieee80211_hdr_3addr header;
+struct libipw_probe_response {
+ struct libipw_hdr_3addr header;
__le32 time_stamp[2];
__le16 beacon_interval;
__le16 capability;
/* SSID, supported rates, FH params, DS params,
* CF params, IBSS params, TIM (if beacon), RSN */
- struct ieee80211_info_element info_element[0];
+ struct libipw_info_element info_element[0];
} __attribute__ ((packed));
/* Alias beacon for probe_response */
-#define ieee80211_beacon ieee80211_probe_response
+#define libipw_beacon libipw_probe_response
-struct ieee80211_assoc_request {
- struct ieee80211_hdr_3addr header;
+struct libipw_assoc_request {
+ struct libipw_hdr_3addr header;
__le16 capability;
__le16 listen_interval;
/* SSID, supported rates, RSN */
- struct ieee80211_info_element info_element[0];
+ struct libipw_info_element info_element[0];
} __attribute__ ((packed));
-struct ieee80211_reassoc_request {
- struct ieee80211_hdr_3addr header;
+struct libipw_reassoc_request {
+ struct libipw_hdr_3addr header;
__le16 capability;
__le16 listen_interval;
u8 current_ap[ETH_ALEN];
- struct ieee80211_info_element info_element[0];
+ struct libipw_info_element info_element[0];
} __attribute__ ((packed));
-struct ieee80211_assoc_response {
- struct ieee80211_hdr_3addr header;
+struct libipw_assoc_response {
+ struct libipw_hdr_3addr header;
__le16 capability;
__le16 status;
__le16 aid;
/* supported rates */
- struct ieee80211_info_element info_element[0];
+ struct libipw_info_element info_element[0];
} __attribute__ ((packed));
-struct ieee80211_txb {
+struct libipw_txb {
u8 nr_frags;
u8 encrypted;
u8 rts_included;
@@ -546,7 +547,7 @@ struct ieee80211_txb {
#define QOS_VERSION_1 1
#define QOS_AIFSN_MIN_VALUE 2
-struct ieee80211_qos_information_element {
+struct libipw_qos_information_element {
u8 elementID;
u8 length;
u8 qui[QOS_OUI_LEN];
@@ -556,19 +557,19 @@ struct ieee80211_qos_information_element {
u8 ac_info;
} __attribute__ ((packed));
-struct ieee80211_qos_ac_parameter {
+struct libipw_qos_ac_parameter {
u8 aci_aifsn;
u8 ecw_min_max;
__le16 tx_op_limit;
} __attribute__ ((packed));
-struct ieee80211_qos_parameter_info {
- struct ieee80211_qos_information_element info_element;
+struct libipw_qos_parameter_info {
+ struct libipw_qos_information_element info_element;
u8 reserved;
- struct ieee80211_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM];
+ struct libipw_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM];
} __attribute__ ((packed));
-struct ieee80211_qos_parameters {
+struct libipw_qos_parameters {
__le16 cw_min[QOS_QUEUE_NUM];
__le16 cw_max[QOS_QUEUE_NUM];
u8 aifs[QOS_QUEUE_NUM];
@@ -576,107 +577,107 @@ struct ieee80211_qos_parameters {
__le16 tx_op_limit[QOS_QUEUE_NUM];
} __attribute__ ((packed));
-struct ieee80211_qos_data {
- struct ieee80211_qos_parameters parameters;
+struct libipw_qos_data {
+ struct libipw_qos_parameters parameters;
int active;
int supported;
u8 param_count;
u8 old_param_count;
};
-struct ieee80211_tim_parameters {
+struct libipw_tim_parameters {
u8 tim_count;
u8 tim_period;
} __attribute__ ((packed));
/*******************************************************/
-enum { /* ieee80211_basic_report.map */
- IEEE80211_BASIC_MAP_BSS = (1 << 0),
- IEEE80211_BASIC_MAP_OFDM = (1 << 1),
- IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2),
- IEEE80211_BASIC_MAP_RADAR = (1 << 3),
- IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4),
+enum { /* libipw_basic_report.map */
+ LIBIPW_BASIC_MAP_BSS = (1 << 0),
+ LIBIPW_BASIC_MAP_OFDM = (1 << 1),
+ LIBIPW_BASIC_MAP_UNIDENTIFIED = (1 << 2),
+ LIBIPW_BASIC_MAP_RADAR = (1 << 3),
+ LIBIPW_BASIC_MAP_UNMEASURED = (1 << 4),
/* Bits 5-7 are reserved */
};
-struct ieee80211_basic_report {
+struct libipw_basic_report {
u8 channel;
__le64 start_time;
__le16 duration;
u8 map;
} __attribute__ ((packed));
-enum { /* ieee80211_measurement_request.mode */
+enum { /* libipw_measurement_request.mode */
/* Bit 0 is reserved */
- IEEE80211_MEASUREMENT_ENABLE = (1 << 1),
- IEEE80211_MEASUREMENT_REQUEST = (1 << 2),
- IEEE80211_MEASUREMENT_REPORT = (1 << 3),
+ LIBIPW_MEASUREMENT_ENABLE = (1 << 1),
+ LIBIPW_MEASUREMENT_REQUEST = (1 << 2),
+ LIBIPW_MEASUREMENT_REPORT = (1 << 3),
/* Bits 4-7 are reserved */
};
enum {
- IEEE80211_REPORT_BASIC = 0, /* required */
- IEEE80211_REPORT_CCA = 1, /* optional */
- IEEE80211_REPORT_RPI = 2, /* optional */
+ LIBIPW_REPORT_BASIC = 0, /* required */
+ LIBIPW_REPORT_CCA = 1, /* optional */
+ LIBIPW_REPORT_RPI = 2, /* optional */
/* 3-255 reserved */
};
-struct ieee80211_measurement_params {
+struct libipw_measurement_params {
u8 channel;
__le64 start_time;
__le16 duration;
} __attribute__ ((packed));
-struct ieee80211_measurement_request {
- struct ieee80211_info_element ie;
+struct libipw_measurement_request {
+ struct libipw_info_element ie;
u8 token;
u8 mode;
u8 type;
- struct ieee80211_measurement_params params[0];
+ struct libipw_measurement_params params[0];
} __attribute__ ((packed));
-struct ieee80211_measurement_report {
- struct ieee80211_info_element ie;
+struct libipw_measurement_report {
+ struct libipw_info_element ie;
u8 token;
u8 mode;
u8 type;
union {
- struct ieee80211_basic_report basic[0];
+ struct libipw_basic_report basic[0];
} u;
} __attribute__ ((packed));
-struct ieee80211_tpc_report {
+struct libipw_tpc_report {
u8 transmit_power;
u8 link_margin;
} __attribute__ ((packed));
-struct ieee80211_channel_map {
+struct libipw_channel_map {
u8 channel;
u8 map;
} __attribute__ ((packed));
-struct ieee80211_ibss_dfs {
- struct ieee80211_info_element ie;
+struct libipw_ibss_dfs {
+ struct libipw_info_element ie;
u8 owner[ETH_ALEN];
u8 recovery_interval;
- struct ieee80211_channel_map channel_map[0];
+ struct libipw_channel_map channel_map[0];
};
-struct ieee80211_csa {
+struct libipw_csa {
u8 mode;
u8 channel;
u8 count;
} __attribute__ ((packed));
-struct ieee80211_quiet {
+struct libipw_quiet {
u8 count;
u8 period;
u8 duration;
u8 offset;
} __attribute__ ((packed));
-struct ieee80211_network {
+struct libipw_network {
/* These entries are used to identify a unique network */
u8 bssid[ETH_ALEN];
u8 channel;
@@ -684,10 +685,10 @@ struct ieee80211_network {
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
- struct ieee80211_qos_data qos_data;
+ struct libipw_qos_data qos_data;
/* These are network statistics */
- struct ieee80211_rx_stats stats;
+ struct libipw_rx_stats stats;
u16 capability;
u8 rates[MAX_RATES_LENGTH];
u8 rates_len;
@@ -706,7 +707,7 @@ struct ieee80211_network {
size_t wpa_ie_len;
u8 rsn_ie[MAX_WPA_IE_LEN];
size_t rsn_ie_len;
- struct ieee80211_tim_parameters tim;
+ struct libipw_tim_parameters tim;
/* 802.11h info */
@@ -714,86 +715,89 @@ struct ieee80211_network {
u8 power_constraint;
/* TPC Report - mandatory if spctrm mgmt required */
- struct ieee80211_tpc_report tpc_report;
+ struct libipw_tpc_report tpc_report;
/* IBSS DFS - mandatory if spctrm mgmt required and IBSS
* NOTE: This is variable length and so must be allocated dynamically */
- struct ieee80211_ibss_dfs *ibss_dfs;
+ struct libipw_ibss_dfs *ibss_dfs;
/* Channel Switch Announcement - optional if spctrm mgmt required */
- struct ieee80211_csa csa;
+ struct libipw_csa csa;
/* Quiet - optional if spctrm mgmt required */
- struct ieee80211_quiet quiet;
+ struct libipw_quiet quiet;
struct list_head list;
};
-enum ieee80211_state {
- IEEE80211_UNINITIALIZED = 0,
- IEEE80211_INITIALIZED,
- IEEE80211_ASSOCIATING,
- IEEE80211_ASSOCIATED,
- IEEE80211_AUTHENTICATING,
- IEEE80211_AUTHENTICATED,
- IEEE80211_SHUTDOWN
+enum libipw_state {
+ LIBIPW_UNINITIALIZED = 0,
+ LIBIPW_INITIALIZED,
+ LIBIPW_ASSOCIATING,
+ LIBIPW_ASSOCIATED,
+ LIBIPW_AUTHENTICATING,
+ LIBIPW_AUTHENTICATED,
+ LIBIPW_SHUTDOWN
};
#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
#define DEFAULT_FTS 2346
-#define CFG_IEEE80211_RESERVE_FCS (1<<0)
-#define CFG_IEEE80211_COMPUTE_FCS (1<<1)
-#define CFG_IEEE80211_RTS (1<<2)
+#define CFG_LIBIPW_RESERVE_FCS (1<<0)
+#define CFG_LIBIPW_COMPUTE_FCS (1<<1)
+#define CFG_LIBIPW_RTS (1<<2)
-#define IEEE80211_24GHZ_MIN_CHANNEL 1
-#define IEEE80211_24GHZ_MAX_CHANNEL 14
-#define IEEE80211_24GHZ_CHANNELS (IEEE80211_24GHZ_MAX_CHANNEL - \
- IEEE80211_24GHZ_MIN_CHANNEL + 1)
+#define LIBIPW_24GHZ_MIN_CHANNEL 1
+#define LIBIPW_24GHZ_MAX_CHANNEL 14
+#define LIBIPW_24GHZ_CHANNELS (LIBIPW_24GHZ_MAX_CHANNEL - \
+ LIBIPW_24GHZ_MIN_CHANNEL + 1)
-#define IEEE80211_52GHZ_MIN_CHANNEL 34
-#define IEEE80211_52GHZ_MAX_CHANNEL 165
-#define IEEE80211_52GHZ_CHANNELS (IEEE80211_52GHZ_MAX_CHANNEL - \
- IEEE80211_52GHZ_MIN_CHANNEL + 1)
+#define LIBIPW_52GHZ_MIN_CHANNEL 34
+#define LIBIPW_52GHZ_MAX_CHANNEL 165
+#define LIBIPW_52GHZ_CHANNELS (LIBIPW_52GHZ_MAX_CHANNEL - \
+ LIBIPW_52GHZ_MIN_CHANNEL + 1)
enum {
- IEEE80211_CH_PASSIVE_ONLY = (1 << 0),
- IEEE80211_CH_80211H_RULES = (1 << 1),
- IEEE80211_CH_B_ONLY = (1 << 2),
- IEEE80211_CH_NO_IBSS = (1 << 3),
- IEEE80211_CH_UNIFORM_SPREADING = (1 << 4),
- IEEE80211_CH_RADAR_DETECT = (1 << 5),
- IEEE80211_CH_INVALID = (1 << 6),
+ LIBIPW_CH_PASSIVE_ONLY = (1 << 0),
+ LIBIPW_CH_80211H_RULES = (1 << 1),
+ LIBIPW_CH_B_ONLY = (1 << 2),
+ LIBIPW_CH_NO_IBSS = (1 << 3),
+ LIBIPW_CH_UNIFORM_SPREADING = (1 << 4),
+ LIBIPW_CH_RADAR_DETECT = (1 << 5),
+ LIBIPW_CH_INVALID = (1 << 6),
};
-struct ieee80211_channel {
+struct libipw_channel {
u32 freq; /* in MHz */
u8 channel;
u8 flags;
u8 max_power; /* in dBm */
};
-struct ieee80211_geo {
+struct libipw_geo {
u8 name[4];
u8 bg_channels;
u8 a_channels;
- struct ieee80211_channel bg[IEEE80211_24GHZ_CHANNELS];
- struct ieee80211_channel a[IEEE80211_52GHZ_CHANNELS];
+ struct libipw_channel bg[LIBIPW_24GHZ_CHANNELS];
+ struct libipw_channel a[LIBIPW_52GHZ_CHANNELS];
};
-struct ieee80211_device {
+struct libipw_device {
struct net_device *dev;
- struct ieee80211_security sec;
+ struct wireless_dev wdev;
+ struct libipw_security sec;
/* Bookkeeping structures */
- struct ieee80211_stats ieee_stats;
+ struct libipw_stats ieee_stats;
- struct ieee80211_geo geo;
+ struct libipw_geo geo;
+ struct ieee80211_supported_band bg_band;
+ struct ieee80211_supported_band a_band;
/* Probe / Beacon management */
struct list_head network_free_list;
struct list_head network_list;
- struct ieee80211_network *networks;
+ struct libipw_network *networks;
int scans;
int scan_age;
@@ -840,7 +844,7 @@ struct ieee80211_device {
* with RX of broad/multicast frames */
/* Fragmentation structures */
- struct ieee80211_frag_entry frag_cache[IEEE80211_FRAG_CACHE_LEN];
+ struct libipw_frag_entry frag_cache[LIBIPW_FRAG_CACHE_LEN];
unsigned int frag_next_idx;
u16 fts; /* Fragmentation Threshold */
u16 rts; /* RTS threshold */
@@ -848,7 +852,7 @@ struct ieee80211_device {
/* Association info */
u8 bssid[ETH_ALEN];
- enum ieee80211_state state;
+ enum libipw_state state;
int mode; /* A, B, G */
int modulation; /* CCK, OFDM */
@@ -862,43 +866,43 @@ struct ieee80211_device {
/* Callback functions */
void (*set_security) (struct net_device * dev,
- struct ieee80211_security * sec);
- int (*hard_start_xmit) (struct ieee80211_txb * txb,
- struct net_device * dev, int pri);
+ struct libipw_security * sec);
+ netdev_tx_t (*hard_start_xmit) (struct libipw_txb * txb,
+ struct net_device * dev, int pri);
int (*reset_port) (struct net_device * dev);
int (*is_queue_full) (struct net_device * dev, int pri);
int (*handle_management) (struct net_device * dev,
- struct ieee80211_network * network, u16 type);
+ struct libipw_network * network, u16 type);
int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb);
/* Typical STA methods */
int (*handle_auth) (struct net_device * dev,
- struct ieee80211_auth * auth);
+ struct libipw_auth * auth);
int (*handle_deauth) (struct net_device * dev,
- struct ieee80211_deauth * auth);
+ struct libipw_deauth * auth);
int (*handle_action) (struct net_device * dev,
- struct ieee80211_action * action,
- struct ieee80211_rx_stats * stats);
+ struct libipw_action * action,
+ struct libipw_rx_stats * stats);
int (*handle_disassoc) (struct net_device * dev,
- struct ieee80211_disassoc * assoc);
+ struct libipw_disassoc * assoc);
int (*handle_beacon) (struct net_device * dev,
- struct ieee80211_beacon * beacon,
- struct ieee80211_network * network);
+ struct libipw_beacon * beacon,
+ struct libipw_network * network);
int (*handle_probe_response) (struct net_device * dev,
- struct ieee80211_probe_response * resp,
- struct ieee80211_network * network);
+ struct libipw_probe_response * resp,
+ struct libipw_network * network);
int (*handle_probe_request) (struct net_device * dev,
- struct ieee80211_probe_request * req,
- struct ieee80211_rx_stats * stats);
+ struct libipw_probe_request * req,
+ struct libipw_rx_stats * stats);
int (*handle_assoc_response) (struct net_device * dev,
- struct ieee80211_assoc_response * resp,
- struct ieee80211_network * network);
+ struct libipw_assoc_response * resp,
+ struct libipw_network * network);
/* Typical AP methods */
int (*handle_assoc_request) (struct net_device * dev);
int (*handle_reassoc_request) (struct net_device * dev,
- struct ieee80211_reassoc_request * req);
+ struct libipw_reassoc_request * req);
/* This must be the last item so that it points to the data
* allocated beyond this structure by alloc_ieee80211 */
@@ -910,12 +914,12 @@ struct ieee80211_device {
#define IEEE_G (1<<2)
#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G)
-static inline void *ieee80211_priv(struct net_device *dev)
+static inline void *libipw_priv(struct net_device *dev)
{
- return ((struct ieee80211_device *)netdev_priv(dev))->priv;
+ return ((struct libipw_device *)netdev_priv(dev))->priv;
}
-static inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee,
+static inline int libipw_is_valid_mode(struct libipw_device *ieee,
int mode)
{
/*
@@ -925,32 +929,32 @@ static inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee,
*
*/
if ((mode & IEEE_A) &&
- (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
- (ieee->freq_band & IEEE80211_52GHZ_BAND))
+ (ieee->modulation & LIBIPW_OFDM_MODULATION) &&
+ (ieee->freq_band & LIBIPW_52GHZ_BAND))
return 1;
if ((mode & IEEE_G) &&
- (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
- (ieee->freq_band & IEEE80211_24GHZ_BAND))
+ (ieee->modulation & LIBIPW_OFDM_MODULATION) &&
+ (ieee->freq_band & LIBIPW_24GHZ_BAND))
return 1;
if ((mode & IEEE_B) &&
- (ieee->modulation & IEEE80211_CCK_MODULATION) &&
- (ieee->freq_band & IEEE80211_24GHZ_BAND))
+ (ieee->modulation & LIBIPW_CCK_MODULATION) &&
+ (ieee->freq_band & LIBIPW_24GHZ_BAND))
return 1;
return 0;
}
-static inline int ieee80211_get_hdrlen(u16 fc)
+static inline int libipw_get_hdrlen(u16 fc)
{
- int hdrlen = IEEE80211_3ADDR_LEN;
+ int hdrlen = LIBIPW_3ADDR_LEN;
u16 stype = WLAN_FC_GET_STYPE(fc);
switch (WLAN_FC_GET_TYPE(fc)) {
case IEEE80211_FTYPE_DATA:
if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
- hdrlen = IEEE80211_4ADDR_LEN;
+ hdrlen = LIBIPW_4ADDR_LEN;
if (stype & IEEE80211_STYPE_QOS_DATA)
hdrlen += 2;
break;
@@ -958,10 +962,10 @@ static inline int ieee80211_get_hdrlen(u16 fc)
switch (WLAN_FC_GET_STYPE(fc)) {
case IEEE80211_STYPE_CTS:
case IEEE80211_STYPE_ACK:
- hdrlen = IEEE80211_1ADDR_LEN;
+ hdrlen = LIBIPW_1ADDR_LEN;
break;
default:
- hdrlen = IEEE80211_2ADDR_LEN;
+ hdrlen = LIBIPW_2ADDR_LEN;
break;
}
break;
@@ -970,118 +974,119 @@ static inline int ieee80211_get_hdrlen(u16 fc)
return hdrlen;
}
-static inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr)
+static inline u8 *libipw_get_payload(struct ieee80211_hdr *hdr)
{
- switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control))) {
- case IEEE80211_1ADDR_LEN:
- return ((struct ieee80211_hdr_1addr *)hdr)->payload;
- case IEEE80211_2ADDR_LEN:
- return ((struct ieee80211_hdr_2addr *)hdr)->payload;
- case IEEE80211_3ADDR_LEN:
- return ((struct ieee80211_hdr_3addr *)hdr)->payload;
- case IEEE80211_4ADDR_LEN:
- return ((struct ieee80211_hdr_4addr *)hdr)->payload;
+ switch (libipw_get_hdrlen(le16_to_cpu(hdr->frame_control))) {
+ case LIBIPW_1ADDR_LEN:
+ return ((struct libipw_hdr_1addr *)hdr)->payload;
+ case LIBIPW_2ADDR_LEN:
+ return ((struct libipw_hdr_2addr *)hdr)->payload;
+ case LIBIPW_3ADDR_LEN:
+ return ((struct libipw_hdr_3addr *)hdr)->payload;
+ case LIBIPW_4ADDR_LEN:
+ return ((struct libipw_hdr_4addr *)hdr)->payload;
}
return NULL;
}
-static inline int ieee80211_is_ofdm_rate(u8 rate)
+static inline int libipw_is_ofdm_rate(u8 rate)
{
- switch (rate & ~IEEE80211_BASIC_RATE_MASK) {
- case IEEE80211_OFDM_RATE_6MB:
- case IEEE80211_OFDM_RATE_9MB:
- case IEEE80211_OFDM_RATE_12MB:
- case IEEE80211_OFDM_RATE_18MB:
- case IEEE80211_OFDM_RATE_24MB:
- case IEEE80211_OFDM_RATE_36MB:
- case IEEE80211_OFDM_RATE_48MB:
- case IEEE80211_OFDM_RATE_54MB:
+ switch (rate & ~LIBIPW_BASIC_RATE_MASK) {
+ case LIBIPW_OFDM_RATE_6MB:
+ case LIBIPW_OFDM_RATE_9MB:
+ case LIBIPW_OFDM_RATE_12MB:
+ case LIBIPW_OFDM_RATE_18MB:
+ case LIBIPW_OFDM_RATE_24MB:
+ case LIBIPW_OFDM_RATE_36MB:
+ case LIBIPW_OFDM_RATE_48MB:
+ case LIBIPW_OFDM_RATE_54MB:
return 1;
}
return 0;
}
-static inline int ieee80211_is_cck_rate(u8 rate)
+static inline int libipw_is_cck_rate(u8 rate)
{
- switch (rate & ~IEEE80211_BASIC_RATE_MASK) {
- case IEEE80211_CCK_RATE_1MB:
- case IEEE80211_CCK_RATE_2MB:
- case IEEE80211_CCK_RATE_5MB:
- case IEEE80211_CCK_RATE_11MB:
+ switch (rate & ~LIBIPW_BASIC_RATE_MASK) {
+ case LIBIPW_CCK_RATE_1MB:
+ case LIBIPW_CCK_RATE_2MB:
+ case LIBIPW_CCK_RATE_5MB:
+ case LIBIPW_CCK_RATE_11MB:
return 1;
}
return 0;
}
/* ieee80211.c */
-extern void free_ieee80211(struct net_device *dev);
-extern struct net_device *alloc_ieee80211(int sizeof_priv);
-extern int ieee80211_change_mtu(struct net_device *dev, int new_mtu);
+extern void free_ieee80211(struct net_device *dev, int monitor);
+extern struct net_device *alloc_ieee80211(int sizeof_priv, int monitor);
+extern int libipw_change_mtu(struct net_device *dev, int new_mtu);
-extern void ieee80211_networks_age(struct ieee80211_device *ieee,
+extern void libipw_networks_age(struct libipw_device *ieee,
unsigned long age_secs);
-extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
+extern int libipw_set_encryption(struct libipw_device *ieee);
-/* ieee80211_tx.c */
-extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev);
-extern void ieee80211_txb_free(struct ieee80211_txb *);
+/* libipw_tx.c */
+extern netdev_tx_t libipw_xmit(struct sk_buff *skb,
+ struct net_device *dev);
+extern void libipw_txb_free(struct libipw_txb *);
-/* ieee80211_rx.c */
-extern void ieee80211_rx_any(struct ieee80211_device *ieee,
- struct sk_buff *skb, struct ieee80211_rx_stats *stats);
-extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
- struct ieee80211_rx_stats *rx_stats);
+/* libipw_rx.c */
+extern void libipw_rx_any(struct libipw_device *ieee,
+ struct sk_buff *skb, struct libipw_rx_stats *stats);
+extern int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
+ struct libipw_rx_stats *rx_stats);
/* make sure to set stats->len */
-extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
- struct ieee80211_hdr_4addr *header,
- struct ieee80211_rx_stats *stats);
-extern void ieee80211_network_reset(struct ieee80211_network *network);
+extern void libipw_rx_mgt(struct libipw_device *ieee,
+ struct libipw_hdr_4addr *header,
+ struct libipw_rx_stats *stats);
+extern void libipw_network_reset(struct libipw_network *network);
-/* ieee80211_geo.c */
-extern const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device
+/* libipw_geo.c */
+extern const struct libipw_geo *libipw_get_geo(struct libipw_device
*ieee);
-extern int ieee80211_set_geo(struct ieee80211_device *ieee,
- const struct ieee80211_geo *geo);
+extern int libipw_set_geo(struct libipw_device *ieee,
+ const struct libipw_geo *geo);
-extern int ieee80211_is_valid_channel(struct ieee80211_device *ieee,
+extern int libipw_is_valid_channel(struct libipw_device *ieee,
u8 channel);
-extern int ieee80211_channel_to_index(struct ieee80211_device *ieee,
+extern int libipw_channel_to_index(struct libipw_device *ieee,
u8 channel);
-extern u8 ieee80211_freq_to_channel(struct ieee80211_device *ieee, u32 freq);
-extern u8 ieee80211_get_channel_flags(struct ieee80211_device *ieee,
+extern u8 libipw_freq_to_channel(struct libipw_device *ieee, u32 freq);
+extern u8 libipw_get_channel_flags(struct libipw_device *ieee,
u8 channel);
-extern const struct ieee80211_channel *ieee80211_get_channel(struct
- ieee80211_device
+extern const struct libipw_channel *libipw_get_channel(struct
+ libipw_device
*ieee, u8 channel);
-extern u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee,
+extern u32 libipw_channel_to_freq(struct libipw_device * ieee,
u8 channel);
-/* ieee80211_wx.c */
-extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
+/* libipw_wx.c */
+extern int libipw_wx_get_scan(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *key);
-extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
+extern int libipw_wx_set_encode(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *key);
-extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
+extern int libipw_wx_get_encode(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *key);
-extern int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
+extern int libipw_wx_set_encodeext(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra);
-extern int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
+extern int libipw_wx_get_encodeext(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra);
-static inline void ieee80211_increment_scans(struct ieee80211_device *ieee)
+static inline void libipw_increment_scans(struct libipw_device *ieee)
{
ieee->scans++;
}
-static inline int ieee80211_get_scans(struct ieee80211_device *ieee)
+static inline int libipw_get_scans(struct libipw_device *ieee)
{
return ieee->scans;
}
-#endif /* IEEE80211_H */
+#endif /* LIBIPW_H */
diff --git a/drivers/net/wireless/ipw2x00/libipw_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c
index 9dfbb8760f67..65e8c175a4a0 100644
--- a/drivers/net/wireless/ipw2x00/libipw_geo.c
+++ b/drivers/net/wireless/ipw2x00/libipw_geo.c
@@ -19,7 +19,7 @@
file called LICENSE.
Contact Information:
- James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
******************************************************************************/
@@ -41,9 +41,9 @@
#include <linux/etherdevice.h>
#include <asm/uaccess.h>
-#include "ieee80211.h"
+#include "libipw.h"
-int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel)
+int libipw_is_valid_channel(struct libipw_device *ieee, u8 channel)
{
int i;
@@ -52,27 +52,27 @@ int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel)
if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
return 0;
- if (ieee->freq_band & IEEE80211_24GHZ_BAND)
+ if (ieee->freq_band & LIBIPW_24GHZ_BAND)
for (i = 0; i < ieee->geo.bg_channels; i++)
/* NOTE: If G mode is currently supported but
* this is a B only channel, we don't see it
* as valid. */
if ((ieee->geo.bg[i].channel == channel) &&
- !(ieee->geo.bg[i].flags & IEEE80211_CH_INVALID) &&
+ !(ieee->geo.bg[i].flags & LIBIPW_CH_INVALID) &&
(!(ieee->mode & IEEE_G) ||
- !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY)))
- return IEEE80211_24GHZ_BAND;
+ !(ieee->geo.bg[i].flags & LIBIPW_CH_B_ONLY)))
+ return LIBIPW_24GHZ_BAND;
- if (ieee->freq_band & IEEE80211_52GHZ_BAND)
+ if (ieee->freq_band & LIBIPW_52GHZ_BAND)
for (i = 0; i < ieee->geo.a_channels; i++)
if ((ieee->geo.a[i].channel == channel) &&
- !(ieee->geo.a[i].flags & IEEE80211_CH_INVALID))
- return IEEE80211_52GHZ_BAND;
+ !(ieee->geo.a[i].flags & LIBIPW_CH_INVALID))
+ return LIBIPW_52GHZ_BAND;
return 0;
}
-int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel)
+int libipw_channel_to_index(struct libipw_device *ieee, u8 channel)
{
int i;
@@ -81,12 +81,12 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel)
if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
return -1;
- if (ieee->freq_band & IEEE80211_24GHZ_BAND)
+ if (ieee->freq_band & LIBIPW_24GHZ_BAND)
for (i = 0; i < ieee->geo.bg_channels; i++)
if (ieee->geo.bg[i].channel == channel)
return i;
- if (ieee->freq_band & IEEE80211_52GHZ_BAND)
+ if (ieee->freq_band & LIBIPW_52GHZ_BAND)
for (i = 0; i < ieee->geo.a_channels; i++)
if (ieee->geo.a[i].channel == channel)
return i;
@@ -94,22 +94,22 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel)
return -1;
}
-u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, u8 channel)
+u32 libipw_channel_to_freq(struct libipw_device * ieee, u8 channel)
{
- const struct ieee80211_channel * ch;
+ const struct libipw_channel * ch;
/* Driver needs to initialize the geography map before using
* these helper functions */
if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
return 0;
- ch = ieee80211_get_channel(ieee, channel);
+ ch = libipw_get_channel(ieee, channel);
if (!ch->channel)
return 0;
return ch->freq;
}
-u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
+u8 libipw_freq_to_channel(struct libipw_device * ieee, u32 freq)
{
int i;
@@ -120,12 +120,12 @@ u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
freq /= 100000;
- if (ieee->freq_band & IEEE80211_24GHZ_BAND)
+ if (ieee->freq_band & LIBIPW_24GHZ_BAND)
for (i = 0; i < ieee->geo.bg_channels; i++)
if (ieee->geo.bg[i].freq == freq)
return ieee->geo.bg[i].channel;
- if (ieee->freq_band & IEEE80211_52GHZ_BAND)
+ if (ieee->freq_band & LIBIPW_52GHZ_BAND)
for (i = 0; i < ieee->geo.a_channels; i++)
if (ieee->geo.a[i].freq == freq)
return ieee->geo.a[i].channel;
@@ -133,63 +133,63 @@ u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
return 0;
}
-int ieee80211_set_geo(struct ieee80211_device *ieee,
- const struct ieee80211_geo *geo)
+int libipw_set_geo(struct libipw_device *ieee,
+ const struct libipw_geo *geo)
{
memcpy(ieee->geo.name, geo->name, 3);
ieee->geo.name[3] = '\0';
ieee->geo.bg_channels = geo->bg_channels;
ieee->geo.a_channels = geo->a_channels;
memcpy(ieee->geo.bg, geo->bg, geo->bg_channels *
- sizeof(struct ieee80211_channel));
+ sizeof(struct libipw_channel));
memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels *
- sizeof(struct ieee80211_channel));
+ sizeof(struct libipw_channel));
return 0;
}
-const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device *ieee)
+const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee)
{
return &ieee->geo;
}
-u8 ieee80211_get_channel_flags(struct ieee80211_device * ieee, u8 channel)
+u8 libipw_get_channel_flags(struct libipw_device * ieee, u8 channel)
{
- int index = ieee80211_channel_to_index(ieee, channel);
+ int index = libipw_channel_to_index(ieee, channel);
if (index == -1)
- return IEEE80211_CH_INVALID;
+ return LIBIPW_CH_INVALID;
- if (channel <= IEEE80211_24GHZ_CHANNELS)
+ if (channel <= LIBIPW_24GHZ_CHANNELS)
return ieee->geo.bg[index].flags;
return ieee->geo.a[index].flags;
}
-static const struct ieee80211_channel bad_channel = {
+static const struct libipw_channel bad_channel = {
.channel = 0,
- .flags = IEEE80211_CH_INVALID,
+ .flags = LIBIPW_CH_INVALID,
.max_power = 0,
};
-const struct ieee80211_channel *ieee80211_get_channel(struct ieee80211_device
+const struct libipw_channel *libipw_get_channel(struct libipw_device
*ieee, u8 channel)
{
- int index = ieee80211_channel_to_index(ieee, channel);
+ int index = libipw_channel_to_index(ieee, channel);
if (index == -1)
return &bad_channel;
- if (channel <= IEEE80211_24GHZ_CHANNELS)
+ if (channel <= LIBIPW_24GHZ_CHANNELS)
return &ieee->geo.bg[index];
return &ieee->geo.a[index];
}
-EXPORT_SYMBOL(ieee80211_get_channel);
-EXPORT_SYMBOL(ieee80211_get_channel_flags);
-EXPORT_SYMBOL(ieee80211_is_valid_channel);
-EXPORT_SYMBOL(ieee80211_freq_to_channel);
-EXPORT_SYMBOL(ieee80211_channel_to_freq);
-EXPORT_SYMBOL(ieee80211_channel_to_index);
-EXPORT_SYMBOL(ieee80211_set_geo);
-EXPORT_SYMBOL(ieee80211_get_geo);
+EXPORT_SYMBOL(libipw_get_channel);
+EXPORT_SYMBOL(libipw_get_channel_flags);
+EXPORT_SYMBOL(libipw_is_valid_channel);
+EXPORT_SYMBOL(libipw_freq_to_channel);
+EXPORT_SYMBOL(libipw_channel_to_freq);
+EXPORT_SYMBOL(libipw_channel_to_index);
+EXPORT_SYMBOL(libipw_set_geo);
+EXPORT_SYMBOL(libipw_get_geo);
diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c
index 8ce6e961c5da..a0e9f6aed7da 100644
--- a/drivers/net/wireless/ipw2x00/libipw_module.c
+++ b/drivers/net/wireless/ipw2x00/libipw_module.c
@@ -25,7 +25,7 @@
file called LICENSE.
Contact Information:
- James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
@@ -50,11 +50,11 @@
#include <net/net_namespace.h>
#include <net/arp.h>
-#include "ieee80211.h"
+#include "libipw.h"
#define DRV_DESCRIPTION "802.11 data/management/control stack"
#define DRV_NAME "ieee80211"
-#define DRV_VERSION IEEE80211_VERSION
+#define DRV_VERSION LIBIPW_VERSION
#define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>"
MODULE_VERSION(DRV_VERSION);
@@ -62,13 +62,16 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
-static int ieee80211_networks_allocate(struct ieee80211_device *ieee)
+struct cfg80211_ops libipw_config_ops = { };
+void *libipw_wiphy_privid = &libipw_wiphy_privid;
+
+static int libipw_networks_allocate(struct libipw_device *ieee)
{
if (ieee->networks)
return 0;
ieee->networks =
- kzalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
+ kzalloc(MAX_NETWORK_COUNT * sizeof(struct libipw_network),
GFP_KERNEL);
if (!ieee->networks) {
printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
@@ -79,7 +82,7 @@ static int ieee80211_networks_allocate(struct ieee80211_device *ieee)
return 0;
}
-void ieee80211_network_reset(struct ieee80211_network *network)
+void libipw_network_reset(struct libipw_network *network)
{
if (!network)
return;
@@ -90,7 +93,7 @@ void ieee80211_network_reset(struct ieee80211_network *network)
}
}
-static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
+static inline void libipw_networks_free(struct libipw_device *ieee)
{
int i;
@@ -105,10 +108,10 @@ static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
ieee->networks = NULL;
}
-void ieee80211_networks_age(struct ieee80211_device *ieee,
+void libipw_networks_age(struct libipw_device *ieee,
unsigned long age_secs)
{
- struct ieee80211_network *network = NULL;
+ struct libipw_network *network = NULL;
unsigned long flags;
unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
@@ -118,9 +121,9 @@ void ieee80211_networks_age(struct ieee80211_device *ieee,
}
spin_unlock_irqrestore(&ieee->lock, flags);
}
-EXPORT_SYMBOL(ieee80211_networks_age);
+EXPORT_SYMBOL(libipw_networks_age);
-static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
+static void libipw_networks_initialize(struct libipw_device *ieee)
{
int i;
@@ -131,38 +134,59 @@ static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
&ieee->network_free_list);
}
-int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
+int libipw_change_mtu(struct net_device *dev, int new_mtu)
{
- if ((new_mtu < 68) || (new_mtu > IEEE80211_DATA_LEN))
+ if ((new_mtu < 68) || (new_mtu > LIBIPW_DATA_LEN))
return -EINVAL;
dev->mtu = new_mtu;
return 0;
}
-EXPORT_SYMBOL(ieee80211_change_mtu);
+EXPORT_SYMBOL(libipw_change_mtu);
-struct net_device *alloc_ieee80211(int sizeof_priv)
+struct net_device *alloc_ieee80211(int sizeof_priv, int monitor)
{
- struct ieee80211_device *ieee;
+ struct libipw_device *ieee;
struct net_device *dev;
int err;
- IEEE80211_DEBUG_INFO("Initializing...\n");
+ LIBIPW_DEBUG_INFO("Initializing...\n");
- dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
+ dev = alloc_etherdev(sizeof(struct libipw_device) + sizeof_priv);
if (!dev) {
- IEEE80211_ERROR("Unable to allocate network device.\n");
+ LIBIPW_ERROR("Unable to allocate network device.\n");
goto failed;
}
ieee = netdev_priv(dev);
ieee->dev = dev;
- err = ieee80211_networks_allocate(ieee);
+ if (!monitor) {
+ ieee->wdev.wiphy = wiphy_new(&libipw_config_ops, 0);
+ if (!ieee->wdev.wiphy) {
+ LIBIPW_ERROR("Unable to allocate wiphy.\n");
+ goto failed_free_netdev;
+ }
+
+ ieee->dev->ieee80211_ptr = &ieee->wdev;
+ ieee->wdev.iftype = NL80211_IFTYPE_STATION;
+
+ /* Fill-out wiphy structure bits we know... Not enough info
+ here to call set_wiphy_dev or set MAC address or channel info
+ -- have to do that in ->ndo_init... */
+ ieee->wdev.wiphy->privid = libipw_wiphy_privid;
+
+ ieee->wdev.wiphy->max_scan_ssids = 1;
+ ieee->wdev.wiphy->max_scan_ie_len = 0;
+ ieee->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
+ | BIT(NL80211_IFTYPE_ADHOC);
+ }
+
+ err = libipw_networks_allocate(ieee);
if (err) {
- IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
- goto failed_free_netdev;
+ LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err);
+ goto failed_free_wiphy;
}
- ieee80211_networks_initialize(ieee);
+ libipw_networks_initialize(ieee);
/* Default fragmentation threshold is maximum payload size */
ieee->fts = DEFAULT_FTS;
@@ -193,33 +217,45 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
return dev;
+failed_free_wiphy:
+ if (!monitor)
+ wiphy_free(ieee->wdev.wiphy);
failed_free_netdev:
free_netdev(dev);
failed:
return NULL;
}
-void free_ieee80211(struct net_device *dev)
+void free_ieee80211(struct net_device *dev, int monitor)
{
- struct ieee80211_device *ieee = netdev_priv(dev);
+ struct libipw_device *ieee = netdev_priv(dev);
lib80211_crypt_info_free(&ieee->crypt_info);
- ieee80211_networks_free(ieee);
+ libipw_networks_free(ieee);
+
+ /* free cfg80211 resources */
+ if (!monitor) {
+ wiphy_unregister(ieee->wdev.wiphy);
+ kfree(ieee->a_band.channels);
+ kfree(ieee->bg_band.channels);
+ wiphy_free(ieee->wdev.wiphy);
+ }
+
free_netdev(dev);
}
#ifdef CONFIG_LIBIPW_DEBUG
static int debug = 0;
-u32 ieee80211_debug_level = 0;
-EXPORT_SYMBOL_GPL(ieee80211_debug_level);
-static struct proc_dir_entry *ieee80211_proc = NULL;
+u32 libipw_debug_level = 0;
+EXPORT_SYMBOL_GPL(libipw_debug_level);
+static struct proc_dir_entry *libipw_proc = NULL;
static int show_debug_level(char *page, char **start, off_t offset,
int count, int *eof, void *data)
{
- return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
+ return snprintf(page, count, "0x%08X\n", libipw_debug_level);
}
static int store_debug_level(struct file *file, const char __user * buffer,
@@ -236,29 +272,29 @@ static int store_debug_level(struct file *file, const char __user * buffer,
printk(KERN_INFO DRV_NAME
": %s is not in hex or decimal form.\n", buf);
else
- ieee80211_debug_level = val;
+ libipw_debug_level = val;
return strnlen(buf, len);
}
#endif /* CONFIG_LIBIPW_DEBUG */
-static int __init ieee80211_init(void)
+static int __init libipw_init(void)
{
#ifdef CONFIG_LIBIPW_DEBUG
struct proc_dir_entry *e;
- ieee80211_debug_level = debug;
- ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
- if (ieee80211_proc == NULL) {
- IEEE80211_ERROR("Unable to create " DRV_NAME
+ libipw_debug_level = debug;
+ libipw_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
+ if (libipw_proc == NULL) {
+ LIBIPW_ERROR("Unable to create " DRV_NAME
" proc directory\n");
return -EIO;
}
e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
- ieee80211_proc);
+ libipw_proc);
if (!e) {
remove_proc_entry(DRV_NAME, init_net.proc_net);
- ieee80211_proc = NULL;
+ libipw_proc = NULL;
return -EIO;
}
e->read_proc = show_debug_level;
@@ -272,13 +308,13 @@ static int __init ieee80211_init(void)
return 0;
}
-static void __exit ieee80211_exit(void)
+static void __exit libipw_exit(void)
{
#ifdef CONFIG_LIBIPW_DEBUG
- if (ieee80211_proc) {
- remove_proc_entry("debug_level", ieee80211_proc);
+ if (libipw_proc) {
+ remove_proc_entry("debug_level", libipw_proc);
remove_proc_entry(DRV_NAME, init_net.proc_net);
- ieee80211_proc = NULL;
+ libipw_proc = NULL;
}
#endif /* CONFIG_LIBIPW_DEBUG */
}
@@ -289,8 +325,8 @@ module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
#endif /* CONFIG_LIBIPW_DEBUG */
-module_exit(ieee80211_exit);
-module_init(ieee80211_init);
+module_exit(libipw_exit);
+module_init(libipw_init);
EXPORT_SYMBOL(alloc_ieee80211);
EXPORT_SYMBOL(free_ieee80211);
diff --git a/drivers/net/wireless/ipw2x00/libipw_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c
index dae4b8e4d8e9..282b1f7ff1e9 100644
--- a/drivers/net/wireless/ipw2x00/libipw_rx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_rx.c
@@ -34,18 +34,18 @@
#include <net/lib80211.h>
-#include "ieee80211.h"
+#include "libipw.h"
-static void ieee80211_monitor_rx(struct ieee80211_device *ieee,
+static void libipw_monitor_rx(struct libipw_device *ieee,
struct sk_buff *skb,
- struct ieee80211_rx_stats *rx_stats)
+ struct libipw_rx_stats *rx_stats)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
u16 fc = le16_to_cpu(hdr->frame_control);
skb->dev = ieee->dev;
skb_reset_mac_header(skb);
- skb_pull(skb, ieee80211_get_hdrlen(fc));
+ skb_pull(skb, libipw_get_hdrlen(fc));
skb->pkt_type = PACKET_OTHERHOST;
skb->protocol = htons(ETH_P_80211_RAW);
memset(skb->cb, 0, sizeof(skb->cb));
@@ -53,22 +53,22 @@ static void ieee80211_monitor_rx(struct ieee80211_device *ieee,
}
/* Called only as a tasklet (software IRQ) */
-static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct
- ieee80211_device
+static struct libipw_frag_entry *libipw_frag_cache_find(struct
+ libipw_device
*ieee,
unsigned int seq,
unsigned int frag,
u8 * src,
u8 * dst)
{
- struct ieee80211_frag_entry *entry;
+ struct libipw_frag_entry *entry;
int i;
- for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) {
+ for (i = 0; i < LIBIPW_FRAG_CACHE_LEN; i++) {
entry = &ieee->frag_cache[i];
if (entry->skb != NULL &&
time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
- IEEE80211_DEBUG_FRAG("expiring fragment cache entry "
+ LIBIPW_DEBUG_FRAG("expiring fragment cache entry "
"seq=%u last_frag=%u\n",
entry->seq, entry->last_frag);
dev_kfree_skb_any(entry->skb);
@@ -86,13 +86,13 @@ static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct
}
/* Called only as a tasklet (software IRQ) */
-static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee,
- struct ieee80211_hdr_4addr *hdr)
+static struct sk_buff *libipw_frag_cache_get(struct libipw_device *ieee,
+ struct libipw_hdr_4addr *hdr)
{
struct sk_buff *skb = NULL;
u16 sc;
unsigned int frag, seq;
- struct ieee80211_frag_entry *entry;
+ struct libipw_frag_entry *entry;
sc = le16_to_cpu(hdr->seq_ctl);
frag = WLAN_GET_SEQ_FRAG(sc);
@@ -101,7 +101,7 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee,
if (frag == 0) {
/* Reserve enough space to fit maximum frame length */
skb = dev_alloc_skb(ieee->dev->mtu +
- sizeof(struct ieee80211_hdr_4addr) +
+ sizeof(struct libipw_hdr_4addr) +
8 /* LLC */ +
2 /* alignment */ +
8 /* WEP */ + ETH_ALEN /* WDS */ );
@@ -110,7 +110,7 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee,
entry = &ieee->frag_cache[ieee->frag_next_idx];
ieee->frag_next_idx++;
- if (ieee->frag_next_idx >= IEEE80211_FRAG_CACHE_LEN)
+ if (ieee->frag_next_idx >= LIBIPW_FRAG_CACHE_LEN)
ieee->frag_next_idx = 0;
if (entry->skb != NULL)
@@ -125,7 +125,7 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee,
} else {
/* received a fragment of a frame for which the head fragment
* should have already been received */
- entry = ieee80211_frag_cache_find(ieee, seq, frag, hdr->addr2,
+ entry = libipw_frag_cache_find(ieee, seq, frag, hdr->addr2,
hdr->addr1);
if (entry != NULL) {
entry->last_frag = frag;
@@ -137,21 +137,21 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee,
}
/* Called only as a tasklet (software IRQ) */
-static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,
- struct ieee80211_hdr_4addr *hdr)
+static int libipw_frag_cache_invalidate(struct libipw_device *ieee,
+ struct libipw_hdr_4addr *hdr)
{
u16 sc;
unsigned int seq;
- struct ieee80211_frag_entry *entry;
+ struct libipw_frag_entry *entry;
sc = le16_to_cpu(hdr->seq_ctl);
seq = WLAN_GET_SEQ_SEQ(sc);
- entry = ieee80211_frag_cache_find(ieee, seq, -1, hdr->addr2,
+ entry = libipw_frag_cache_find(ieee, seq, -1, hdr->addr2,
hdr->addr1);
if (entry == NULL) {
- IEEE80211_DEBUG_FRAG("could not invalidate fragment cache "
+ LIBIPW_DEBUG_FRAG("could not invalidate fragment cache "
"entry (seq=%u)\n", seq);
return -1;
}
@@ -161,14 +161,14 @@ static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,
}
#ifdef NOT_YET
-/* ieee80211_rx_frame_mgtmt
+/* libipw_rx_frame_mgtmt
*
* Responsible for handling management control frames
*
- * Called by ieee80211_rx */
+ * Called by libipw_rx */
static int
-ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
- struct ieee80211_rx_stats *rx_stats, u16 type,
+libipw_rx_frame_mgmt(struct libipw_device *ieee, struct sk_buff *skb,
+ struct libipw_rx_stats *rx_stats, u16 type,
u16 stype)
{
if (ieee->iw_mode == IW_MODE_MASTER) {
@@ -176,7 +176,7 @@ ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
ieee->dev->name);
return 0;
/*
- hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr_4addr *)
+ hostap_update_sta_ps(ieee, (struct hostap_libipw_hdr_4addr *)
skb->data);*/
}
@@ -219,26 +219,27 @@ ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-static unsigned char rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+static unsigned char libipw_rfc1042_header[] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-static unsigned char bridge_tunnel_header[] =
+static unsigned char libipw_bridge_tunnel_header[] =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
/* No encapsulation header if EtherType < 0x600 (=length) */
-/* Called by ieee80211_rx_frame_decrypt */
-static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,
+/* Called by libipw_rx_frame_decrypt */
+static int libipw_is_eapol_frame(struct libipw_device *ieee,
struct sk_buff *skb)
{
struct net_device *dev = ieee->dev;
u16 fc, ethertype;
- struct ieee80211_hdr_3addr *hdr;
+ struct libipw_hdr_3addr *hdr;
u8 *pos;
if (skb->len < 24)
return 0;
- hdr = (struct ieee80211_hdr_3addr *)skb->data;
+ hdr = (struct libipw_hdr_3addr *)skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
/* check that the frame is unicast frame to us */
@@ -266,28 +267,28 @@ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,
return 0;
}
-/* Called only as a tasklet (software IRQ), by ieee80211_rx */
+/* Called only as a tasklet (software IRQ), by libipw_rx */
static int
-ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
+libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb,
struct lib80211_crypt_data *crypt)
{
- struct ieee80211_hdr_3addr *hdr;
+ struct libipw_hdr_3addr *hdr;
int res, hdrlen;
if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
return 0;
- hdr = (struct ieee80211_hdr_3addr *)skb->data;
- hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+ hdr = (struct libipw_hdr_3addr *)skb->data;
+ hdrlen = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
atomic_inc(&crypt->refcnt);
res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
atomic_dec(&crypt->refcnt);
if (res < 0) {
- IEEE80211_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n",
+ LIBIPW_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n",
hdr->addr2, res);
if (res == -2)
- IEEE80211_DEBUG_DROP("Decryption failed ICV "
+ LIBIPW_DEBUG_DROP("Decryption failed ICV "
"mismatch (key %d)\n",
skb->data[hdrlen + 3] >> 6);
ieee->ieee_stats.rx_discards_undecryptable++;
@@ -297,20 +298,20 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
return res;
}
-/* Called only as a tasklet (software IRQ), by ieee80211_rx */
+/* Called only as a tasklet (software IRQ), by libipw_rx */
static int
-ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee,
+libipw_rx_frame_decrypt_msdu(struct libipw_device *ieee,
struct sk_buff *skb, int keyidx,
struct lib80211_crypt_data *crypt)
{
- struct ieee80211_hdr_3addr *hdr;
+ struct libipw_hdr_3addr *hdr;
int res, hdrlen;
if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
return 0;
- hdr = (struct ieee80211_hdr_3addr *)skb->data;
- hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+ hdr = (struct libipw_hdr_3addr *)skb->data;
+ hdrlen = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
atomic_inc(&crypt->refcnt);
res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
@@ -328,11 +329,11 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee,
/* All received frames are sent to this function. @skb contains the frame in
* IEEE 802.11 format, i.e., in the format it was sent over air.
* This function is called only as a tasklet (software IRQ). */
-int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
- struct ieee80211_rx_stats *rx_stats)
+int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
+ struct libipw_rx_stats *rx_stats)
{
struct net_device *dev = ieee->dev;
- struct ieee80211_hdr_4addr *hdr;
+ struct libipw_hdr_4addr *hdr;
size_t hdrlen;
u16 fc, type, stype, sc;
unsigned int frag;
@@ -352,7 +353,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
int keyidx = 0;
int can_be_decrypted = 0;
- hdr = (struct ieee80211_hdr_4addr *)skb->data;
+ hdr = (struct libipw_hdr_4addr *)skb->data;
if (skb->len < 10) {
printk(KERN_INFO "%s: SKB length < 10\n", dev->name);
goto rx_dropped;
@@ -363,7 +364,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
stype = WLAN_FC_GET_STYPE(fc);
sc = le16_to_cpu(hdr->seq_ctl);
frag = WLAN_GET_SEQ_FRAG(sc);
- hdrlen = ieee80211_get_hdrlen(fc);
+ hdrlen = libipw_get_hdrlen(fc);
if (skb->len < hdrlen) {
printk(KERN_INFO "%s: invalid SKB length %d\n",
@@ -380,19 +381,19 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
struct iw_quality wstats;
wstats.updated = 0;
- if (rx_stats->mask & IEEE80211_STATMASK_RSSI) {
+ if (rx_stats->mask & LIBIPW_STATMASK_RSSI) {
wstats.level = rx_stats->signal;
wstats.updated |= IW_QUAL_LEVEL_UPDATED;
} else
wstats.updated |= IW_QUAL_LEVEL_INVALID;
- if (rx_stats->mask & IEEE80211_STATMASK_NOISE) {
+ if (rx_stats->mask & LIBIPW_STATMASK_NOISE) {
wstats.noise = rx_stats->noise;
wstats.updated |= IW_QUAL_NOISE_UPDATED;
} else
wstats.updated |= IW_QUAL_NOISE_INVALID;
- if (rx_stats->mask & IEEE80211_STATMASK_SIGNAL) {
+ if (rx_stats->mask & LIBIPW_STATMASK_SIGNAL) {
wstats.qual = rx_stats->signal;
wstats.updated |= IW_QUAL_QUAL_UPDATED;
} else
@@ -411,7 +412,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
if (ieee->iw_mode == IW_MODE_MONITOR) {
dev->stats.rx_packets++;
dev->stats.rx_bytes += skb->len;
- ieee80211_monitor_rx(ieee, skb, rx_stats);
+ libipw_monitor_rx(ieee, skb, rx_stats);
return 1;
}
@@ -457,7 +458,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
* frames from other than current BSS, so just drop the
* frames silently instead of filling system log with
* these reports. */
- IEEE80211_DEBUG_DROP("Decryption failed (not set)"
+ LIBIPW_DEBUG_DROP("Decryption failed (not set)"
" (SA=%pM)\n", hdr->addr2);
ieee->ieee_stats.rx_discards_undecryptable++;
goto rx_dropped;
@@ -475,7 +476,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
goto rx_dropped;
}
- if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype))
+ if (libipw_rx_frame_mgmt(ieee, skb, rx_stats, type, stype))
goto rx_dropped;
else
goto rx_exit;
@@ -488,7 +489,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
ieee->prev_seq_ctl = sc;
/* Data frame - extract src/dst addresses */
- if (skb->len < IEEE80211_3ADDR_LEN)
+ if (skb->len < LIBIPW_3ADDR_LEN)
goto rx_dropped;
switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
@@ -501,7 +502,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
memcpy(src, hdr->addr2, ETH_ALEN);
break;
case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
- if (skb->len < IEEE80211_4ADDR_LEN)
+ if (skb->len < LIBIPW_4ADDR_LEN)
goto rx_dropped;
memcpy(dst, hdr->addr3, ETH_ALEN);
memcpy(src, hdr->addr4, ETH_ALEN);
@@ -560,7 +561,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
stype != IEEE80211_STYPE_DATA_CFPOLL &&
stype != IEEE80211_STYPE_DATA_CFACKPOLL) {
if (stype != IEEE80211_STYPE_NULLFUNC)
- IEEE80211_DEBUG_DROP("RX: dropped data frame "
+ LIBIPW_DEBUG_DROP("RX: dropped data frame "
"with no data (type=0x%02x, "
"subtype=0x%02x, len=%d)\n",
type, stype, skb->len);
@@ -570,21 +571,21 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
/* skb: hdr + (possibly fragmented, possibly encrypted) payload */
if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
- (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0)
+ (keyidx = libipw_rx_frame_decrypt(ieee, skb, crypt)) < 0)
goto rx_dropped;
- hdr = (struct ieee80211_hdr_4addr *)skb->data;
+ hdr = (struct libipw_hdr_4addr *)skb->data;
/* skb: hdr + (possibly fragmented) plaintext payload */
// PR: FIXME: hostap has additional conditions in the "if" below:
// ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) {
int flen;
- struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr);
- IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
+ struct sk_buff *frag_skb = libipw_frag_cache_get(ieee, hdr);
+ LIBIPW_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
if (!frag_skb) {
- IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG,
+ LIBIPW_DEBUG(LIBIPW_DL_RX | LIBIPW_DL_FRAG,
"Rx cannot get skb from fragment "
"cache (morefrag=%d seq=%u frag=%u)\n",
(fc & IEEE80211_FCTL_MOREFRAGS) != 0,
@@ -600,7 +601,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
printk(KERN_WARNING "%s: host decrypted and "
"reassembled frame did not fit skb\n",
dev->name);
- ieee80211_frag_cache_invalidate(ieee, hdr);
+ libipw_frag_cache_invalidate(ieee, hdr);
goto rx_dropped;
}
@@ -627,24 +628,24 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
/* this was the last fragment and the frame will be
* delivered, so remove skb from fragment cache */
skb = frag_skb;
- hdr = (struct ieee80211_hdr_4addr *)skb->data;
- ieee80211_frag_cache_invalidate(ieee, hdr);
+ hdr = (struct libipw_hdr_4addr *)skb->data;
+ libipw_frag_cache_invalidate(ieee, hdr);
}
/* skb: hdr + (possible reassembled) full MSDU payload; possibly still
* encrypted/authenticated */
if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
- ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
+ libipw_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
goto rx_dropped;
- hdr = (struct ieee80211_hdr_4addr *)skb->data;
+ hdr = (struct libipw_hdr_4addr *)skb->data;
if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) {
if ( /*ieee->ieee802_1x && */
- ieee80211_is_eapol_frame(ieee, skb)) {
+ libipw_is_eapol_frame(ieee, skb)) {
/* pass unencrypted EAPOL frames even if encryption is
* configured */
} else {
- IEEE80211_DEBUG_DROP("encryption configured, but RX "
+ LIBIPW_DEBUG_DROP("encryption configured, but RX "
"frame not encrypted (SA=%pM)\n",
hdr->addr2);
goto rx_dropped;
@@ -652,8 +653,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
}
if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep &&
- !ieee80211_is_eapol_frame(ieee, skb)) {
- IEEE80211_DEBUG_DROP("dropped unencrypted RX data "
+ !libipw_is_eapol_frame(ieee, skb)) {
+ LIBIPW_DEBUG_DROP("dropped unencrypted RX data "
"frame from %pM (drop_unencrypted=1)\n",
hdr->addr2);
goto rx_dropped;
@@ -736,9 +737,9 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
/* convert hdr + possible LLC headers into Ethernet header */
if (skb->len - hdrlen >= 8 &&
- ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 &&
+ ((memcmp(payload, libipw_rfc1042_header, SNAP_SIZE) == 0 &&
ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
- memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) {
+ memcmp(payload, libipw_bridge_tunnel_header, SNAP_SIZE) == 0)) {
/* remove RFC1042 or Bridge-Tunnel encapsulation and
* replace EtherType */
skb_pull(skb, hdrlen + SNAP_SIZE);
@@ -807,7 +808,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
/* netif_rx always succeeds, but it might drop
* the packet. If it drops the packet, we log that
* in our stats. */
- IEEE80211_DEBUG_DROP
+ LIBIPW_DEBUG_DROP
("RX: netif_rx dropped the packet\n");
dev->stats.rx_dropped++;
}
@@ -829,18 +830,18 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
return 0;
}
-/* Filter out unrelated packets, call ieee80211_rx[_mgt]
+/* Filter out unrelated packets, call libipw_rx[_mgt]
* This function takes over the skb, it should not be used again after calling
* this function. */
-void ieee80211_rx_any(struct ieee80211_device *ieee,
- struct sk_buff *skb, struct ieee80211_rx_stats *stats)
+void libipw_rx_any(struct libipw_device *ieee,
+ struct sk_buff *skb, struct libipw_rx_stats *stats)
{
- struct ieee80211_hdr_4addr *hdr;
+ struct libipw_hdr_4addr *hdr;
int is_packet_for_us;
u16 fc;
if (ieee->iw_mode == IW_MODE_MONITOR) {
- if (!ieee80211_rx(ieee, skb, stats))
+ if (!libipw_rx(ieee, skb, stats))
dev_kfree_skb_irq(skb);
return;
}
@@ -848,7 +849,7 @@ void ieee80211_rx_any(struct ieee80211_device *ieee,
if (skb->len < sizeof(struct ieee80211_hdr))
goto drop_free;
- hdr = (struct ieee80211_hdr_4addr *)skb->data;
+ hdr = (struct libipw_hdr_4addr *)skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
if ((fc & IEEE80211_FCTL_VERS) != 0)
@@ -856,9 +857,9 @@ void ieee80211_rx_any(struct ieee80211_device *ieee,
switch (fc & IEEE80211_FCTL_FTYPE) {
case IEEE80211_FTYPE_MGMT:
- if (skb->len < sizeof(struct ieee80211_hdr_3addr))
+ if (skb->len < sizeof(struct libipw_hdr_3addr))
goto drop_free;
- ieee80211_rx_mgt(ieee, hdr, stats);
+ libipw_rx_mgt(ieee, hdr, stats);
dev_kfree_skb_irq(skb);
return;
case IEEE80211_FTYPE_DATA:
@@ -910,7 +911,7 @@ void ieee80211_rx_any(struct ieee80211_device *ieee,
}
if (is_packet_for_us)
- if (!ieee80211_rx(ieee, skb, stats))
+ if (!libipw_rx(ieee, skb, stats))
dev_kfree_skb_irq(skb);
return;
@@ -928,7 +929,7 @@ static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
* Make ther structure we read from the beacon packet has
* the right values
*/
-static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element
+static int libipw_verify_qos_info(struct libipw_qos_information_element
*info_element, int sub_type)
{
@@ -947,12 +948,12 @@ static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element
/*
* Parse a QoS parameter element
*/
-static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info
- *element_param, struct ieee80211_info_element
+static int libipw_read_qos_param_element(struct libipw_qos_parameter_info
+ *element_param, struct libipw_info_element
*info_element)
{
int ret = 0;
- u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2;
+ u16 size = sizeof(struct libipw_qos_parameter_info) - 2;
if ((info_element == NULL) || (element_param == NULL))
return -1;
@@ -965,7 +966,7 @@ static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info
} else
ret = -1;
if (ret == 0)
- ret = ieee80211_verify_qos_info(&element_param->info_element,
+ ret = libipw_verify_qos_info(&element_param->info_element,
QOS_OUI_PARAM_SUB_TYPE);
return ret;
}
@@ -973,13 +974,13 @@ static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info
/*
* Parse a QoS information element
*/
-static int ieee80211_read_qos_info_element(struct
- ieee80211_qos_information_element
- *element_info, struct ieee80211_info_element
+static int libipw_read_qos_info_element(struct
+ libipw_qos_information_element
+ *element_info, struct libipw_info_element
*info_element)
{
int ret = 0;
- u16 size = sizeof(struct ieee80211_qos_information_element) - 2;
+ u16 size = sizeof(struct libipw_qos_information_element) - 2;
if (element_info == NULL)
return -1;
@@ -995,7 +996,7 @@ static int ieee80211_read_qos_info_element(struct
ret = -1;
if (ret == 0)
- ret = ieee80211_verify_qos_info(element_info,
+ ret = libipw_verify_qos_info(element_info,
QOS_OUI_INFO_SUB_TYPE);
return ret;
}
@@ -1003,15 +1004,15 @@ static int ieee80211_read_qos_info_element(struct
/*
* Write QoS parameters from the ac parameters.
*/
-static int ieee80211_qos_convert_ac_to_parameters(struct
- ieee80211_qos_parameter_info
+static int libipw_qos_convert_ac_to_parameters(struct
+ libipw_qos_parameter_info
*param_elm, struct
- ieee80211_qos_parameters
+ libipw_qos_parameters
*qos_param)
{
int rc = 0;
int i;
- struct ieee80211_qos_ac_parameter *ac_params;
+ struct libipw_qos_ac_parameter *ac_params;
u32 txop;
u8 cw_min;
u8 cw_max;
@@ -1042,27 +1043,27 @@ static int ieee80211_qos_convert_ac_to_parameters(struct
* parameters element. check the information element length to decide
* which type to read
*/
-static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element
+static int libipw_parse_qos_info_param_IE(struct libipw_info_element
*info_element,
- struct ieee80211_network *network)
+ struct libipw_network *network)
{
int rc = 0;
- struct ieee80211_qos_parameters *qos_param = NULL;
- struct ieee80211_qos_information_element qos_info_element;
+ struct libipw_qos_parameters *qos_param = NULL;
+ struct libipw_qos_information_element qos_info_element;
- rc = ieee80211_read_qos_info_element(&qos_info_element, info_element);
+ rc = libipw_read_qos_info_element(&qos_info_element, info_element);
if (rc == 0) {
network->qos_data.param_count = qos_info_element.ac_info & 0x0F;
network->flags |= NETWORK_HAS_QOS_INFORMATION;
} else {
- struct ieee80211_qos_parameter_info param_element;
+ struct libipw_qos_parameter_info param_element;
- rc = ieee80211_read_qos_param_element(&param_element,
+ rc = libipw_read_qos_param_element(&param_element,
info_element);
if (rc == 0) {
qos_param = &(network->qos_data.parameters);
- ieee80211_qos_convert_ac_to_parameters(&param_element,
+ libipw_qos_convert_ac_to_parameters(&param_element,
qos_param);
network->flags |= NETWORK_HAS_QOS_PARAMETERS;
network->qos_data.param_count =
@@ -1071,7 +1072,7 @@ static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element
}
if (rc == 0) {
- IEEE80211_DEBUG_QOS("QoS is supported\n");
+ LIBIPW_DEBUG_QOS("QoS is supported\n");
network->qos_data.supported = 1;
}
return rc;
@@ -1116,9 +1117,9 @@ static const char *get_info_element_string(u16 id)
}
#endif
-static int ieee80211_parse_info_param(struct ieee80211_info_element
+static int libipw_parse_info_param(struct libipw_info_element
*info_element, u16 length,
- struct ieee80211_network *network)
+ struct libipw_network *network)
{
DECLARE_SSID_BUF(ssid);
u8 i;
@@ -1129,7 +1130,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
while (length >= sizeof(*info_element)) {
if (sizeof(*info_element) + info_element->len > length) {
- IEEE80211_DEBUG_MGMT("Info elem: parse failed: "
+ LIBIPW_DEBUG_MGMT("Info elem: parse failed: "
"info_element->len + 2 > left : "
"info_element->len+2=%zd left=%d, id=%d.\n",
info_element->len +
@@ -1151,7 +1152,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
memset(network->ssid + network->ssid_len, 0,
IW_ESSID_MAX_SIZE - network->ssid_len);
- IEEE80211_DEBUG_MGMT("WLAN_EID_SSID: '%s' len=%d.\n",
+ LIBIPW_DEBUG_MGMT("WLAN_EID_SSID: '%s' len=%d.\n",
print_ssid(ssid, network->ssid,
network->ssid_len),
network->ssid_len);
@@ -1170,17 +1171,17 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
(p - rates_str), "%02X ",
network->rates[i]);
#endif
- if (ieee80211_is_ofdm_rate
+ if (libipw_is_ofdm_rate
(info_element->data[i])) {
network->flags |= NETWORK_HAS_OFDM;
if (info_element->data[i] &
- IEEE80211_BASIC_RATE_MASK)
+ LIBIPW_BASIC_RATE_MASK)
network->flags &=
~NETWORK_HAS_CCK;
}
}
- IEEE80211_DEBUG_MGMT("WLAN_EID_SUPP_RATES: '%s' (%d)\n",
+ LIBIPW_DEBUG_MGMT("WLAN_EID_SUPP_RATES: '%s' (%d)\n",
rates_str, network->rates_len);
break;
@@ -1197,61 +1198,61 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
(p - rates_str), "%02X ",
network->rates[i]);
#endif
- if (ieee80211_is_ofdm_rate
+ if (libipw_is_ofdm_rate
(info_element->data[i])) {
network->flags |= NETWORK_HAS_OFDM;
if (info_element->data[i] &
- IEEE80211_BASIC_RATE_MASK)
+ LIBIPW_BASIC_RATE_MASK)
network->flags &=
~NETWORK_HAS_CCK;
}
}
- IEEE80211_DEBUG_MGMT("WLAN_EID_EXT_SUPP_RATES: '%s' (%d)\n",
+ LIBIPW_DEBUG_MGMT("WLAN_EID_EXT_SUPP_RATES: '%s' (%d)\n",
rates_str, network->rates_ex_len);
break;
case WLAN_EID_DS_PARAMS:
- IEEE80211_DEBUG_MGMT("WLAN_EID_DS_PARAMS: %d\n",
+ LIBIPW_DEBUG_MGMT("WLAN_EID_DS_PARAMS: %d\n",
info_element->data[0]);
network->channel = info_element->data[0];
break;
case WLAN_EID_FH_PARAMS:
- IEEE80211_DEBUG_MGMT("WLAN_EID_FH_PARAMS: ignored\n");
+ LIBIPW_DEBUG_MGMT("WLAN_EID_FH_PARAMS: ignored\n");
break;
case WLAN_EID_CF_PARAMS:
- IEEE80211_DEBUG_MGMT("WLAN_EID_CF_PARAMS: ignored\n");
+ LIBIPW_DEBUG_MGMT("WLAN_EID_CF_PARAMS: ignored\n");
break;
case WLAN_EID_TIM:
network->tim.tim_count = info_element->data[0];
network->tim.tim_period = info_element->data[1];
- IEEE80211_DEBUG_MGMT("WLAN_EID_TIM: partially ignored\n");
+ LIBIPW_DEBUG_MGMT("WLAN_EID_TIM: partially ignored\n");
break;
case WLAN_EID_ERP_INFO:
network->erp_value = info_element->data[0];
network->flags |= NETWORK_HAS_ERP_VALUE;
- IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
+ LIBIPW_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
network->erp_value);
break;
case WLAN_EID_IBSS_PARAMS:
network->atim_window = info_element->data[0];
- IEEE80211_DEBUG_MGMT("WLAN_EID_IBSS_PARAMS: %d\n",
+ LIBIPW_DEBUG_MGMT("WLAN_EID_IBSS_PARAMS: %d\n",
network->atim_window);
break;
case WLAN_EID_CHALLENGE:
- IEEE80211_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n");
+ LIBIPW_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n");
break;
case WLAN_EID_GENERIC:
- IEEE80211_DEBUG_MGMT("WLAN_EID_GENERIC: %d bytes\n",
+ LIBIPW_DEBUG_MGMT("WLAN_EID_GENERIC: %d bytes\n",
info_element->len);
- if (!ieee80211_parse_qos_info_param_IE(info_element,
+ if (!libipw_parse_qos_info_param_IE(info_element,
network))
break;
@@ -1268,7 +1269,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
break;
case WLAN_EID_RSN:
- IEEE80211_DEBUG_MGMT("WLAN_EID_RSN: %d bytes\n",
+ LIBIPW_DEBUG_MGMT("WLAN_EID_RSN: %d bytes\n",
info_element->len);
network->rsn_ie_len = min(info_element->len + 2,
MAX_WPA_IE_LEN);
@@ -1318,7 +1319,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
break;
default:
- IEEE80211_DEBUG_MGMT
+ LIBIPW_DEBUG_MGMT
("Unsupported info element: %s (%d)\n",
get_info_element_string(info_element->id),
info_element->id);
@@ -1327,20 +1328,20 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
length -= sizeof(*info_element) + info_element->len;
info_element =
- (struct ieee80211_info_element *)&info_element->
+ (struct libipw_info_element *)&info_element->
data[info_element->len];
}
return 0;
}
-static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response
- *frame, struct ieee80211_rx_stats *stats)
+static int libipw_handle_assoc_resp(struct libipw_device *ieee, struct libipw_assoc_response
+ *frame, struct libipw_rx_stats *stats)
{
- struct ieee80211_network network_resp = {
+ struct libipw_network network_resp = {
.ibss_dfs = NULL,
};
- struct ieee80211_network *network = &network_resp;
+ struct libipw_network *network = &network_resp;
struct net_device *dev = ieee->dev;
network->flags = 0;
@@ -1361,7 +1362,7 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee
network->erp_value =
(network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0;
- if (stats->freq == IEEE80211_52GHZ_BAND) {
+ if (stats->freq == LIBIPW_52GHZ_BAND) {
/* for A band (No DS info) */
network->channel = stats->received_channel;
} else
@@ -1370,12 +1371,12 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee
network->wpa_ie_len = 0;
network->rsn_ie_len = 0;
- if (ieee80211_parse_info_param
+ if (libipw_parse_info_param
(frame->info_element, stats->len - sizeof(*frame), network))
return 1;
network->mode = 0;
- if (stats->freq == IEEE80211_52GHZ_BAND)
+ if (stats->freq == LIBIPW_52GHZ_BAND)
network->mode = IEEE_A;
else {
if (network->flags & NETWORK_HAS_OFDM)
@@ -1394,10 +1395,10 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee
/***************************************************/
-static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response
+static int libipw_network_init(struct libipw_device *ieee, struct libipw_probe_response
*beacon,
- struct ieee80211_network *network,
- struct ieee80211_rx_stats *stats)
+ struct libipw_network *network,
+ struct libipw_rx_stats *stats)
{
DECLARE_SSID_BUF(ssid);
@@ -1423,7 +1424,7 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021
network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ?
0x3 : 0x0;
- if (stats->freq == IEEE80211_52GHZ_BAND) {
+ if (stats->freq == LIBIPW_52GHZ_BAND) {
/* for A band (No DS info) */
network->channel = stats->received_channel;
} else
@@ -1432,12 +1433,12 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021
network->wpa_ie_len = 0;
network->rsn_ie_len = 0;
- if (ieee80211_parse_info_param
+ if (libipw_parse_info_param
(beacon->info_element, stats->len - sizeof(*beacon), network))
return 1;
network->mode = 0;
- if (stats->freq == IEEE80211_52GHZ_BAND)
+ if (stats->freq == LIBIPW_52GHZ_BAND)
network->mode = IEEE_A;
else {
if (network->flags & NETWORK_HAS_OFDM)
@@ -1447,7 +1448,7 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021
}
if (network->mode == 0) {
- IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' "
+ LIBIPW_DEBUG_SCAN("Filtered out '%s (%pM)' "
"network.\n",
print_ssid(ssid, network->ssid,
network->ssid_len),
@@ -1460,8 +1461,8 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021
return 0;
}
-static inline int is_same_network(struct ieee80211_network *src,
- struct ieee80211_network *dst)
+static inline int is_same_network(struct libipw_network *src,
+ struct libipw_network *dst)
{
/* A network is only a duplicate if the channel, BSSID, and ESSID
* all match. We treat all <hidden> with the same BSSID and channel
@@ -1472,13 +1473,13 @@ static inline int is_same_network(struct ieee80211_network *src,
!memcmp(src->ssid, dst->ssid, src->ssid_len));
}
-static void update_network(struct ieee80211_network *dst,
- struct ieee80211_network *src)
+static void update_network(struct libipw_network *dst,
+ struct libipw_network *src)
{
int qos_active;
u8 old_param;
- ieee80211_network_reset(dst);
+ libipw_network_reset(dst);
dst->ibss_dfs = src->ibss_dfs;
/* We only update the statistics if they were created by receiving
@@ -1488,9 +1489,9 @@ static void update_network(struct ieee80211_network *dst,
* down the signal level of an AP. */
if (dst->channel == src->stats.received_channel)
memcpy(&dst->stats, &src->stats,
- sizeof(struct ieee80211_rx_stats));
+ sizeof(struct libipw_rx_stats));
else
- IEEE80211_DEBUG_SCAN("Network %pM info received "
+ LIBIPW_DEBUG_SCAN("Network %pM info received "
"off channel (%d vs. %d)\n", src->bssid,
dst->channel, src->stats.received_channel);
@@ -1521,7 +1522,7 @@ static void update_network(struct ieee80211_network *dst,
old_param = dst->qos_data.old_param_count;
if (dst->flags & NETWORK_HAS_QOS_MASK)
memcpy(&dst->qos_data, &src->qos_data,
- sizeof(struct ieee80211_qos_data));
+ sizeof(struct libipw_qos_data));
else {
dst->qos_data.supported = src->qos_data.supported;
dst->qos_data.param_count = src->qos_data.param_count;
@@ -1529,11 +1530,11 @@ static void update_network(struct ieee80211_network *dst,
if (dst->qos_data.supported == 1) {
if (dst->ssid_len)
- IEEE80211_DEBUG_QOS
+ LIBIPW_DEBUG_QOS
("QoS the network %s is QoS supported\n",
dst->ssid);
else
- IEEE80211_DEBUG_QOS
+ LIBIPW_DEBUG_QOS
("QoS the network is QoS supported\n");
}
dst->qos_data.active = qos_active;
@@ -1547,25 +1548,25 @@ static inline int is_beacon(__le16 fc)
return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON);
}
-static void ieee80211_process_probe_response(struct ieee80211_device
+static void libipw_process_probe_response(struct libipw_device
*ieee, struct
- ieee80211_probe_response
- *beacon, struct ieee80211_rx_stats
+ libipw_probe_response
+ *beacon, struct libipw_rx_stats
*stats)
{
struct net_device *dev = ieee->dev;
- struct ieee80211_network network = {
+ struct libipw_network network = {
.ibss_dfs = NULL,
};
- struct ieee80211_network *target;
- struct ieee80211_network *oldest = NULL;
+ struct libipw_network *target;
+ struct libipw_network *oldest = NULL;
#ifdef CONFIG_LIBIPW_DEBUG
- struct ieee80211_info_element *info_element = beacon->info_element;
+ struct libipw_info_element *info_element = beacon->info_element;
#endif
unsigned long flags;
DECLARE_SSID_BUF(ssid);
- IEEE80211_DEBUG_SCAN("'%s' (%pM"
+ LIBIPW_DEBUG_SCAN("'%s' (%pM"
"): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
print_ssid(ssid, info_element->data, info_element->len),
beacon->header.addr3,
@@ -1586,8 +1587,8 @@ static void ieee80211_process_probe_response(struct ieee80211_device
(beacon->capability & cpu_to_le16(1 << 0x1)) ? '1' : '0',
(beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0');
- if (ieee80211_network_init(ieee, beacon, &network, stats)) {
- IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n",
+ if (libipw_network_init(ieee, beacon, &network, stats)) {
+ LIBIPW_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n",
print_ssid(ssid, info_element->data,
info_element->len),
beacon->header.addr3,
@@ -1624,21 +1625,21 @@ static void ieee80211_process_probe_response(struct ieee80211_device
/* If there are no more slots, expire the oldest */
list_del(&oldest->list);
target = oldest;
- IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from "
+ LIBIPW_DEBUG_SCAN("Expired '%s' (%pM) from "
"network list.\n",
print_ssid(ssid, target->ssid,
target->ssid_len),
target->bssid);
- ieee80211_network_reset(target);
+ libipw_network_reset(target);
} else {
/* Otherwise just pull from the free list */
target = list_entry(ieee->network_free_list.next,
- struct ieee80211_network, list);
+ struct libipw_network, list);
list_del(ieee->network_free_list.next);
}
#ifdef CONFIG_LIBIPW_DEBUG
- IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n",
+ LIBIPW_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n",
print_ssid(ssid, network.ssid,
network.ssid_len),
network.bssid,
@@ -1649,7 +1650,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device
network.ibss_dfs = NULL;
list_add_tail(&target->list, &ieee->network_list);
} else {
- IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
+ LIBIPW_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
print_ssid(ssid, target->ssid,
target->ssid_len),
target->bssid,
@@ -1670,121 +1671,121 @@ static void ieee80211_process_probe_response(struct ieee80211_device
}
}
-void ieee80211_rx_mgt(struct ieee80211_device *ieee,
- struct ieee80211_hdr_4addr *header,
- struct ieee80211_rx_stats *stats)
+void libipw_rx_mgt(struct libipw_device *ieee,
+ struct libipw_hdr_4addr *header,
+ struct libipw_rx_stats *stats)
{
switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) {
case IEEE80211_STYPE_ASSOC_RESP:
- IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n",
+ LIBIPW_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n",
WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl)));
- ieee80211_handle_assoc_resp(ieee,
- (struct ieee80211_assoc_response *)
+ libipw_handle_assoc_resp(ieee,
+ (struct libipw_assoc_response *)
header, stats);
break;
case IEEE80211_STYPE_REASSOC_RESP:
- IEEE80211_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n",
+ LIBIPW_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n",
WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl)));
break;
case IEEE80211_STYPE_PROBE_REQ:
- IEEE80211_DEBUG_MGMT("received auth (%d)\n",
+ LIBIPW_DEBUG_MGMT("received auth (%d)\n",
WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl)));
if (ieee->handle_probe_request != NULL)
ieee->handle_probe_request(ieee->dev,
(struct
- ieee80211_probe_request *)
+ libipw_probe_request *)
header, stats);
break;
case IEEE80211_STYPE_PROBE_RESP:
- IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n",
+ LIBIPW_DEBUG_MGMT("received PROBE RESPONSE (%d)\n",
WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl)));
- IEEE80211_DEBUG_SCAN("Probe response\n");
- ieee80211_process_probe_response(ieee,
+ LIBIPW_DEBUG_SCAN("Probe response\n");
+ libipw_process_probe_response(ieee,
(struct
- ieee80211_probe_response *)
+ libipw_probe_response *)
header, stats);
break;
case IEEE80211_STYPE_BEACON:
- IEEE80211_DEBUG_MGMT("received BEACON (%d)\n",
+ LIBIPW_DEBUG_MGMT("received BEACON (%d)\n",
WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl)));
- IEEE80211_DEBUG_SCAN("Beacon\n");
- ieee80211_process_probe_response(ieee,
+ LIBIPW_DEBUG_SCAN("Beacon\n");
+ libipw_process_probe_response(ieee,
(struct
- ieee80211_probe_response *)
+ libipw_probe_response *)
header, stats);
break;
case IEEE80211_STYPE_AUTH:
- IEEE80211_DEBUG_MGMT("received auth (%d)\n",
+ LIBIPW_DEBUG_MGMT("received auth (%d)\n",
WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl)));
if (ieee->handle_auth != NULL)
ieee->handle_auth(ieee->dev,
- (struct ieee80211_auth *)header);
+ (struct libipw_auth *)header);
break;
case IEEE80211_STYPE_DISASSOC:
if (ieee->handle_disassoc != NULL)
ieee->handle_disassoc(ieee->dev,
- (struct ieee80211_disassoc *)
+ (struct libipw_disassoc *)
header);
break;
case IEEE80211_STYPE_ACTION:
- IEEE80211_DEBUG_MGMT("ACTION\n");
+ LIBIPW_DEBUG_MGMT("ACTION\n");
if (ieee->handle_action)
ieee->handle_action(ieee->dev,
- (struct ieee80211_action *)
+ (struct libipw_action *)
header, stats);
break;
case IEEE80211_STYPE_REASSOC_REQ:
- IEEE80211_DEBUG_MGMT("received reassoc (%d)\n",
+ LIBIPW_DEBUG_MGMT("received reassoc (%d)\n",
WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl)));
- IEEE80211_DEBUG_MGMT("%s: IEEE80211_REASSOC_REQ received\n",
+ LIBIPW_DEBUG_MGMT("%s: LIBIPW_REASSOC_REQ received\n",
ieee->dev->name);
if (ieee->handle_reassoc_request != NULL)
ieee->handle_reassoc_request(ieee->dev,
- (struct ieee80211_reassoc_request *)
+ (struct libipw_reassoc_request *)
header);
break;
case IEEE80211_STYPE_ASSOC_REQ:
- IEEE80211_DEBUG_MGMT("received assoc (%d)\n",
+ LIBIPW_DEBUG_MGMT("received assoc (%d)\n",
WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl)));
- IEEE80211_DEBUG_MGMT("%s: IEEE80211_ASSOC_REQ received\n",
+ LIBIPW_DEBUG_MGMT("%s: LIBIPW_ASSOC_REQ received\n",
ieee->dev->name);
if (ieee->handle_assoc_request != NULL)
ieee->handle_assoc_request(ieee->dev);
break;
case IEEE80211_STYPE_DEAUTH:
- IEEE80211_DEBUG_MGMT("DEAUTH\n");
+ LIBIPW_DEBUG_MGMT("DEAUTH\n");
if (ieee->handle_deauth != NULL)
ieee->handle_deauth(ieee->dev,
- (struct ieee80211_deauth *)
+ (struct libipw_deauth *)
header);
break;
default:
- IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
+ LIBIPW_DEBUG_MGMT("received UNKNOWN (%d)\n",
WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl)));
- IEEE80211_DEBUG_MGMT("%s: Unknown management packet: %d\n",
+ LIBIPW_DEBUG_MGMT("%s: Unknown management packet: %d\n",
ieee->dev->name,
WLAN_FC_GET_STYPE(le16_to_cpu
(header->frame_ctl)));
@@ -1792,6 +1793,6 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
}
}
-EXPORT_SYMBOL_GPL(ieee80211_rx_any);
-EXPORT_SYMBOL(ieee80211_rx_mgt);
-EXPORT_SYMBOL(ieee80211_rx);
+EXPORT_SYMBOL_GPL(libipw_rx_any);
+EXPORT_SYMBOL(libipw_rx_mgt);
+EXPORT_SYMBOL(libipw_rx);
diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c
index da2ad5437ce5..da8beac7fcf3 100644
--- a/drivers/net/wireless/ipw2x00/libipw_tx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_tx.c
@@ -19,7 +19,7 @@
file called LICENSE.
Contact Information:
- James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
******************************************************************************/
@@ -41,7 +41,7 @@
#include <linux/etherdevice.h>
#include <asm/uaccess.h>
-#include "ieee80211.h"
+#include "libipw.h"
/*
@@ -126,12 +126,12 @@ payload of each frame is reduced to 492 bytes.
static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
-static int ieee80211_copy_snap(u8 * data, __be16 h_proto)
+static int libipw_copy_snap(u8 * data, __be16 h_proto)
{
- struct ieee80211_snap_hdr *snap;
+ struct libipw_snap_hdr *snap;
u8 *oui;
- snap = (struct ieee80211_snap_hdr *)data;
+ snap = (struct libipw_snap_hdr *)data;
snap->dsap = 0xaa;
snap->ssap = 0xaa;
snap->ctrl = 0x03;
@@ -149,7 +149,7 @@ static int ieee80211_copy_snap(u8 * data, __be16 h_proto)
return SNAP_SIZE + sizeof(u16);
}
-static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
+static int libipw_encrypt_fragment(struct libipw_device *ieee,
struct sk_buff *frag, int hdr_len)
{
struct lib80211_crypt_data *crypt =
@@ -177,7 +177,7 @@ static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
return 0;
}
-void ieee80211_txb_free(struct ieee80211_txb *txb)
+void libipw_txb_free(struct libipw_txb *txb)
{
int i;
if (unlikely(!txb))
@@ -188,17 +188,17 @@ void ieee80211_txb_free(struct ieee80211_txb *txb)
kfree(txb);
}
-static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
+static struct libipw_txb *libipw_alloc_txb(int nr_frags, int txb_size,
int headroom, gfp_t gfp_mask)
{
- struct ieee80211_txb *txb;
+ struct libipw_txb *txb;
int i;
- txb = kmalloc(sizeof(struct ieee80211_txb) + (sizeof(u8 *) * nr_frags),
+ txb = kmalloc(sizeof(struct libipw_txb) + (sizeof(u8 *) * nr_frags),
gfp_mask);
if (!txb)
return NULL;
- memset(txb, 0, sizeof(struct ieee80211_txb));
+ memset(txb, 0, sizeof(struct libipw_txb));
txb->nr_frags = nr_frags;
txb->frag_size = txb_size;
@@ -220,7 +220,7 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
return txb;
}
-static int ieee80211_classify(struct sk_buff *skb)
+static int libipw_classify(struct sk_buff *skb)
{
struct ethhdr *eth;
struct iphdr *ip;
@@ -252,11 +252,11 @@ static int ieee80211_classify(struct sk_buff *skb)
/* Incoming skb is converted to a txb which consists of
* a block of 802.11 fragment packets (stored as skbs) */
-int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
+netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct ieee80211_device *ieee = netdev_priv(dev);
- struct ieee80211_txb *txb = NULL;
- struct ieee80211_hdr_3addrqos *frag_hdr;
+ struct libipw_device *ieee = netdev_priv(dev);
+ struct libipw_txb *txb = NULL;
+ struct libipw_hdr_3addrqos *frag_hdr;
int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
rts_required;
unsigned long flags;
@@ -264,7 +264,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
__be16 ether_type;
int bytes, fc, hdr_len;
struct sk_buff *skb_frag;
- struct ieee80211_hdr_3addrqos header = {/* Ensure zero initialized */
+ struct libipw_hdr_3addrqos header = {/* Ensure zero initialized */
.duration_id = 0,
.seq_ctl = 0,
.qos_ctl = 0
@@ -331,14 +331,14 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
memcpy(header.addr2, src, ETH_ALEN);
memcpy(header.addr3, ieee->bssid, ETH_ALEN);
}
- hdr_len = IEEE80211_3ADDR_LEN;
+ hdr_len = LIBIPW_3ADDR_LEN;
if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) {
fc |= IEEE80211_STYPE_QOS_DATA;
hdr_len += 2;
- skb->priority = ieee80211_classify(skb);
- header.qos_ctl |= cpu_to_le16(skb->priority & IEEE80211_QCTL_TID);
+ skb->priority = libipw_classify(skb);
+ header.qos_ctl |= cpu_to_le16(skb->priority & LIBIPW_QCTL_TID);
}
header.frame_ctl = cpu_to_le16(fc);
@@ -362,12 +362,12 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len);
memcpy(skb_put(skb_new, hdr_len), &header, hdr_len);
snapped = 1;
- ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)),
+ libipw_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)),
ether_type);
skb_copy_from_linear_data(skb, skb_put(skb_new, skb->len), skb->len);
res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv);
if (res < 0) {
- IEEE80211_ERROR("msdu encryption failed\n");
+ LIBIPW_ERROR("msdu encryption failed\n");
dev_kfree_skb_any(skb_new);
goto failed;
}
@@ -393,8 +393,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
* for it when determining the amount of payload space. */
bytes_per_frag = frag_size - hdr_len;
if (ieee->config &
- (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
- bytes_per_frag -= IEEE80211_FCS_LEN;
+ (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
+ bytes_per_frag -= LIBIPW_FCS_LEN;
/* Each fragment may need to have room for encryptiong
* pre/postfix */
@@ -417,14 +417,14 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
}
rts_required = (frag_size > ieee->rts
- && ieee->config & CFG_IEEE80211_RTS);
+ && ieee->config & CFG_LIBIPW_RTS);
if (rts_required)
nr_frags++;
/* When we allocate the TXB we allocate enough space for the reserve
* and full fragment bytes (bytes_per_frag doesn't include prefix,
* postfix, header, FCS, etc.) */
- txb = ieee80211_alloc_txb(nr_frags, frag_size,
+ txb = libipw_alloc_txb(nr_frags, frag_size,
ieee->tx_headroom, GFP_ATOMIC);
if (unlikely(!txb)) {
printk(KERN_WARNING "%s: Could not allocate TXB\n",
@@ -441,7 +441,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
if (rts_required) {
skb_frag = txb->fragments[0];
frag_hdr =
- (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
+ (struct libipw_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
/*
* Set header frame_ctl to the RTS.
@@ -456,7 +456,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
header.frame_ctl = cpu_to_le16(fc);
if (ieee->config &
- (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
+ (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
skb_put(skb_frag, 4);
txb->rts_included = 1;
@@ -472,7 +472,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
crypt->ops->extra_mpdu_prefix_len);
frag_hdr =
- (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
+ (struct libipw_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
memcpy(frag_hdr, &header, hdr_len);
/* If this is not the last fragment, then add the MOREFRAGS
@@ -487,7 +487,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (i == 0 && !snapped) {
- ieee80211_copy_snap(skb_put
+ libipw_copy_snap(skb_put
(skb_frag, SNAP_SIZE + sizeof(u16)),
ether_type);
bytes -= SNAP_SIZE + sizeof(u16);
@@ -501,7 +501,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
/* Encryption routine will move the header forward in order
* to insert the IV between the header and the payload */
if (host_encrypt)
- ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
+ libipw_encrypt_fragment(ieee, skb_frag, hdr_len);
else if (host_build_iv) {
atomic_inc(&crypt->refcnt);
if (crypt->ops->build_iv)
@@ -513,7 +513,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (ieee->config &
- (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
+ (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
skb_put(skb_frag, 4);
}
@@ -523,17 +523,17 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb_any(skb);
if (txb) {
- int ret = (*ieee->hard_start_xmit) (txb, dev, priority);
- if (ret == 0) {
+ netdev_tx_t ret = (*ieee->hard_start_xmit)(txb, dev, priority);
+ if (ret == NETDEV_TX_OK) {
dev->stats.tx_packets++;
dev->stats.tx_bytes += txb->payload_size;
- return 0;
+ return NETDEV_TX_OK;
}
- ieee80211_txb_free(txb);
+ libipw_txb_free(txb);
}
- return 0;
+ return NETDEV_TX_OK;
failed:
spin_unlock_irqrestore(&ieee->lock, flags);
@@ -541,6 +541,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_errors++;
return NETDEV_TX_BUSY;
}
-EXPORT_SYMBOL(ieee80211_xmit);
+EXPORT_SYMBOL(libipw_xmit);
-EXPORT_SYMBOL(ieee80211_txb_free);
+EXPORT_SYMBOL(libipw_txb_free);
diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c
index 3c0812db030a..4d89f66f53b2 100644
--- a/drivers/net/wireless/ipw2x00/libipw_wx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_wx.c
@@ -25,7 +25,7 @@
file called LICENSE.
Contact Information:
- James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
******************************************************************************/
@@ -37,9 +37,9 @@
#include <net/lib80211.h>
#include <linux/wireless.h>
-#include "ieee80211.h"
+#include "libipw.h"
-static const char *ieee80211_modes[] = {
+static const char *libipw_modes[] = {
"?", "a", "b", "ab", "g", "ag", "bg", "abg"
};
@@ -54,9 +54,9 @@ static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
}
#define MAX_CUSTOM_LEN 64
-static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
+static char *libipw_translate_scan(struct libipw_device *ieee,
char *start, char *stop,
- struct ieee80211_network *network,
+ struct libipw_network *network,
struct iw_request_info *info)
{
char custom[MAX_CUSTOM_LEN];
@@ -84,7 +84,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
/* Add the protocol name */
iwe.cmd = SIOCGIWNAME;
snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
- ieee80211_modes[network->mode]);
+ libipw_modes[network->mode]);
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
/* Add mode */
@@ -102,7 +102,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
/* Add channel and frequency */
/* Note : userspace automatically computes channel using iwrange */
iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
+ iwe.u.freq.m = libipw_channel_to_freq(ieee, network->channel);
iwe.u.freq.e = 6;
iwe.u.freq.i = 0;
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
@@ -155,7 +155,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
IW_QUAL_NOISE_UPDATED;
- if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) {
+ if (!(network->stats.mask & LIBIPW_STATMASK_RSSI)) {
iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
IW_QUAL_LEVEL_INVALID;
iwe.u.qual.qual = 0;
@@ -180,14 +180,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
iwe.u.qual.qual = 0;
}
- if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
+ if (!(network->stats.mask & LIBIPW_STATMASK_NOISE)) {
iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
iwe.u.qual.noise = 0;
} else {
iwe.u.qual.noise = network->stats.noise;
}
- if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) {
+ if (!(network->stats.mask & LIBIPW_STATMASK_SIGNAL)) {
iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
iwe.u.qual.level = 0;
} else {
@@ -237,14 +237,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
p = custom;
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
- if (ieee80211_get_channel_flags(ieee, network->channel) &
- IEEE80211_CH_INVALID) {
+ if (libipw_get_channel_flags(ieee, network->channel) &
+ LIBIPW_CH_INVALID) {
iwe.cmd = IWEVCUSTOM;
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
}
- if (ieee80211_get_channel_flags(ieee, network->channel) &
- IEEE80211_CH_RADAR_DETECT) {
+ if (libipw_get_channel_flags(ieee, network->channel) &
+ LIBIPW_CH_RADAR_DETECT) {
iwe.cmd = IWEVCUSTOM;
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
}
@@ -259,11 +259,11 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
#define SCAN_ITEM_SIZE 128
-int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
+int libipw_wx_get_scan(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct ieee80211_network *network;
+ struct libipw_network *network;
unsigned long flags;
int err = 0;
@@ -272,7 +272,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
int i = 0;
DECLARE_SSID_BUF(ssid);
- IEEE80211_DEBUG_WX("Getting scan\n");
+ LIBIPW_DEBUG_WX("Getting scan\n");
spin_lock_irqsave(&ieee->lock, flags);
@@ -285,10 +285,10 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
if (ieee->scan_age == 0 ||
time_after(network->last_scanned + ieee->scan_age, jiffies))
- ev = ieee80211_translate_scan(ieee, ev, stop, network,
+ ev = libipw_translate_scan(ieee, ev, stop, network,
info);
else {
- IEEE80211_DEBUG_SCAN("Not showing network '%s ("
+ LIBIPW_DEBUG_SCAN("Not showing network '%s ("
"%pM)' due to age (%ums).\n",
print_ssid(ssid, network->ssid,
network->ssid_len),
@@ -303,18 +303,18 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
wrqu->data.length = ev - extra;
wrqu->data.flags = 0;
- IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
+ LIBIPW_DEBUG_WX("exit: %d networks returned.\n", i);
return err;
}
-int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
+int libipw_wx_set_encode(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *keybuf)
{
struct iw_point *erq = &(wrqu->encoding);
struct net_device *dev = ieee->dev;
- struct ieee80211_security sec = {
+ struct libipw_security sec = {
.flags = 0
};
int i, key, key_provided, len;
@@ -322,7 +322,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
DECLARE_SSID_BUF(ssid);
- IEEE80211_DEBUG_WX("SET_ENCODE\n");
+ LIBIPW_DEBUG_WX("SET_ENCODE\n");
key = erq->flags & IW_ENCODE_INDEX;
if (key) {
@@ -335,18 +335,18 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
key = ieee->crypt_info.tx_keyidx;
}
- IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
+ LIBIPW_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
"provided" : "default");
crypt = &ieee->crypt_info.crypt[key];
if (erq->flags & IW_ENCODE_DISABLED) {
if (key_provided && *crypt) {
- IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
+ LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n",
key);
lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
} else
- IEEE80211_DEBUG_WX("Disabling encryption.\n");
+ LIBIPW_DEBUG_WX("Disabling encryption.\n");
/* Check all the keys to see if any are still configured,
* and if no key index was provided, de-init them all */
@@ -410,7 +410,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
/* If a new key was provided, set it up */
if (erq->length > 0) {
-#ifdef CONFIG_IEEE80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
DECLARE_SSID_BUF(ssid);
#endif
@@ -419,7 +419,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
if (len > erq->length)
memset(sec.keys[key] + erq->length, 0,
len - erq->length);
- IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
+ LIBIPW_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
key, print_ssid(ssid, sec.keys[key], len),
erq->length, len);
sec.key_sizes[key] = len;
@@ -438,7 +438,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
NULL, (*crypt)->priv);
if (len == 0) {
/* Set a default key of all 0 */
- IEEE80211_DEBUG_WX("Setting key %d to all "
+ LIBIPW_DEBUG_WX("Setting key %d to all "
"zero.\n", key);
memset(sec.keys[key], 0, 13);
(*crypt)->ops->set_key(sec.keys[key], 13, NULL,
@@ -449,7 +449,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
}
/* No key data - just set the default TX key index */
if (key_provided) {
- IEEE80211_DEBUG_WX("Setting key %d to default Tx "
+ LIBIPW_DEBUG_WX("Setting key %d to default Tx "
"key.\n", key);
ieee->crypt_info.tx_keyidx = key;
sec.active_key = key;
@@ -461,7 +461,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
WLAN_AUTH_SHARED_KEY;
sec.flags |= SEC_AUTH_MODE;
- IEEE80211_DEBUG_WX("Auth: %s\n",
+ LIBIPW_DEBUG_WX("Auth: %s\n",
sec.auth_mode == WLAN_AUTH_OPEN ?
"OPEN" : "SHARED KEY");
}
@@ -490,16 +490,16 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
return 0;
}
-int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
+int libipw_wx_get_encode(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *keybuf)
{
struct iw_point *erq = &(wrqu->encoding);
int len, key;
struct lib80211_crypt_data *crypt;
- struct ieee80211_security *sec = &ieee->sec;
+ struct libipw_security *sec = &ieee->sec;
- IEEE80211_DEBUG_WX("GET_ENCODE\n");
+ LIBIPW_DEBUG_WX("GET_ENCODE\n");
key = erq->flags & IW_ENCODE_INDEX;
if (key) {
@@ -532,7 +532,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
return 0;
}
-int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
+int libipw_wx_set_encodeext(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
@@ -545,7 +545,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
struct lib80211_crypto_ops *ops;
struct lib80211_crypt_data **crypt;
- struct ieee80211_security sec = {
+ struct libipw_security sec = {
.flags = 0,
};
@@ -611,7 +611,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
module = "lib80211_crypt_ccmp";
break;
default:
- IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
+ LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
dev->name, ext->alg);
ret = -EINVAL;
goto done;
@@ -623,7 +623,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
ops = lib80211_get_crypto_ops(alg);
}
if (ops == NULL) {
- IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
+ LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
dev->name, ext->alg);
ret = -EINVAL;
goto done;
@@ -653,7 +653,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
if (ext->key_len > 0 && (*crypt)->ops->set_key &&
(*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
(*crypt)->priv) < 0) {
- IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
+ LIBIPW_DEBUG_WX("%s: key setting failed\n", dev->name);
ret = -EINVAL;
goto done;
}
@@ -700,20 +700,20 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
if (ieee->reset_on_keychange &&
ieee->iw_mode != IW_MODE_INFRA &&
ieee->reset_port && ieee->reset_port(dev)) {
- IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
+ LIBIPW_DEBUG_WX("%s: reset_port failed\n", dev->name);
return -EINVAL;
}
return ret;
}
-int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
+int libipw_wx_get_encodeext(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- struct ieee80211_security *sec = &ieee->sec;
+ struct libipw_security *sec = &ieee->sec;
int idx, max_key_len;
max_key_len = encoding->length - sizeof(*ext);
@@ -763,9 +763,9 @@ int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
return 0;
}
-EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
-EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
+EXPORT_SYMBOL(libipw_wx_set_encodeext);
+EXPORT_SYMBOL(libipw_wx_get_encodeext);
-EXPORT_SYMBOL(ieee80211_wx_get_scan);
-EXPORT_SYMBOL(ieee80211_wx_set_encode);
-EXPORT_SYMBOL(ieee80211_wx_get_encode);
+EXPORT_SYMBOL(libipw_wx_get_scan);
+EXPORT_SYMBOL(libipw_wx_set_encode);
+EXPORT_SYMBOL(libipw_wx_get_encode);
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index e092af09d6bf..99310c033253 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -9,6 +9,9 @@ config IWLWIFI
config IWLWIFI_LEDS
bool "Enable LED support in iwlagn and iwl3945 drivers"
depends on IWLWIFI
+ default y
+ ---help---
+ Select this if you want LED support.
config IWLWIFI_SPECTRUM_MEASUREMENT
bool "Enable Spectrum Measurement in iwlagn driver"
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 7da52f1cc1d6..a95caa014143 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -46,7 +46,7 @@
#include "iwl-5000-hw.h"
/* Highest firmware API version supported */
-#define IWL1000_UCODE_API_MAX 2
+#define IWL1000_UCODE_API_MAX 3
/* Lowest firmware API version supported */
#define IWL1000_UCODE_API_MIN 1
@@ -55,19 +55,109 @@
#define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode"
#define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api)
+
+/*
+ * For 1000, use advance thermal throttling critical temperature threshold,
+ * but legacy thermal management implementation for now.
+ * This is for the reason of 1000 uCode using advance thermal throttling API
+ * but not implement ct_kill_exit based on ct_kill exit temperature
+ * so the thermal throttling will still based on legacy thermal throttling
+ * management.
+ * The code here need to be modified once 1000 uCode has the advanced thermal
+ * throttling algorithm in place
+ */
+static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
+{
+ /* want Celsius */
+ priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
+ priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+}
+
+/* NIC configuration for 1000 series */
+static void iwl1000_nic_config(struct iwl_priv *priv)
+{
+ iwl5000_nic_config(priv);
+
+ /* Setting digital SVR for 1000 card to 1.32V */
+ /* locking is acquired in iwl_set_bits_mask_prph() function */
+ iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG,
+ APMG_SVR_DIGITAL_VOLTAGE_1_32,
+ ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
+}
+
+static struct iwl_lib_ops iwl1000_lib = {
+ .set_hw_params = iwl5000_hw_set_hw_params,
+ .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
+ .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
+ .txq_set_sched = iwl5000_txq_set_sched,
+ .txq_agg_enable = iwl5000_txq_agg_enable,
+ .txq_agg_disable = iwl5000_txq_agg_disable,
+ .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
+ .txq_free_tfd = iwl_hw_txq_free_tfd,
+ .txq_init = iwl_hw_tx_queue_init,
+ .rx_handler_setup = iwl5000_rx_handler_setup,
+ .setup_deferred_work = iwl5000_setup_deferred_work,
+ .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+ .load_ucode = iwl5000_load_ucode,
+ .init_alive_start = iwl5000_init_alive_start,
+ .alive_notify = iwl5000_alive_notify,
+ .send_tx_power = iwl5000_send_tx_power,
+ .update_chain_flags = iwl_update_chain_flags,
+ .apm_ops = {
+ .init = iwl5000_apm_init,
+ .reset = iwl5000_apm_reset,
+ .stop = iwl5000_apm_stop,
+ .config = iwl1000_nic_config,
+ .set_pwr_src = iwl_set_pwr_src,
+ },
+ .eeprom_ops = {
+ .regulatory_bands = {
+ EEPROM_5000_REG_BAND_1_CHANNELS,
+ EEPROM_5000_REG_BAND_2_CHANNELS,
+ EEPROM_5000_REG_BAND_3_CHANNELS,
+ EEPROM_5000_REG_BAND_4_CHANNELS,
+ EEPROM_5000_REG_BAND_5_CHANNELS,
+ EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
+ EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+ },
+ .verify_signature = iwlcore_eeprom_verify_signature,
+ .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+ .release_semaphore = iwlcore_eeprom_release_semaphore,
+ .calib_version = iwl5000_eeprom_calib_version,
+ .query_addr = iwl5000_eeprom_query_addr,
+ },
+ .post_associate = iwl_post_associate,
+ .isr = iwl_isr_ict,
+ .config_ap = iwl_config_ap,
+ .temp_ops = {
+ .temperature = iwl5000_temperature,
+ .set_ct_kill = iwl1000_set_ct_threshold,
+ },
+};
+
+static struct iwl_ops iwl1000_ops = {
+ .ucode = &iwl5000_ucode,
+ .lib = &iwl1000_lib,
+ .hcmd = &iwl5000_hcmd,
+ .utils = &iwl5000_hcmd_utils,
+};
+
struct iwl_cfg iwl1000_bgn_cfg = {
.name = "1000 Series BGN",
.fw_name_pre = IWL1000_FW_PRE,
.ucode_api_max = IWL1000_UCODE_API_MAX,
.ucode_api_min = IWL1000_UCODE_API_MIN,
.sku = IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl5000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .ops = &iwl1000_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_A,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = true,
+ .max_ll_items = OTP_MAX_LL_ITEMS_1000,
+ .shadow_ram_support = false,
+ .ht_greenfield_support = true,
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 73f93a0ff2df..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 {
* in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
* txpower (MSB).
*
- * Entries immediately below are for 20 MHz channel width. FAT (40 MHz)
+ * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz)
* channels (only for 4965, not supported by 3945) appear later in the EEPROM.
*
* 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
@@ -232,9 +232,8 @@ struct iwl3945_eeprom {
#define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */
#define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */
-#define TFD_QUEUE_MIN 0
-#define TFD_QUEUE_MAX 5 /* 4 DATA + 1 CMD */
-
+/* 4 DATA + 1 CMD. There are 2 HCCA queues that are not used. */
+#define IWL39_NUM_QUEUES 5
#define IWL_NUM_SCAN_RATES (2)
#define IWL_DEFAULT_TX_RETRY 15
@@ -280,8 +279,6 @@ struct iwl3945_eeprom {
/* Size of uCode instruction memory in bootstrap state machine */
#define IWL39_MAX_BSM_SIZE IWL39_RTC_INST_SIZE
-#define IWL39_MAX_NUM_QUEUES 8
-
static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr)
{
return (addr >= IWL39_RTC_DATA_LOWER_BOUND) &&
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index 225e5f889346..8c29ded7d02c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -79,11 +79,10 @@ static const struct {
#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/
#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
-static int iwl3945_led_cmd_callback(struct iwl_priv *priv,
- struct iwl_cmd *cmd,
- struct sk_buff *skb)
+static void iwl3945_led_cmd_callback(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb)
{
- return 1;
}
static inline int iwl3945_brightness_to_idx(enum led_brightness brightness)
@@ -99,8 +98,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv,
.id = REPLY_LEDS_CMD,
.len = sizeof(struct iwl_led_cmd),
.data = led_cmd,
- .meta.flags = CMD_ASYNC,
- .meta.u.callback = iwl3945_led_cmd_callback,
+ .flags = CMD_ASYNC,
+ .callback = iwl3945_led_cmd_callback,
};
return iwl_send_cmd(priv, &cmd);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index 5eb538d18a80..a16bd4147eac 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -673,33 +673,17 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
s8 scale_action = 0;
unsigned long flags;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- u16 fc;
- u16 rate_mask = 0;
+ u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0;
s8 max_rate_idx = -1;
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
IWL_DEBUG_RATE(priv, "enter\n");
- if (sta)
- rate_mask = sta->supp_rates[sband->band];
-
- /* Send management frames and NO_ACK data using lowest rate. */
- fc = le16_to_cpu(hdr->frame_control);
- if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
- info->flags & IEEE80211_TX_CTL_NO_ACK ||
- !sta || !priv_sta) {
- IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n");
- if (!rate_mask)
- info->control.rates[0].idx =
- rate_lowest_index(sband, NULL);
- else
- info->control.rates[0].idx =
- rate_lowest_index(sband, sta);
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- info->control.rates[0].count = 1;
+ if (rate_control_send_low(sta, priv_sta, txrc))
return;
- }
+
+ rate_mask = sta->supp_rates[sband->band];
/* get user max rate if set */
max_rate_idx = txrc->max_rate_idx;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 46288e724889..e9a685d8e3a1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -349,12 +349,13 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
*
*****************************************************************************/
-void iwl3945_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
{
struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
(int)sizeof(struct iwl3945_notif_statistics),
- le32_to_cpu(pkt->len));
+ le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39));
@@ -509,7 +510,7 @@ static void iwl3945_dbg_report_frame(struct iwl_priv *priv,
struct iwl_rx_packet *pkt,
struct ieee80211_hdr *header, int group100)
{
- if (priv->debug_level & IWL_DL_RX)
+ if (iwl_get_debug_level(priv) & IWL_DL_RX)
_iwl3945_dbg_report_frame(priv, pkt, header, group100);
}
@@ -544,9 +545,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
struct ieee80211_rx_status *stats)
{
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-#ifdef CONFIG_IWLWIFI_LEDS
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
-#endif
struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
short len = le16_to_cpu(rx_hdr->len);
@@ -577,7 +576,10 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
if (ieee80211_is_data(hdr->frame_control))
priv->rxtxpackets += len;
#endif
- ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ iwl_update_stats(priv, false, hdr->frame_control, len);
+
+ memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb);
rxb->skb = NULL;
}
@@ -678,6 +680,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
/* Set "1" to report good data frames in groups of 100 */
iwl3945_dbg_report_frame(priv, pkt, header, 1);
+ iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header);
if (network_packet) {
priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
@@ -748,8 +751,8 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
/* Unmap tx_cmd */
if (counter)
pci_unmap_single(dev,
- pci_unmap_addr(&txq->cmd[index]->meta, mapping),
- pci_unmap_len(&txq->cmd[index]->meta, len),
+ pci_unmap_addr(&txq->meta[index], mapping),
+ pci_unmap_len(&txq->meta[index], len),
PCI_DMA_TODEVICE);
/* unmap chunks if any */
@@ -773,9 +776,11 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
* iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
*
*/
-void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd,
- struct ieee80211_tx_info *info,
- struct ieee80211_hdr *hdr, int sta_id, int tx_id)
+void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_hdr *hdr,
+ int sta_id, int tx_id)
{
u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value;
u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1);
@@ -962,7 +967,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
goto error;
/* Tx queue(s) */
- for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) {
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
@@ -1139,7 +1144,7 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
int txq_id;
/* Tx queues */
- for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++)
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
if (txq_id == IWL_CMD_QUEUE_NUM)
iwl_cmd_queue_free(priv);
else
@@ -1155,7 +1160,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
iwl_write_prph(priv, ALM_SCD_MODE_REG, 0);
/* reset TFD queues */
- for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) {
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0);
iwl_poll_direct_bit(priv, FH39_TSSR_TX_STATUS,
FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
@@ -1857,7 +1862,7 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
struct iwl_host_cmd cmd = {
.id = REPLY_RXON_ASSOC,
.len = sizeof(rxon_assoc),
- .meta.flags = CMD_WANT_SKB,
+ .flags = CMD_WANT_SKB,
.data = &rxon_assoc,
};
const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
@@ -1881,14 +1886,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
if (rc)
return rc;
- res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n");
rc = -EIO;
}
priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.meta.u.skb);
+ dev_kfree_skb_any(cmd.reply_skb);
return rc;
}
@@ -1986,7 +1991,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
staging_rxon->reserved4 = 0;
staging_rxon->reserved5 = 0;
- iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+ iwl_set_rxon_hwcrypto(priv, !iwl3945_mod_params.sw_crypto);
/* Apply the new configuration */
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
@@ -2551,7 +2556,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
}
/* Assign number of Usable TX queues */
- priv->hw_params.max_txq_num = TFD_QUEUE_MAX;
+ priv->hw_params.max_txq_num = IWL39_NUM_QUEUES;
priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K;
@@ -2562,6 +2567,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.bcast_sta_id = IWL3945_BROADCAST_ID;
priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR;
+ priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL;
return 0;
}
@@ -2784,11 +2790,50 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
return 0;
}
+#define IWL3945_UCODE_GET(item) \
+static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+ u32 api_ver) \
+{ \
+ return le32_to_cpu(ucode->u.v1.item); \
+}
+
+static u32 iwl3945_ucode_get_header_size(u32 api_ver)
+{
+ return UCODE_HEADER_SIZE(1);
+}
+static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return 0;
+}
+static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return (u8 *) ucode->u.v1.data;
+}
+
+IWL3945_UCODE_GET(inst_size);
+IWL3945_UCODE_GET(data_size);
+IWL3945_UCODE_GET(init_size);
+IWL3945_UCODE_GET(init_data_size);
+IWL3945_UCODE_GET(boot_size);
+
static struct iwl_hcmd_ops iwl3945_hcmd = {
.rxon_assoc = iwl3945_send_rxon_assoc,
.commit_rxon = iwl3945_commit_rxon,
};
+static struct iwl_ucode_ops iwl3945_ucode = {
+ .get_header_size = iwl3945_ucode_get_header_size,
+ .get_build = iwl3945_ucode_get_build,
+ .get_inst_size = iwl3945_ucode_get_inst_size,
+ .get_data_size = iwl3945_ucode_get_data_size,
+ .get_init_size = iwl3945_ucode_get_init_size,
+ .get_init_data_size = iwl3945_ucode_get_init_data_size,
+ .get_boot_size = iwl3945_ucode_get_boot_size,
+ .get_data = iwl3945_ucode_get_data,
+};
+
static struct iwl_lib_ops iwl3945_lib = {
.txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl3945_hw_txq_free_tfd,
@@ -2808,8 +2853,8 @@ static struct iwl_lib_ops iwl3945_lib = {
EEPROM_REGULATORY_BAND_3_CHANNELS,
EEPROM_REGULATORY_BAND_4_CHANNELS,
EEPROM_REGULATORY_BAND_5_CHANNELS,
- EEPROM_REGULATORY_BAND_NO_FAT,
- EEPROM_REGULATORY_BAND_NO_FAT,
+ EEPROM_REGULATORY_BAND_NO_HT40,
+ EEPROM_REGULATORY_BAND_NO_HT40,
},
.verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwl3945_eeprom_acquire_semaphore,
@@ -2829,6 +2874,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
};
static struct iwl_ops iwl3945_ops = {
+ .ucode = &iwl3945_ucode,
.lib = &iwl3945_lib,
.hcmd = &iwl3945_hcmd,
.utils = &iwl3945_hcmd_utils,
@@ -2844,7 +2890,8 @@ static struct iwl_cfg iwl3945_bg_cfg = {
.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
.ops = &iwl3945_ops,
.mod_params = &iwl3945_mod_params,
- .use_isr_legacy = true
+ .use_isr_legacy = true,
+ .ht_greenfield_support = false,
};
static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2857,7 +2904,8 @@ static struct iwl_cfg iwl3945_abg_cfg = {
.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
.ops = &iwl3945_ops,
.mod_params = &iwl3945_mod_params,
- .use_isr_legacy = true
+ .use_isr_legacy = true,
+ .ht_greenfield_support = false,
};
struct pci_device_id iwl3945_hw_card_ids[] = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 2de6471d4be9..f24036909916 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -111,9 +111,6 @@ enum iwl3945_antenna {
#define IWL_TX_FIFO_HCCA_2 6
#define IWL_TX_FIFO_NONE 7
-/* Minimum number of queues. MAX_NUM is defined in hw specific files */
-#define IWL39_MIN_NUM_QUEUES 4
-
#define IEEE80211_DATA_LEN 2304
#define IEEE80211_4ADDR_LEN 30
#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)
@@ -257,10 +254,11 @@ extern int iwl3945_hw_tx_queue_init(struct iwl_priv *priv,
struct iwl_tx_queue *txq);
extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl_priv *priv,
struct iwl3945_frame *frame, u8 rate);
-void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd,
- struct ieee80211_tx_info *info,
- struct ieee80211_hdr *hdr,
- int sta_id, int tx_id);
+void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_hdr *hdr,
+ int sta_id, int tx_id);
extern int iwl3945_hw_reg_send_txpower(struct iwl_priv *priv);
extern int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
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)
*
* 1) Regulatory information (max txpower and channel usage flags) is provided
* separately for each channel that can possibly supported by 4965.
- * 40 MHz wide (.11n fat) channels are listed separately from 20 MHz
+ * 40 MHz wide (.11n HT40) channels are listed separately from 20 MHz
* (legacy) channels.
*
* 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)
* no reduction (such as with regulatory txpower limits) is required.
*
* Saturation and Backoff values apply equally to 20 Mhz (legacy) channel
- * widths and 40 Mhz (.11n fat) channel widths; there is no separate
- * factory measurement for fat channels.
+ * widths and 40 Mhz (.11n HT40) channel widths; there is no separate
+ * factory measurement for ht40 channels.
*
* The result of this step is the final target txpower. The rest of
* 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 8f3d4bc6a03f..6a13bfbc9d98 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -46,7 +46,7 @@
#include "iwl-sta.h"
static int iwl4965_send_tx_power(struct iwl_priv *priv);
-static int iwl4965_hw_get_temperature(const struct iwl_priv *priv);
+static int iwl4965_hw_get_temperature(struct iwl_priv *priv);
/* Highest firmware API version supported */
#define IWL4965_UCODE_API_MAX 2
@@ -293,7 +293,7 @@ restart:
queue_work(priv->workqueue, &priv->restart);
}
-static bool is_fat_channel(__le32 rxon_flags)
+static bool is_ht40_channel(__le32 rxon_flags)
{
int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK)
>> RXON_FLG_CHANNEL_MODE_POS;
@@ -728,7 +728,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
.min_nrg_cck = 97,
- .max_nrg_cck = 0,
+ .max_nrg_cck = 0, /* not used, set to 0 */
.auto_corr_min_ofdm = 85,
.auto_corr_min_ofdm_mrc = 170,
@@ -752,7 +752,8 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
static void iwl4965_set_ct_threshold(struct iwl_priv *priv)
{
/* want Kelvin */
- priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD);
+ priv->hw_params.ct_kill_threshold =
+ CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY);
}
/**
@@ -781,7 +782,7 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE;
priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE;
priv->hw_params.max_bsm_size = BSM_SRAM_SIZE;
- priv->hw_params.fat_channel = BIT(IEEE80211_BAND_5GHZ);
+ priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_5GHZ);
priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
@@ -1241,7 +1242,7 @@ static const struct gain_entry gain_table[2][108] = {
};
static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
- u8 is_fat, u8 ctrl_chan_high,
+ u8 is_ht40, u8 ctrl_chan_high,
struct iwl4965_tx_power_db *tx_power_tbl)
{
u8 saturation_power;
@@ -1273,8 +1274,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
user_target_power = 2 * priv->tx_power_user_lmt;
/* Get current (RXON) channel, band, width */
- IWL_DEBUG_TXPOWER(priv, "chan %d band %d is_fat %d\n", channel, band,
- is_fat);
+ IWL_DEBUG_TXPOWER(priv, "chan %d band %d is_ht40 %d\n", channel, band,
+ is_ht40);
ch_info = iwl_get_channel_info(priv, priv->band, channel);
@@ -1293,7 +1294,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
IWL_DEBUG_TXPOWER(priv, "channel %d belongs to txatten group %d\n",
channel, txatten_grp);
- if (is_fat) {
+ if (is_ht40) {
if (ctrl_chan_high)
channel -= 2;
else
@@ -1317,8 +1318,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
/* regulatory txpower limits ... reg_limit values are in half-dBm,
* max_power_avg values are in dBm, convert * 2 */
- if (is_fat)
- reg_limit = ch_info->fat_max_power_avg * 2;
+ if (is_ht40)
+ reg_limit = ch_info->ht40_max_power_avg * 2;
else
reg_limit = ch_info->max_power_avg * 2;
@@ -1484,7 +1485,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
/**
* iwl4965_send_tx_power - Configure the TXPOWER level user limit
*
- * Uses the active RXON for channel, band, and characteristics (fat, high)
+ * Uses the active RXON for channel, band, and characteristics (ht40, high)
* The power limit is taken from priv->tx_power_user_lmt.
*/
static int iwl4965_send_tx_power(struct iwl_priv *priv)
@@ -1492,7 +1493,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
struct iwl4965_txpowertable_cmd cmd = { 0 };
int ret;
u8 band = 0;
- bool is_fat = false;
+ bool is_ht40 = false;
u8 ctrl_chan_high = 0;
if (test_bit(STATUS_SCANNING, &priv->status)) {
@@ -1505,9 +1506,9 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
band = priv->band == IEEE80211_BAND_2GHZ;
- is_fat = is_fat_channel(priv->active_rxon.flags);
+ is_ht40 = is_ht40_channel(priv->active_rxon.flags);
- if (is_fat &&
+ if (is_ht40 &&
(priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
ctrl_chan_high = 1;
@@ -1516,7 +1517,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
ret = iwl4965_fill_txpower_tbl(priv, band,
le16_to_cpu(priv->active_rxon.channel),
- is_fat, ctrl_chan_high, &cmd.tx_power);
+ is_ht40, ctrl_chan_high, &cmd.tx_power);
if (ret)
goto out;
@@ -1570,7 +1571,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
{
int rc;
u8 band = 0;
- bool is_fat = false;
+ bool is_ht40 = false;
u8 ctrl_chan_high = 0;
struct iwl4965_channel_switch_cmd cmd = { 0 };
const struct iwl_channel_info *ch_info;
@@ -1579,9 +1580,9 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
ch_info = iwl_get_channel_info(priv, priv->band, channel);
- is_fat = is_fat_channel(priv->staging_rxon.flags);
+ is_ht40 = is_ht40_channel(priv->staging_rxon.flags);
- if (is_fat &&
+ if (is_ht40 &&
(priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
ctrl_chan_high = 1;
@@ -1596,7 +1597,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
else
cmd.expect_beacon = 1;
- rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_fat,
+ rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40,
ctrl_chan_high, &cmd.tx_power);
if (rc) {
IWL_DEBUG_11H(priv, "error:%d fill txpower_tbl\n", rc);
@@ -1655,7 +1656,7 @@ static s32 sign_extend(u32 oper, int index)
*
* A return of <0 indicates bogus data in the statistics
*/
-static int iwl4965_hw_get_temperature(const struct iwl_priv *priv)
+static int iwl4965_hw_get_temperature(struct iwl_priv *priv)
{
s32 temperature;
s32 vt;
@@ -1663,8 +1664,8 @@ static int iwl4965_hw_get_temperature(const struct iwl_priv *priv)
u32 R4;
if (test_bit(STATUS_TEMPERATURE, &priv->status) &&
- (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)) {
- IWL_DEBUG_TEMP(priv, "Running FAT temperature calibration\n");
+ (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)) {
+ IWL_DEBUG_TEMP(priv, "Running HT40 temperature calibration\n");
R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]);
@@ -1772,6 +1773,7 @@ static void iwl4965_temperature_calib(struct iwl_priv *priv)
}
priv->temperature = temp;
+ iwl_tt_handler(priv);
set_bit(STATUS_TEMPERATURE, &priv->status);
if (!priv->disable_tx_power_cal &&
@@ -2221,12 +2223,50 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
cancel_work_sync(&priv->txpower_work);
}
+#define IWL4965_UCODE_GET(item) \
+static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+ u32 api_ver) \
+{ \
+ return le32_to_cpu(ucode->u.v1.item); \
+}
+
+static u32 iwl4965_ucode_get_header_size(u32 api_ver)
+{
+ return UCODE_HEADER_SIZE(1);
+}
+static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return 0;
+}
+static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return (u8 *) ucode->u.v1.data;
+}
+
+IWL4965_UCODE_GET(inst_size);
+IWL4965_UCODE_GET(data_size);
+IWL4965_UCODE_GET(init_size);
+IWL4965_UCODE_GET(init_data_size);
+IWL4965_UCODE_GET(boot_size);
+
static struct iwl_hcmd_ops iwl4965_hcmd = {
.rxon_assoc = iwl4965_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
.set_rxon_chain = iwl_set_rxon_chain,
};
+static struct iwl_ucode_ops iwl4965_ucode = {
+ .get_header_size = iwl4965_ucode_get_header_size,
+ .get_build = iwl4965_ucode_get_build,
+ .get_inst_size = iwl4965_ucode_get_inst_size,
+ .get_data_size = iwl4965_ucode_get_data_size,
+ .get_init_size = iwl4965_ucode_get_init_size,
+ .get_init_data_size = iwl4965_ucode_get_init_data_size,
+ .get_boot_size = iwl4965_ucode_get_boot_size,
+ .get_data = iwl4965_ucode_get_data,
+};
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.get_hcmd_size = iwl4965_get_hcmd_size,
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
@@ -2266,8 +2306,8 @@ static struct iwl_lib_ops iwl4965_lib = {
EEPROM_REGULATORY_BAND_3_CHANNELS,
EEPROM_REGULATORY_BAND_4_CHANNELS,
EEPROM_REGULATORY_BAND_5_CHANNELS,
- EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS,
- EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS
+ EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS,
+ EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS
},
.verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
@@ -2287,6 +2327,7 @@ static struct iwl_lib_ops iwl4965_lib = {
};
static struct iwl_ops iwl4965_ops = {
+ .ucode = &iwl4965_ucode,
.lib = &iwl4965_lib,
.hcmd = &iwl4965_hcmd,
.utils = &iwl4965_hcmd_utils,
@@ -2303,7 +2344,8 @@ struct iwl_cfg iwl4965_agn_cfg = {
.eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
.ops = &iwl4965_ops,
.mod_params = &iwl4965_mod_params,
- .use_isr_legacy = true
+ .use_isr_legacy = true,
+ .ht_greenfield_support = false,
};
/* Module firmware */
@@ -2313,8 +2355,6 @@ module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(debug, iwl4965_mod_params.debug, uint, 0444);
-MODULE_PARM_DESC(debug, "debug output mask");
module_param_named(
disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index b3c648ce8c7b..1d539e3b8db1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -91,7 +91,7 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv)
}
-static int iwl5000_apm_init(struct iwl_priv *priv)
+int iwl5000_apm_init(struct iwl_priv *priv)
{
int ret = 0;
@@ -137,7 +137,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
}
/* FIXME: this is identical to 4965 */
-static void iwl5000_apm_stop(struct iwl_priv *priv)
+void iwl5000_apm_stop(struct iwl_priv *priv)
{
unsigned long flags;
@@ -156,7 +156,7 @@ static void iwl5000_apm_stop(struct iwl_priv *priv)
}
-static int iwl5000_apm_reset(struct iwl_priv *priv)
+int iwl5000_apm_reset(struct iwl_priv *priv)
{
int ret = 0;
@@ -198,7 +198,8 @@ out:
}
-static void iwl5000_nic_config(struct iwl_priv *priv)
+/* NIC configuration for 5000 series and up */
+void iwl5000_nic_config(struct iwl_priv *priv)
{
unsigned long flags;
u16 radio_cfg;
@@ -239,11 +240,11 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
+
spin_unlock_irqrestore(&priv->lock, flags);
}
-
/*
* EEPROM
*/
@@ -283,7 +284,7 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
return (address & ADDRESS_MSK) + (offset << 1);
}
-static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
+u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
{
struct iwl_eeprom_calib_hdr {
u8 version;
@@ -388,7 +389,7 @@ void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.min_nrg_cck = 95,
- .max_nrg_cck = 0,
+ .max_nrg_cck = 0, /* not used, set to 0 */
.auto_corr_min_ofdm = 90,
.auto_corr_min_ofdm_mrc = 170,
.auto_corr_min_ofdm_x1 = 120,
@@ -407,7 +408,29 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.nrg_th_ofdm = 95,
};
-static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
+static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
+ .min_nrg_cck = 95,
+ .max_nrg_cck = 0, /* not used, set to 0 */
+ .auto_corr_min_ofdm = 90,
+ .auto_corr_min_ofdm_mrc = 170,
+ .auto_corr_min_ofdm_x1 = 105,
+ .auto_corr_min_ofdm_mrc_x1 = 220,
+
+ .auto_corr_max_ofdm = 120,
+ .auto_corr_max_ofdm_mrc = 210,
+ /* max = min for performance bug in 5150 DSP */
+ .auto_corr_max_ofdm_x1 = 105,
+ .auto_corr_max_ofdm_mrc_x1 = 220,
+
+ .auto_corr_min_cck = 125,
+ .auto_corr_max_cck = 200,
+ .auto_corr_min_cck_mrc = 170,
+ .auto_corr_max_cck_mrc = 400,
+ .nrg_th_cck = 95,
+ .nrg_th_ofdm = 95,
+};
+
+const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
size_t offset)
{
u32 address = eeprom_indirect_address(priv, offset);
@@ -418,7 +441,7 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
{
const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
- s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) -
+ s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
iwl_temp_calib_to_offset(priv);
priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
@@ -427,7 +450,7 @@ static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
{
/* want Celsius */
- priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
+ priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
}
/*
@@ -471,7 +494,7 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv,
{
struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
- int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK;
+ int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
int index;
/* reduce the size of the length field itself */
@@ -602,7 +625,7 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv,
return ret;
}
-static int iwl5000_load_ucode(struct iwl_priv *priv)
+int iwl5000_load_ucode(struct iwl_priv *priv)
{
int ret = 0;
@@ -629,7 +652,7 @@ static int iwl5000_load_ucode(struct iwl_priv *priv)
return ret;
}
-static void iwl5000_init_alive_start(struct iwl_priv *priv)
+void iwl5000_init_alive_start(struct iwl_priv *priv)
{
int ret = 0;
@@ -705,7 +728,7 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv)
sizeof(coex_cmd), &coex_cmd);
}
-static int iwl5000_alive_notify(struct iwl_priv *priv)
+int iwl5000_alive_notify(struct iwl_priv *priv)
{
u32 a;
unsigned long flags;
@@ -792,7 +815,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
return 0;
}
-static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
+int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
{
if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) ||
(priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
@@ -822,12 +845,10 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
}
priv->hw_params.max_bsm_size = 0;
- priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) |
+ priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
BIT(IEEE80211_BAND_5GHZ);
priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
- priv->hw_params.sens = &iwl5000_sensitivity;
-
priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
@@ -836,9 +857,11 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+ /* Set initial sensitivity parameters */
/* Set initial calibration set */
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
case CSR_HW_REV_TYPE_5150:
+ priv->hw_params.sens = &iwl5150_sensitivity;
priv->hw_params.calib_init_cfg =
BIT(IWL_CALIB_DC) |
BIT(IWL_CALIB_LO) |
@@ -847,6 +870,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
break;
default:
+ priv->hw_params.sens = &iwl5000_sensitivity;
priv->hw_params.calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
@@ -862,7 +886,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
/**
* iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
*/
-static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
u16 byte_cnt)
{
@@ -902,7 +926,7 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
}
-static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
struct iwl_tx_queue *txq)
{
struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
@@ -957,7 +981,7 @@ static void iwl5000_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
(1 << IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
}
-static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
+int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
int tx_fifo, int sta_id, int tid, u16 ssn_idx)
{
unsigned long flags;
@@ -1018,7 +1042,7 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
return 0;
}
-static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo)
{
if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
@@ -1061,7 +1085,7 @@ u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
* Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
* must be called under priv->lock and mac access
*/
-static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
+void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
{
iwl_write_prph(priv, IWL50_SCD_TXFACT, mask);
}
@@ -1282,13 +1306,13 @@ u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
return len;
}
-static void iwl5000_setup_deferred_work(struct iwl_priv *priv)
+void iwl5000_setup_deferred_work(struct iwl_priv *priv)
{
/* in 5000 the tx power calibration is done in uCode */
priv->disable_tx_power_cal = 1;
}
-static void iwl5000_rx_handler_setup(struct iwl_priv *priv)
+void iwl5000_rx_handler_setup(struct iwl_priv *priv)
{
/* init calibration handlers */
priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
@@ -1299,7 +1323,7 @@ static void iwl5000_rx_handler_setup(struct iwl_priv *priv)
}
-static int iwl5000_hw_valid_rtc_data_addr(u32 addr)
+int iwl5000_hw_valid_rtc_data_addr(u32 addr)
{
return (addr >= IWL50_RTC_DATA_LOWER_BOUND) &&
(addr < IWL50_RTC_DATA_UPPER_BOUND);
@@ -1351,7 +1375,7 @@ static int iwl5000_send_rxon_assoc(struct iwl_priv *priv)
return ret;
}
-static int iwl5000_send_tx_power(struct iwl_priv *priv)
+int iwl5000_send_tx_power(struct iwl_priv *priv)
{
struct iwl5000_tx_power_dbm_cmd tx_power_cmd;
u8 tx_ant_cfg_cmd;
@@ -1371,10 +1395,11 @@ static int iwl5000_send_tx_power(struct iwl_priv *priv)
NULL);
}
-static void iwl5000_temperature(struct iwl_priv *priv)
+void iwl5000_temperature(struct iwl_priv *priv)
{
/* store temperature from statistics (in Celsius) */
priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
+ iwl_tt_handler(priv);
}
static void iwl5150_temperature(struct iwl_priv *priv)
@@ -1386,6 +1411,7 @@ static void iwl5150_temperature(struct iwl_priv *priv)
vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
/* now vt hold the temperature in Kelvin */
priv->temperature = KELVIN_TO_CELSIUS(vt);
+ iwl_tt_handler(priv);
}
/* Calc max signal level (dBm) among 3 possible receivers */
@@ -1426,6 +1452,44 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
return max_rssi - agc - IWL49_RSSI_OFFSET;
}
+#define IWL5000_UCODE_GET(item) \
+static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+ u32 api_ver) \
+{ \
+ if (api_ver <= 2) \
+ return le32_to_cpu(ucode->u.v1.item); \
+ return le32_to_cpu(ucode->u.v2.item); \
+}
+
+static u32 iwl5000_ucode_get_header_size(u32 api_ver)
+{
+ if (api_ver <= 2)
+ return UCODE_HEADER_SIZE(1);
+ return UCODE_HEADER_SIZE(2);
+}
+
+static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ if (api_ver <= 2)
+ return 0;
+ return le32_to_cpu(ucode->u.v2.build);
+}
+
+static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ if (api_ver <= 2)
+ return (u8 *) ucode->u.v1.data;
+ return (u8 *) ucode->u.v2.data;
+}
+
+IWL5000_UCODE_GET(inst_size);
+IWL5000_UCODE_GET(data_size);
+IWL5000_UCODE_GET(init_size);
+IWL5000_UCODE_GET(init_data_size);
+IWL5000_UCODE_GET(boot_size);
+
struct iwl_hcmd_ops iwl5000_hcmd = {
.rxon_assoc = iwl5000_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
@@ -1441,6 +1505,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
.calc_rssi = iwl5000_calc_rssi,
};
+struct iwl_ucode_ops iwl5000_ucode = {
+ .get_header_size = iwl5000_ucode_get_header_size,
+ .get_build = iwl5000_ucode_get_build,
+ .get_inst_size = iwl5000_ucode_get_inst_size,
+ .get_data_size = iwl5000_ucode_get_data_size,
+ .get_init_size = iwl5000_ucode_get_init_size,
+ .get_init_data_size = iwl5000_ucode_get_init_data_size,
+ .get_boot_size = iwl5000_ucode_get_boot_size,
+ .get_data = iwl5000_ucode_get_data,
+};
+
struct iwl_lib_ops iwl5000_lib = {
.set_hw_params = iwl5000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
@@ -1473,8 +1548,8 @@ struct iwl_lib_ops iwl5000_lib = {
EEPROM_5000_REG_BAND_3_CHANNELS,
EEPROM_5000_REG_BAND_4_CHANNELS,
EEPROM_5000_REG_BAND_5_CHANNELS,
- EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
- EEPROM_5000_REG_BAND_52_FAT_CHANNELS
+ EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
+ EEPROM_5000_REG_BAND_52_HT40_CHANNELS
},
.verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
@@ -1523,8 +1598,8 @@ static struct iwl_lib_ops iwl5150_lib = {
EEPROM_5000_REG_BAND_3_CHANNELS,
EEPROM_5000_REG_BAND_4_CHANNELS,
EEPROM_5000_REG_BAND_5_CHANNELS,
- EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
- EEPROM_5000_REG_BAND_52_FAT_CHANNELS
+ EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
+ EEPROM_5000_REG_BAND_52_HT40_CHANNELS
},
.verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
@@ -1542,12 +1617,14 @@ static struct iwl_lib_ops iwl5150_lib = {
};
struct iwl_ops iwl5000_ops = {
+ .ucode = &iwl5000_ucode,
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
};
static struct iwl_ops iwl5150_ops = {
+ .ucode = &iwl5000_ucode,
.lib = &iwl5150_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
@@ -1576,6 +1653,7 @@ struct iwl_cfg iwl5300_agn_cfg = {
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
.need_pll_cfg = true,
+ .ht_greenfield_support = true,
};
struct iwl_cfg iwl5100_bg_cfg = {
@@ -1592,6 +1670,7 @@ struct iwl_cfg iwl5100_bg_cfg = {
.valid_tx_ant = ANT_B,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = true,
+ .ht_greenfield_support = true,
};
struct iwl_cfg iwl5100_abg_cfg = {
@@ -1608,6 +1687,7 @@ struct iwl_cfg iwl5100_abg_cfg = {
.valid_tx_ant = ANT_B,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = true,
+ .ht_greenfield_support = true,
};
struct iwl_cfg iwl5100_agn_cfg = {
@@ -1624,6 +1704,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
.valid_tx_ant = ANT_B,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = true,
+ .ht_greenfield_support = true,
};
struct iwl_cfg iwl5350_agn_cfg = {
@@ -1640,6 +1721,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
.need_pll_cfg = true,
+ .ht_greenfield_support = true,
};
struct iwl_cfg iwl5150_agn_cfg = {
@@ -1656,6 +1738,7 @@ struct iwl_cfg iwl5150_agn_cfg = {
.valid_tx_ant = ANT_A,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = true,
+ .ht_greenfield_support = true,
};
MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
@@ -1664,8 +1747,6 @@ MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
MODULE_PARM_DESC(swcrypto50,
"using software crypto engine (default 0 [hardware])\n");
-module_param_named(debug50, iwl50_mod_params.debug, uint, 0444);
-MODULE_PARM_DESC(debug50, "50XX debug output mask");
module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444);
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index bd438d8acf55..82b9c93dff54 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -46,8 +46,8 @@
#include "iwl-5000-hw.h"
/* Highest firmware API version supported */
-#define IWL6000_UCODE_API_MAX 2
-#define IWL6050_UCODE_API_MAX 2
+#define IWL6000_UCODE_API_MAX 4
+#define IWL6050_UCODE_API_MAX 4
/* Lowest firmware API version supported */
#define IWL6000_UCODE_API_MIN 1
@@ -61,6 +61,82 @@
#define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode"
#define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api)
+static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
+{
+ /* want Celsius */
+ priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
+ priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+}
+
+/* NIC configuration for 6000 series */
+static void iwl6000_nic_config(struct iwl_priv *priv)
+{
+ iwl5000_nic_config(priv);
+
+ /* no locking required for register write */
+ if (priv->cfg->pa_type == IWL_PA_HYBRID) {
+ /* 2x2 hybrid phy type */
+ iwl_write32(priv, CSR_GP_DRIVER_REG,
+ CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB);
+ } else if (priv->cfg->pa_type == IWL_PA_INTERNAL) {
+ /* 2x2 IPA phy type */
+ iwl_write32(priv, CSR_GP_DRIVER_REG,
+ CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
+ }
+ /* else do nothing, uCode configured */
+}
+
+static struct iwl_lib_ops iwl6000_lib = {
+ .set_hw_params = iwl5000_hw_set_hw_params,
+ .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
+ .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
+ .txq_set_sched = iwl5000_txq_set_sched,
+ .txq_agg_enable = iwl5000_txq_agg_enable,
+ .txq_agg_disable = iwl5000_txq_agg_disable,
+ .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
+ .txq_free_tfd = iwl_hw_txq_free_tfd,
+ .txq_init = iwl_hw_tx_queue_init,
+ .rx_handler_setup = iwl5000_rx_handler_setup,
+ .setup_deferred_work = iwl5000_setup_deferred_work,
+ .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+ .load_ucode = iwl5000_load_ucode,
+ .init_alive_start = iwl5000_init_alive_start,
+ .alive_notify = iwl5000_alive_notify,
+ .send_tx_power = iwl5000_send_tx_power,
+ .update_chain_flags = iwl_update_chain_flags,
+ .apm_ops = {
+ .init = iwl5000_apm_init,
+ .reset = iwl5000_apm_reset,
+ .stop = iwl5000_apm_stop,
+ .config = iwl6000_nic_config,
+ .set_pwr_src = iwl_set_pwr_src,
+ },
+ .eeprom_ops = {
+ .regulatory_bands = {
+ EEPROM_5000_REG_BAND_1_CHANNELS,
+ EEPROM_5000_REG_BAND_2_CHANNELS,
+ EEPROM_5000_REG_BAND_3_CHANNELS,
+ EEPROM_5000_REG_BAND_4_CHANNELS,
+ EEPROM_5000_REG_BAND_5_CHANNELS,
+ EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
+ EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+ },
+ .verify_signature = iwlcore_eeprom_verify_signature,
+ .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+ .release_semaphore = iwlcore_eeprom_release_semaphore,
+ .calib_version = iwl5000_eeprom_calib_version,
+ .query_addr = iwl5000_eeprom_query_addr,
+ .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
+ },
+ .post_associate = iwl_post_associate,
+ .isr = iwl_isr_ict,
+ .config_ap = iwl_config_ap,
+ .temp_ops = {
+ .temperature = iwl5000_temperature,
+ .set_ct_kill = iwl6000_set_ct_threshold,
+ },
+};
+
static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
.get_hcmd_size = iwl5000_get_hcmd_size,
.build_addsta_hcmd = iwl5000_build_addsta_hcmd,
@@ -69,41 +145,57 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
};
static struct iwl_ops iwl6000_ops = {
- .lib = &iwl5000_lib,
+ .ucode = &iwl5000_ucode,
+ .lib = &iwl6000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl6000_hcmd_utils,
};
-struct iwl_cfg iwl6000_2ag_cfg = {
- .name = "6000 Series 2x2 AG",
+
+/*
+ * "h": Hybrid configuration, use both internal and external Power Amplifier
+ */
+struct iwl_cfg iwl6000h_2agn_cfg = {
+ .name = "6000 Series 2x2 AGN",
.fw_name_pre = IWL6000_FW_PRE,
.ucode_api_max = IWL6000_UCODE_API_MAX,
.ucode_api_min = IWL6000_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G,
+ .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
- .valid_tx_ant = ANT_BC,
- .valid_rx_ant = ANT_BC,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
.need_pll_cfg = false,
+ .pa_type = IWL_PA_HYBRID,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
};
-struct iwl_cfg iwl6000_2agn_cfg = {
+/*
+ * "i": Internal configuration, use internal Power Amplifier
+ */
+struct iwl_cfg iwl6000i_2agn_cfg = {
.name = "6000 Series 2x2 AGN",
.fw_name_pre = IWL6000_FW_PRE,
.ucode_api_max = IWL6000_UCODE_API_MAX,
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
+ .valid_tx_ant = ANT_BC,
+ .valid_rx_ant = ANT_BC,
.need_pll_cfg = false,
+ .pa_type = IWL_PA_INTERNAL,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
};
struct iwl_cfg iwl6050_2agn_cfg = {
@@ -113,13 +205,17 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
};
struct iwl_cfg iwl6000_3agn_cfg = {
@@ -129,13 +225,17 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
.need_pll_cfg = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
};
struct iwl_cfg iwl6050_3agn_cfg = {
@@ -145,13 +245,17 @@ struct iwl_cfg iwl6050_3agn_cfg = {
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
.need_pll_cfg = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
};
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index ff20e5048a55..40b207aa8fef 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 {
enum iwl_table_type lq_type;
u8 ant_type;
u8 is_SGI; /* 1 = short guard interval */
- u8 is_fat; /* 1 = 40 MHz channel width */
+ u8 is_ht40; /* 1 = 40 MHz channel width */
u8 is_dup; /* 1 = duplicated data streams */
u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
u8 max_search; /* maximun number of tables we can search */
@@ -177,7 +177,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
struct sk_buff *skb,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta);
-static void rs_fill_link_cmd(const struct iwl_priv *priv,
+static void rs_fill_link_cmd(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
@@ -332,6 +332,9 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
} else
return MAX_TID_COUNT;
+ if (unlikely(tid >= TID_MAX_LOAD_COUNT))
+ return MAX_TID_COUNT;
+
tl = &lq_data->load[tid];
curr_time -= curr_time % TID_ROUND_VALUE;
@@ -539,11 +542,11 @@ static u32 rate_n_flags_from_tbl(struct iwl_priv *priv,
RATE_MCS_ANT_ABC_MSK);
if (is_Ht(tbl->lq_type)) {
- if (tbl->is_fat) {
+ if (tbl->is_ht40) {
if (tbl->is_dup)
rate_n_flags |= RATE_MCS_DUP_MSK;
else
- rate_n_flags |= RATE_MCS_FAT_MSK;
+ rate_n_flags |= RATE_MCS_HT40_MSK;
}
if (tbl->is_SGI)
rate_n_flags |= RATE_MCS_SGI_MSK;
@@ -579,7 +582,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
return -EINVAL;
}
tbl->is_SGI = 0; /* default legacy setup */
- tbl->is_fat = 0;
+ tbl->is_ht40 = 0;
tbl->is_dup = 0;
tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS);
tbl->lq_type = LQ_NONE;
@@ -598,9 +601,9 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
if (rate_n_flags & RATE_MCS_SGI_MSK)
tbl->is_SGI = 1;
- if ((rate_n_flags & RATE_MCS_FAT_MSK) ||
+ if ((rate_n_flags & RATE_MCS_HT40_MSK) ||
(rate_n_flags & RATE_MCS_DUP_MSK))
- tbl->is_fat = 1;
+ tbl->is_ht40 = 1;
if (rate_n_flags & RATE_MCS_DUP_MSK)
tbl->is_dup = 1;
@@ -654,19 +657,15 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
return 1;
}
-/* in 4965 we don't use greenfield at all */
-static inline u8 rs_use_green(struct iwl_priv *priv,
- struct ieee80211_conf *conf)
+/**
+ * Green-field mode is valid if the station supports it and
+ * there are no non-GF stations present in the BSS.
+ */
+static inline u8 rs_use_green(struct ieee80211_sta *sta,
+ struct iwl_ht_info *ht_conf)
{
- u8 is_green;
-
- if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
- is_green = 0;
- else
- is_green = (conf_is_ht(conf) &&
- priv->current_ht_config.is_green_field &&
- !priv->current_ht_config.non_GF_STA_present);
- return is_green;
+ return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
+ !(ht_conf->non_GF_STA_present);
}
/**
@@ -776,7 +775,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
if (num_of_ant(tbl->ant_type) > 1)
tbl->ant_type = ANT_A;/*FIXME:RS*/
- tbl->is_fat = 0;
+ tbl->is_ht40 = 0;
tbl->is_SGI = 0;
tbl->max_search = IWL_MAX_SEARCH;
}
@@ -819,15 +818,15 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
{
int status;
u8 retries;
- int rs_index, index = 0;
+ int rs_index, mac_index, index = 0;
struct iwl_lq_sta *lq_sta = priv_sta;
struct iwl_link_quality_cmd *table;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
- struct ieee80211_hw *hw = priv->hw;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_rate_scale_data *window = NULL;
struct iwl_rate_scale_data *search_win = NULL;
+ enum mac80211_rate_control_flags mac_flags;
u32 tx_rate;
struct iwl_scale_tbl_info tbl_type;
struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
@@ -877,17 +876,24 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
if (priv->band == IEEE80211_BAND_5GHZ)
rs_index -= IWL_FIRST_OFDM_RATE;
+ mac_flags = info->status.rates[0].flags;
+ mac_index = info->status.rates[0].idx;
+ /* For HT packets, map MCS to PLCP */
+ if (mac_flags & IEEE80211_TX_RC_MCS) {
+ mac_index &= RATE_MCS_CODE_MSK; /* Remove # of streams */
+ if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE))
+ mac_index++;
+ }
- if ((info->status.rates[0].idx < 0) ||
- (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) ||
- (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
- (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) ||
+ if ((mac_index < 0) ||
+ (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) ||
+ (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
+ (tbl_type.is_dup != !!(mac_flags & IEEE80211_TX_RC_DUP_DATA)) ||
(tbl_type.ant_type != info->antenna_sel_tx) ||
- (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) ||
- (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
- (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
- hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) {
- IWL_DEBUG_RATE(priv, "initial rate does not match 0x%x\n", tx_rate);
+ (!!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)) ||
+ (!!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
+ (rs_index != mac_index)) {
+ IWL_DEBUG_RATE(priv, "initial rate %d does not match %d (0x%x)\n", mac_index, rs_index, tx_rate);
/* the last LQ command could failed so the LQ in ucode not
* the same in driver sync up
*/
@@ -1049,7 +1055,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
else
tbl->expected_tpt = expected_tpt_A;
} else if (is_siso(tbl->lq_type)) {
- if (tbl->is_fat && !lq_sta->is_dup)
+ if (tbl->is_ht40 && !lq_sta->is_dup)
if (tbl->is_SGI)
tbl->expected_tpt = expected_tpt_siso40MHzSGI;
else
@@ -1059,7 +1065,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
else
tbl->expected_tpt = expected_tpt_siso20MHz;
} else if (is_mimo2(tbl->lq_type)) {
- if (tbl->is_fat && !lq_sta->is_dup)
+ if (tbl->is_ht40 && !lq_sta->is_dup)
if (tbl->is_SGI)
tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI;
else
@@ -1069,7 +1075,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
else
tbl->expected_tpt = expected_tpt_mimo2_20MHz;
} else if (is_mimo3(tbl->lq_type)) {
- if (tbl->is_fat && !lq_sta->is_dup)
+ if (tbl->is_ht40 && !lq_sta->is_dup)
if (tbl->is_SGI)
tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI;
else
@@ -1217,22 +1223,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
tbl->max_search = IWL_MAX_SEARCH;
rate_mask = lq_sta->active_mimo2_rate;
- if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap))
- tbl->is_fat = 1;
+ if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
+ tbl->is_ht40 = 1;
else
- tbl->is_fat = 0;
-
- /* FIXME: - don't toggle SGI here
- if (tbl->is_fat) {
- if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
- tbl->is_SGI = 1;
- else
- tbl->is_SGI = 0;
- } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
- tbl->is_SGI = 1;
- else
- tbl->is_SGI = 0;
- */
+ tbl->is_ht40 = 0;
rs_set_expected_tpt_table(lq_sta, tbl);
@@ -1283,22 +1277,10 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
rate_mask = lq_sta->active_mimo3_rate;
- if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap))
- tbl->is_fat = 1;
- else
- tbl->is_fat = 0;
-
- /* FIXME: - don't toggle SGI here
- if (tbl->is_fat) {
- if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
- tbl->is_SGI = 1;
- else
- tbl->is_SGI = 0;
- } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
- tbl->is_SGI = 1;
+ if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
+ tbl->is_ht40 = 1;
else
- tbl->is_SGI = 0;
- */
+ tbl->is_ht40 = 0;
rs_set_expected_tpt_table(lq_sta, tbl);
@@ -1342,22 +1324,10 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
tbl->max_search = IWL_MAX_SEARCH;
rate_mask = lq_sta->active_siso_rate;
- if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap))
- tbl->is_fat = 1;
+ if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
+ tbl->is_ht40 = 1;
else
- tbl->is_fat = 0;
-
- /* FIXME: - don't toggle SGI here
- if (tbl->is_fat) {
- if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
- tbl->is_SGI = 1;
- else
- tbl->is_SGI = 0;
- } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
- tbl->is_SGI = 1;
- else
- tbl->is_SGI = 0;
- */
+ tbl->is_ht40 = 0;
if (is_green)
tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/
@@ -1398,6 +1368,12 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
int ret = 0;
u8 update_search_tbl_counter = 0;
+ if (!iwl_ht_enabled(priv))
+ /* stay in Legacy */
+ tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+ else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
+ tbl->action > IWL_LEGACY_SWITCH_SISO)
+ tbl->action = IWL_LEGACY_SWITCH_SISO;
for (; ;) {
lq_sta->action_counter++;
switch (tbl->action) {
@@ -1521,6 +1497,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
struct iwl_scale_tbl_info *search_tbl =
&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action = tbl->action;
@@ -1529,6 +1506,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
u8 update_search_tbl_counter = 0;
int ret;
+ if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
+ tbl->action > IWL_SISO_SWITCH_ANTENNA2) {
+ /* stay in SISO */
+ tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+ }
for (;;) {
lq_sta->action_counter++;
switch (tbl->action) {
@@ -1575,13 +1557,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
goto out;
break;
case IWL_SISO_SWITCH_GI:
- if (!tbl->is_fat &&
- !(priv->current_ht_config.sgf &
- HT_SHORT_GI_20MHZ))
+ if (!tbl->is_ht40 && !(ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_20))
break;
- if (tbl->is_fat &&
- !(priv->current_ht_config.sgf &
- HT_SHORT_GI_40MHZ))
+ if (tbl->is_ht40 && !(ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_40))
break;
IWL_DEBUG_RATE(priv, "LQ: SISO toggle SGI/NGI\n");
@@ -1655,6 +1635,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
struct iwl_scale_tbl_info *search_tbl =
&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action = tbl->action;
@@ -1663,6 +1644,12 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
u8 update_search_tbl_counter = 0;
int ret;
+ if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
+ (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
+ tbl->action > IWL_MIMO2_SWITCH_SISO_C)) {
+ /* switch in SISO */
+ tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+ }
for (;;) {
lq_sta->action_counter++;
switch (tbl->action) {
@@ -1709,13 +1696,11 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
break;
case IWL_MIMO2_SWITCH_GI:
- if (!tbl->is_fat &&
- !(priv->current_ht_config.sgf &
- HT_SHORT_GI_20MHZ))
+ if (!tbl->is_ht40 && !(ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_20))
break;
- if (tbl->is_fat &&
- !(priv->current_ht_config.sgf &
- HT_SHORT_GI_40MHZ))
+ if (tbl->is_ht40 && !(ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_40))
break;
IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n");
@@ -1791,6 +1776,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
struct iwl_scale_tbl_info *search_tbl =
&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action = tbl->action;
@@ -1799,6 +1785,12 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
int ret;
u8 update_search_tbl_counter = 0;
+ if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
+ (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
+ tbl->action > IWL_MIMO3_SWITCH_SISO_C)) {
+ /* switch in SISO */
+ tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+ }
for (;;) {
lq_sta->action_counter++;
switch (tbl->action) {
@@ -1867,13 +1859,11 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
break;
case IWL_MIMO3_SWITCH_GI:
- if (!tbl->is_fat &&
- !(priv->current_ht_config.sgf &
- HT_SHORT_GI_20MHZ))
+ if (!tbl->is_ht40 && !(ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_20))
break;
- if (tbl->is_fat &&
- !(priv->current_ht_config.sgf &
- HT_SHORT_GI_40MHZ))
+ if (tbl->is_ht40 && !(ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_40))
break;
IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n");
@@ -2003,6 +1993,25 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
}
/*
+ * setup rate table in uCode
+ * return rate_n_flags as used in the table
+ */
+static u32 rs_update_rate_tbl(struct iwl_priv *priv,
+ struct iwl_lq_sta *lq_sta,
+ struct iwl_scale_tbl_info *tbl,
+ int index, u8 is_green)
+{
+ u32 rate;
+
+ /* Update uCode's rate table. */
+ rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
+ rs_fill_link_cmd(priv, lq_sta, rate);
+ iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
+
+ return rate;
+}
+
+/*
* Do rate scaling and search for new modulation mode.
*/
static void rs_rate_scale_perform(struct iwl_priv *priv,
@@ -2066,7 +2075,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
if (is_legacy(tbl->lq_type))
lq_sta->is_green = 0;
else
- lq_sta->is_green = rs_use_green(priv, conf);
+ lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config);
is_green = lq_sta->is_green;
/* current tx rate */
@@ -2098,6 +2107,16 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
if (!((1 << index) & rate_scale_index_msk)) {
IWL_ERR(priv, "Current Rate is not valid\n");
+ if (lq_sta->search_better_tbl) {
+ /* revert to active table if search table is not valid*/
+ tbl->lq_type = LQ_NONE;
+ lq_sta->search_better_tbl = 0;
+ tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ /* get "active" rate info */
+ index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+ rate = rs_update_rate_tbl(priv, lq_sta,
+ tbl, index, is_green);
+ }
return;
}
@@ -2149,8 +2168,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
tbl->expected_tpt[index] + 64) / 128));
/* If we are searching for better modulation mode, check success. */
- if (lq_sta->search_better_tbl) {
-
+ if (lq_sta->search_better_tbl &&
+ (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI)) {
/* If good success, continue using the "search" mode;
* no need to send new link quality command, since we're
* continuing to use the setup that we've been trying. */
@@ -2278,7 +2297,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
((sr > IWL_RATE_HIGH_TH) ||
(current_tpt > (100 * tbl->expected_tpt[low]))))
scale_action = 0;
-
+ if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type))
+ scale_action = -1;
+ if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI &&
+ (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type)))
+ scale_action = -1;
switch (scale_action) {
case -1:
/* Decrease starting rate, update uCode's rate table */
@@ -2308,15 +2331,15 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
lq_update:
/* Replace uCode's rate table for the destination station. */
- if (update_lq) {
- rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
- rs_fill_link_cmd(priv, lq_sta, rate);
- iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
- }
-
- /* Should we stay with this modulation mode, or search for a new one? */
- rs_stay_in_table(lq_sta);
+ if (update_lq)
+ rate = rs_update_rate_tbl(priv, lq_sta,
+ tbl, index, is_green);
+ if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) {
+ /* Should we stay with this modulation mode,
+ * or search for a new one? */
+ rs_stay_in_table(lq_sta);
+ }
/*
* Search for new modulation mode if we're:
* 1) Not changing rates right now
@@ -2373,7 +2396,8 @@ lq_update:
* have been tried and compared, stay in this best modulation
* mode for a while before next round of mode comparisons. */
if (lq_sta->enable_counter &&
- (lq_sta->action_counter >= tbl1->max_search)) {
+ (lq_sta->action_counter >= tbl1->max_search) &&
+ iwl_ht_enabled(priv)) {
if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
(lq_sta->tx_agg_tid_en & (1 << tid)) &&
(tid != MAX_TID_COUNT)) {
@@ -2409,7 +2433,7 @@ static void rs_initialize_lq(struct iwl_priv *priv,
int rate_idx;
int i;
u32 rate;
- u8 use_green = rs_use_green(priv, conf);
+ u8 use_green = rs_use_green(sta, &priv->current_ht_config);
u8 active_tbl = 0;
u8 valid_tx_ant;
@@ -2462,11 +2486,11 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
struct ieee80211_supported_band *sband = txrc->sband;
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_conf *conf = &priv->hw->conf;
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_lq_sta *lq_sta = priv_sta;
int rate_idx;
- u64 mask_bit = 0;
IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n");
@@ -2481,22 +2505,9 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
lq_sta->max_rate_idx = -1;
}
- if (sta)
- mask_bit = sta->supp_rates[sband->band];
-
/* Send management frames and NO_ACK data using lowest rate. */
- if (!ieee80211_is_data(hdr->frame_control) ||
- info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !lq_sta) {
- if (!mask_bit)
- info->control.rates[0].idx =
- rate_lowest_index(sband, NULL);
- else
- info->control.rates[0].idx =
- rate_lowest_index(sband, sta);
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- info->control.rates[0].count = 1;
+ if (rate_control_send_low(sta, priv_sta, txrc))
return;
- }
rate_idx = lq_sta->last_txrate_idx;
@@ -2508,7 +2519,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n",
hdr->addr1);
sta_id = iwl_add_station(priv, hdr->addr1,
- false, CMD_ASYNC, NULL);
+ false, CMD_ASYNC, ht_cap);
}
if ((sta_id != IWL_INVALID_STATION)) {
lq_sta->lq.sta_id = sta_id;
@@ -2533,15 +2544,20 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI;
if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK)
info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA;
- if (lq_sta->last_rate_n_flags & RATE_MCS_FAT_MSK)
+ if (lq_sta->last_rate_n_flags & RATE_MCS_HT40_MSK)
info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK)
info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD;
} else {
- if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT)
+ /* Check for invalid rates */
+ if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) ||
+ ((sband->band == IEEE80211_BAND_5GHZ) &&
+ (rate_idx < IWL_FIRST_OFDM_RATE)))
rate_idx = rate_lowest_index(sband, sta);
+ /* On valid 5 GHz rate, adjust index */
else if (sband->band == IEEE80211_BAND_5GHZ)
rate_idx -= IWL_FIRST_OFDM_RATE;
+ info->control.rates[0].flags = 0;
}
info->control.rates[0].idx = rate_idx;
@@ -2577,10 +2593,8 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
int i, j;
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_conf *conf = &priv->hw->conf;
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
struct iwl_lq_sta *lq_sta = priv_sta;
- u16 mask_bit = 0;
- int count;
- int start_rate = 0;
lq_sta->flush_timer = 0;
lq_sta->supp_rates = sta->supp_rates[sband->band];
@@ -2605,7 +2619,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
sta_id = iwl_add_station(priv, sta->addr, false,
- CMD_ASYNC, NULL);
+ CMD_ASYNC, ht_cap);
}
if ((sta_id != IWL_INVALID_STATION)) {
lq_sta->lq.sta_id = sta_id;
@@ -2618,7 +2632,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
lq_sta->is_dup = 0;
lq_sta->max_rate_idx = -1;
lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
- lq_sta->is_green = rs_use_green(priv, conf);
+ lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config);
lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
lq_sta->active_rate_basic = priv->active_rate_basic;
lq_sta->band = priv->band;
@@ -2626,19 +2640,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
* active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
* supp_rates[] does not; shift to convert format, force 9 MBits off.
*/
- lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1;
- lq_sta->active_siso_rate |= sta->ht_cap.mcs.rx_mask[0] & 0x1;
+ lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
+ lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
lq_sta->active_siso_rate &= ~((u16)0x2);
lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
/* Same here */
- lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1;
- lq_sta->active_mimo2_rate |= sta->ht_cap.mcs.rx_mask[1] & 0x1;
+ lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
+ lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
lq_sta->active_mimo2_rate &= ~((u16)0x2);
lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
- lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1;
- lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1;
+ lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1;
+ lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1;
lq_sta->active_mimo3_rate &= ~((u16)0x2);
lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
@@ -2655,25 +2669,15 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
lq_sta->drv = priv;
- /* Find highest tx rate supported by hardware and destination station */
- mask_bit = sta->supp_rates[sband->band];
- count = sband->n_bitrates;
- if (sband->band == IEEE80211_BAND_5GHZ) {
- count += IWL_FIRST_OFDM_RATE;
- start_rate = IWL_FIRST_OFDM_RATE;
- mask_bit <<= IWL_FIRST_OFDM_RATE;
- }
-
- mask_bit = mask_bit & lq_sta->active_legacy_rate;
- lq_sta->last_txrate_idx = 4;
- for (i = start_rate; i < count; i++)
- if (mask_bit & BIT(i))
- lq_sta->last_txrate_idx = i;
+ /* Set last_txrate_idx to lowest rate */
+ lq_sta->last_txrate_idx = rate_lowest_index(sband, sta);
+ if (sband->band == IEEE80211_BAND_5GHZ)
+ lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
rs_initialize_lq(priv, conf, sta, lq_sta);
}
-static void rs_fill_link_cmd(const struct iwl_priv *priv,
+static void rs_fill_link_cmd(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta, u32 new_rate)
{
struct iwl_scale_tbl_info tbl_type;
@@ -2920,7 +2924,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
(is_siso(tbl->lq_type)) ? "SISO" :
((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
desc += sprintf(buff+desc, " %s",
- (tbl->is_fat) ? "40MHz" : "20MHz");
+ (tbl->is_ht40) ? "40MHz" : "20MHz");
desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "",
(lq_sta->is_green) ? "GF enabled" : "");
}
@@ -2985,12 +2989,13 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
return -ENOMEM;
for (i = 0; i < LQ_SIZE; i++) {
- desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d GF=%d\n"
+ desc += sprintf(buff+desc,
+ "%s type=%d SGI=%d HT40=%d DUP=%d GF=%d\n"
"rate=0x%X\n",
lq_sta->active_tbl == i ? "*" : "x",
lq_sta->lq_info[i].lq_type,
lq_sta->lq_info[i].is_SGI,
- lq_sta->lq_info[i].is_fat,
+ lq_sta->lq_info[i].is_ht40,
lq_sta->lq_info[i].is_dup,
lq_sta->is_green,
lq_sta->lq_info[i].current_rate);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index 25050bf315a2..9fac530cfb7e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -73,6 +73,7 @@ enum {
IWL_RATE_54M_INDEX,
IWL_RATE_60M_INDEX,
IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/
+ IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1, /* Excluding 60M */
IWL_RATE_COUNT_3945 = IWL_RATE_COUNT - 1,
IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
IWL_RATE_INVALID = IWL_RATE_COUNT,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 355f50ea7fef..00457bff1ed1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -171,7 +171,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
le16_to_cpu(priv->staging_rxon.channel),
priv->staging_rxon.bssid_addr);
- iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+ iwl_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto);
/* Apply the new configuration
* RXON unassoc clears the station table in uCode, send it before
@@ -442,8 +442,8 @@ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
/* Unmap tx_cmd */
if (num_tbs)
pci_unmap_single(dev,
- pci_unmap_addr(&txq->cmd[index]->meta, mapping),
- pci_unmap_len(&txq->cmd[index]->meta, len),
+ pci_unmap_addr(&txq->meta[index], mapping),
+ pci_unmap_len(&txq->meta[index], len),
PCI_DMA_BIDIRECTIONAL);
/* Unmap chunks, if any. */
@@ -512,70 +512,6 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv,
return 0;
}
-
-/******************************************************************************
- *
- * Misc. internal state and helper functions
- *
- ******************************************************************************/
-
-#define MAX_UCODE_BEACON_INTERVAL 4096
-
-static u16 iwl_adjust_beacon_interval(u16 beacon_val)
-{
- u16 new_val = 0;
- u16 beacon_factor = 0;
-
- beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL)
- / MAX_UCODE_BEACON_INTERVAL;
- new_val = beacon_val / beacon_factor;
-
- if (!new_val)
- new_val = MAX_UCODE_BEACON_INTERVAL;
-
- return new_val;
-}
-
-static void iwl_setup_rxon_timing(struct iwl_priv *priv)
-{
- u64 tsf;
- s32 interval_tm, rem;
- unsigned long flags;
- struct ieee80211_conf *conf = NULL;
- u16 beacon_int = 0;
-
- conf = ieee80211_get_hw_conf(priv->hw);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
- priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
-
- if (priv->iw_mode == NL80211_IFTYPE_STATION) {
- beacon_int = iwl_adjust_beacon_interval(priv->beacon_int);
- priv->rxon_timing.atim_window = 0;
- } else {
- beacon_int = iwl_adjust_beacon_interval(
- priv->vif->bss_conf.beacon_int);
-
- /* TODO: we need to get atim_window from upper stack
- * for now we set to 0 */
- priv->rxon_timing.atim_window = 0;
- }
-
- priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
-
- tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
- interval_tm = beacon_int * 1024;
- rem = do_div(tsf, interval_tm);
- priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- IWL_DEBUG_ASSOC(priv, "beacon interval %d beacon timer %d beacon tim %d\n",
- le16_to_cpu(priv->rxon_timing.beacon_interval),
- le32_to_cpu(priv->rxon_timing.beacon_init_val),
- le16_to_cpu(priv->rxon_timing.atim_window));
-}
-
/******************************************************************************
*
* Generic RX handler implementations
@@ -697,7 +633,6 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status;
- unsigned long reg_flags;
IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
(flags & HW_CARD_DISABLED) ? "Kill" : "On",
@@ -717,19 +652,12 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
iwl_write_direct32(priv, HBUS_TARG_MBX_C,
HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
-
- }
-
- if (flags & RF_CARD_DISABLED) {
- iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
- CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
- iwl_read32(priv, CSR_UCODE_DRV_GP1);
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- if (!iwl_grab_nic_access(priv))
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
}
+ if (flags & RF_CARD_DISABLED)
+ iwl_tt_enter_ct_kill(priv);
}
+ if (!(flags & RF_CARD_DISABLED))
+ iwl_tt_exit_ct_kill(priv);
if (flags & HW_CARD_DISABLED)
set_bit(STATUS_RF_KILL_HW, &priv->status);
@@ -964,7 +892,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_ISR) {
+ if (iwl_get_debug_level(priv) & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@@ -983,7 +911,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
+ IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
@@ -999,7 +927,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1024,7 +952,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
hw_rf_kill = 1;
- IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
+ IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
hw_rf_kill ? "disable radio" : "enable radio");
priv->isr_stats.rfkill++;
@@ -1113,7 +1041,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
iwl_enable_interrupts(priv);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
inta = iwl_read32(priv, CSR_INT);
inta_mask = iwl_read32(priv, CSR_INT_MASK);
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@@ -1144,7 +1072,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
inta = priv->inta;
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_ISR) {
+ if (iwl_get_debug_level(priv) & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ",
@@ -1156,7 +1084,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
+ IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
@@ -1172,7 +1100,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1197,7 +1125,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
hw_rf_kill = 1;
- IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
+ IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
hw_rf_kill ? "disable radio" : "enable radio");
priv->isr_stats.rfkill++;
@@ -1348,7 +1276,7 @@ static void iwl_nic_start(struct iwl_priv *priv)
*/
static int iwl_read_ucode(struct iwl_priv *priv)
{
- struct iwl_ucode *ucode;
+ struct iwl_ucode_header *ucode;
int ret = -EINVAL, index;
const struct firmware *ucode_raw;
const char *name_pre = priv->cfg->fw_name_pre;
@@ -1357,7 +1285,9 @@ static int iwl_read_ucode(struct iwl_priv *priv)
char buf[25];
u8 *src;
size_t len;
- u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size;
+ u32 api_ver, build;
+ u32 inst_size, data_size, init_size, init_data_size, boot_size;
+ u16 eeprom_ver;
/* Ask kernel firmware_class module to get the boot firmware off disk.
* request_firmware() is synchronous, file is in memory on return. */
@@ -1387,23 +1317,26 @@ static int iwl_read_ucode(struct iwl_priv *priv)
if (ret < 0)
goto error;
- /* Make sure that we got at least our header! */
- if (ucode_raw->size < sizeof(*ucode)) {
+ /* Make sure that we got at least the v1 header! */
+ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n");
ret = -EINVAL;
goto err_release;
}
/* Data from ucode file: header followed by uCode images */
- ucode = (void *)ucode_raw->data;
+ ucode = (struct iwl_ucode_header *)ucode_raw->data;
priv->ucode_ver = le32_to_cpu(ucode->ver);
api_ver = IWL_UCODE_API(priv->ucode_ver);
- inst_size = le32_to_cpu(ucode->inst_size);
- data_size = le32_to_cpu(ucode->data_size);
- init_size = le32_to_cpu(ucode->init_size);
- init_data_size = le32_to_cpu(ucode->init_data_size);
- boot_size = le32_to_cpu(ucode->boot_size);
+ build = priv->cfg->ops->ucode->get_build(ucode, api_ver);
+ inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
+ data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
+ init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
+ init_data_size =
+ priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
+ boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
+ src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
/* api_ver should match the api version forming part of the
* firmware filename ... but we don't check for that and only rely
@@ -1429,6 +1362,14 @@ static int iwl_read_ucode(struct iwl_priv *priv)
IWL_UCODE_API(priv->ucode_ver),
IWL_UCODE_SERIAL(priv->ucode_ver));
+ if (build)
+ IWL_DEBUG_INFO(priv, "Build %u\n", build);
+
+ eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
+ IWL_DEBUG_INFO(priv, "NVM Type: %s, version: 0x%x\n",
+ (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+ ? "OTP" : "EEPROM", eeprom_ver);
+
IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
priv->ucode_ver);
IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
@@ -1443,12 +1384,14 @@ static int iwl_read_ucode(struct iwl_priv *priv)
boot_size);
/* Verify size of file vs. image size info in file's header */
- if (ucode_raw->size < sizeof(*ucode) +
+ if (ucode_raw->size !=
+ priv->cfg->ops->ucode->get_header_size(api_ver) +
inst_size + data_size + init_size +
init_data_size + boot_size) {
- IWL_DEBUG_INFO(priv, "uCode file size %d too small\n",
- (int)ucode_raw->size);
+ IWL_DEBUG_INFO(priv,
+ "uCode file size %d does not match expected size\n",
+ (int)ucode_raw->size);
ret = -EINVAL;
goto err_release;
}
@@ -1528,42 +1471,42 @@ static int iwl_read_ucode(struct iwl_priv *priv)
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
- src = &ucode->data[0];
- len = priv->ucode_code.len;
+ len = inst_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len);
memcpy(priv->ucode_code.v_addr, src, len);
+ src += len;
+
IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
/* Runtime data (2nd block)
* NOTE: Copy into backup buffer will be done in iwl_up() */
- src = &ucode->data[inst_size];
- len = priv->ucode_data.len;
+ len = data_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len);
memcpy(priv->ucode_data.v_addr, src, len);
memcpy(priv->ucode_data_backup.v_addr, src, len);
+ src += len;
/* Initialization instructions (3rd block) */
if (init_size) {
- src = &ucode->data[inst_size + data_size];
- len = priv->ucode_init.len;
+ len = init_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
len);
memcpy(priv->ucode_init.v_addr, src, len);
+ src += len;
}
/* Initialization data (4th block) */
if (init_data_size) {
- src = &ucode->data[inst_size + data_size + init_size];
- len = priv->ucode_init_data.len;
+ len = init_data_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
len);
memcpy(priv->ucode_init_data.v_addr, src, len);
+ src += len;
}
/* Bootstrap instructions (5th block) */
- src = &ucode->data[inst_size + data_size + init_size + init_data_size];
- len = priv->ucode_boot.len;
+ len = boot_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
memcpy(priv->ucode_boot.v_addr, src, len);
@@ -1663,7 +1606,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
set_bit(STATUS_READY, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
- iwl_power_update_mode(priv, 1);
+ iwl_power_update_mode(priv, true);
/* reassociate for ADHOC mode */
if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) {
@@ -1812,6 +1755,11 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n");
+ ret = iwl_set_hw_ready(priv);
+ if (priv->hw_ready)
+ return ret;
+
+ /* If HW is not ready, prepare the conditions to check again */
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_PREPARE);
@@ -1819,6 +1767,7 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
+ /* HW should be ready by now, check again. */
if (ret != -ETIMEDOUT)
iwl_set_hw_ready(priv);
@@ -2126,7 +2075,7 @@ void iwl_post_associate(struct iwl_priv *priv)
* If chain noise has already been run, then we need to enable
* power management here */
if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
- iwl_power_update_mode(priv, 0);
+ iwl_power_update_mode(priv, false);
/* Enable Rx differential gain and sensitivity calibrations */
iwl_chain_noise_reset(priv);
@@ -2206,7 +2155,7 @@ static void iwl_mac_stop(struct ieee80211_hw *hw)
priv->is_open = 0;
- if (iwl_is_ready_rf(priv)) {
+ if (iwl_is_ready_rf(priv) || test_bit(STATUS_SCAN_HW, &priv->status)) {
/* stop mac, cancel any scan request and clear
* RXON_FILTER_ASSOC_MSK BIT
*/
@@ -2331,7 +2280,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
IWL_DEBUG_MAC80211(priv, "enter\n");
- if (priv->hw_params.sw_crypto) {
+ if (priv->cfg->mod_params->sw_crypto) {
IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
return -EOPNOTSUPP;
}
@@ -2455,14 +2404,16 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
* used for controlling the debug level.
*
* See the level definitions in iwl for details.
+ *
+ * The debug_level being managed using sysfs below is a per device debug
+ * level that is used instead of the global debug level if it (the per
+ * device debug level) is set.
*/
-
static ssize_t show_debug_level(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwl_priv *priv = dev_get_drvdata(d);
-
- return sprintf(buf, "0x%08X\n", priv->debug_level);
+ return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv));
}
static ssize_t store_debug_level(struct device *d,
struct device_attribute *attr,
@@ -2475,9 +2426,12 @@ static ssize_t store_debug_level(struct device *d,
ret = strict_strtoul(buf, 0, &val);
if (ret)
IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
- else
+ else {
priv->debug_level = val;
-
+ if (iwl_alloc_traffic_mem(priv))
+ IWL_ERR(priv,
+ "Not enough memory to generate traffic log\n");
+ }
return strnlen(buf, count);
}
@@ -2488,39 +2442,6 @@ static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO,
#endif /* CONFIG_IWLWIFI_DEBUG */
-static ssize_t show_version(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- struct iwl_alive_resp *palive = &priv->card_alive;
- ssize_t pos = 0;
- u16 eeprom_ver;
-
- if (palive->is_valid)
- pos += sprintf(buf + pos,
- "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n"
- "fw type: 0x%01X 0x%01X\n",
- palive->ucode_major, palive->ucode_minor,
- palive->sw_rev[0], palive->sw_rev[1],
- palive->ver_type, palive->ver_subtype);
- else
- pos += sprintf(buf + pos, "fw not loaded\n");
-
- if (priv->eeprom) {
- eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
- pos += sprintf(buf + pos, "NVM Type: %s, version: 0x%x\n",
- (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
- ? "OTP" : "EEPROM", eeprom_ver);
-
- } else {
- pos += sprintf(buf + pos, "EEPROM not initialzed\n");
- }
-
- return pos;
-}
-
-static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL);
-
static ssize_t show_temperature(struct device *d,
struct device_attribute *attr, char *buf)
{
@@ -2556,10 +2477,15 @@ static ssize_t store_tx_power(struct device *d,
ret = strict_strtoul(buf, 10, &val);
if (ret)
IWL_INFO(priv, "%s is not in decimal form.\n", buf);
- else
- iwl_set_tx_power(priv, val, false);
-
- return count;
+ else {
+ ret = iwl_set_tx_power(priv, val, false);
+ if (ret)
+ IWL_ERR(priv, "failed setting tx power (0x%d).\n",
+ ret);
+ else
+ ret = count;
+ }
+ return ret;
}
static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
@@ -2644,67 +2570,6 @@ static ssize_t store_filter_flags(struct device *d,
static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
store_filter_flags);
-static ssize_t store_power_level(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- int ret;
- unsigned long mode;
-
-
- mutex_lock(&priv->mutex);
-
- ret = strict_strtoul(buf, 10, &mode);
- if (ret)
- goto out;
-
- ret = iwl_power_set_user_mode(priv, mode);
- if (ret) {
- IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n");
- goto out;
- }
- ret = count;
-
- out:
- mutex_unlock(&priv->mutex);
- return ret;
-}
-
-static ssize_t show_power_level(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- int level = priv->power_data.power_mode;
- char *p = buf;
-
- p += sprintf(p, "%d\n", level);
- return p - buf + 1;
-}
-
-static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
- store_power_level);
-
-static ssize_t show_qos(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- char *p = buf;
- int q;
-
- for (q = 0; q < AC_NUM; q++) {
- p += sprintf(p, "\tcw_min\tcw_max\taifsn\ttxop\n");
- p += sprintf(p, "AC[%d]\t%u\t%u\t%u\t%u\n", q,
- priv->qos_data.def_qos_parm.ac[q].cw_min,
- priv->qos_data.def_qos_parm.ac[q].cw_max,
- priv->qos_data.def_qos_parm.ac[q].aifsn,
- priv->qos_data.def_qos_parm.ac[q].edca_txop);
- }
-
- return p - buf + 1;
-}
-
-static DEVICE_ATTR(qos, S_IRUGO, show_qos, NULL);
static ssize_t show_statistics(struct device *d,
struct device_attribute *attr, char *buf)
@@ -2797,15 +2662,12 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
static struct attribute *iwl_sysfs_entries[] = {
&dev_attr_flags.attr,
&dev_attr_filter_flags.attr,
- &dev_attr_power_level.attr,
&dev_attr_statistics.attr,
&dev_attr_temperature.attr,
&dev_attr_tx_power.attr,
#ifdef CONFIG_IWLWIFI_DEBUG
&dev_attr_debug_level.attr,
#endif
- &dev_attr_version.attr,
- &dev_attr_qos.attr,
NULL
};
@@ -2849,7 +2711,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan. */
if (cfg->mod_params->disable_hw_scan) {
- if (cfg->mod_params->debug & IWL_DL_INFO)
+ if (iwl_debug_level & IWL_DL_INFO)
dev_printk(KERN_DEBUG, &(pdev->dev),
"Disabling hw_scan\n");
iwl_hw_ops.hw_scan = NULL;
@@ -2871,9 +2733,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv->inta_mask = CSR_INI_SET_MASK;
#ifdef CONFIG_IWLWIFI_DEBUG
- priv->debug_level = priv->cfg->mod_params->debug;
atomic_set(&priv->restrict_refcnt, 0);
#endif
+ if (iwl_alloc_traffic_mem(priv))
+ IWL_ERR(priv, "Not enough memory to generate traffic log\n");
/**************************
* 2. Initializing PCI bus
@@ -3034,6 +2897,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
test_bit(STATUS_RF_KILL_HW, &priv->status));
iwl_power_initialize(priv);
+ iwl_tt_initialize(priv);
return 0;
out_remove_sysfs:
@@ -3057,6 +2921,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_disable_device(pdev);
out_ieee80211_free_hw:
ieee80211_free_hw(priv->hw);
+ iwl_free_traffic_mem(priv);
out:
return err;
}
@@ -3086,6 +2951,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
iwl_down(priv);
}
+ iwl_tt_exit(priv);
+
/* make sure we flush any pending irq or
* tasklet for the driver
*/
@@ -3113,6 +2980,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
* until now... */
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;
+ iwl_free_traffic_mem(priv);
free_irq(priv->pci_dev->irq, priv);
pci_disable_msi(priv->pci_dev);
@@ -3163,15 +3031,12 @@ static struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)},
{IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)},
/* 6000/6050 Series */
- {IWL_PCI_DEVICE(0x0082, 0x1102, iwl6000_2ag_cfg)},
- {IWL_PCI_DEVICE(0x0085, 0x1112, iwl6000_2ag_cfg)},
- {IWL_PCI_DEVICE(0x0082, 0x1122, iwl6000_2ag_cfg)},
+ {IWL_PCI_DEVICE(0x008D, PCI_ANY_ID, iwl6000h_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x008E, PCI_ANY_ID, iwl6000h_2agn_cfg)},
{IWL_PCI_DEVICE(0x422B, PCI_ANY_ID, iwl6000_3agn_cfg)},
- {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000i_2agn_cfg)},
{IWL_PCI_DEVICE(0x4238, PCI_ANY_ID, iwl6000_3agn_cfg)},
- {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0082, PCI_ANY_ID, iwl6000_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0085, PCI_ANY_ID, iwl6000_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000i_2agn_cfg)},
{IWL_PCI_DEVICE(0x0086, PCI_ANY_ID, iwl6050_3agn_cfg)},
{IWL_PCI_DEVICE(0x0087, PCI_ANY_ID, iwl6050_2agn_cfg)},
{IWL_PCI_DEVICE(0x0088, PCI_ANY_ID, iwl6050_3agn_cfg)},
@@ -3231,3 +3096,11 @@ static void __exit iwl_exit(void)
module_exit(iwl_exit);
module_init(iwl_init);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+module_param_named(debug50, iwl_debug_level, uint, 0444);
+MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)");
+module_param_named(debug, iwl_debug_level, uint, 0644);
+MODULE_PARM_DESC(debug, "debug output mask");
+#endif
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index a5d63672ad39..c4b565a2de94 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -86,7 +86,7 @@ int iwl_send_calib_results(struct iwl_priv *priv)
struct iwl_host_cmd hcmd = {
.id = REPLY_PHY_CALIBRATION_CMD,
- .meta.flags = CMD_SIZE_HUGE,
+ .flags = CMD_SIZE_HUGE,
};
for (i = 0; i < IWL_CALIB_MAX; i++) {
@@ -251,12 +251,7 @@ static int iwl_sens_energy_cck(struct iwl_priv *priv,
/* increase energy threshold (reduce nrg value)
* to decrease sensitivity */
- if (data->nrg_th_cck >
- (ranges->max_nrg_cck + NRG_STEP_CCK))
- data->nrg_th_cck = data->nrg_th_cck
- - NRG_STEP_CCK;
- else
- data->nrg_th_cck = ranges->max_nrg_cck;
+ data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK;
/* Else if we got fewer than desired, increase sensitivity */
} else if (false_alarms < min_false_alarms) {
data->nrg_curr_state = IWL_FA_TOO_FEW;
@@ -424,7 +419,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
struct iwl_host_cmd cmd_out = {
.id = SENSITIVITY_CMD,
.len = sizeof(struct iwl_sensitivity_cmd),
- .meta.flags = CMD_ASYNC,
+ .flags = CMD_ASYNC,
.data = &cmd,
};
@@ -857,7 +852,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
priv->cfg->ops->lib->update_chain_flags(priv);
data->state = IWL_CHAIN_NOISE_DONE;
- iwl_power_update_mode(priv, 0);
+ iwl_power_update_mode(priv, false);
}
EXPORT_SYMBOL(iwl_chain_noise_calibration);
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index c87033bf3ad2..2c5c88fc38f5 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 {
* 1) Dual stream (MIMO)
* 2) Triple stream (MIMO)
*
- * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data
+ * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data
*
* Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"):
* 3-0: 0xD) 6 Mbps
@@ -320,11 +320,11 @@ struct iwl3945_power_per_rate {
#define RATE_MCS_GF_POS 10
#define RATE_MCS_GF_MSK 0x400
-/* Bit 11: (1) Use 40Mhz FAT chnl width, (0) use 20 MHz legacy chnl width */
-#define RATE_MCS_FAT_POS 11
-#define RATE_MCS_FAT_MSK 0x800
+/* Bit 11: (1) Use 40Mhz HT40 chnl width, (0) use 20 MHz legacy chnl width */
+#define RATE_MCS_HT40_POS 11
+#define RATE_MCS_HT40_MSK 0x800
-/* Bit 12: (1) Duplicate data on both 20MHz chnls. FAT (bit 11) must be set. */
+/* Bit 12: (1) Duplicate data on both 20MHz chnls. HT40 (bit 11) must be set. */
#define RATE_MCS_DUP_POS 12
#define RATE_MCS_DUP_MSK 0x1000
@@ -459,7 +459,7 @@ struct iwl_init_alive_resp {
/* calibration values from "initialize" uCode */
__le32 voltage; /* signed, higher value is lower voltage */
- __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for FAT channel*/
+ __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for HT40 */
__le32 therm_r2[2]; /* signed */
__le32 therm_r3[2]; /* signed */
__le32 therm_r4[2]; /* signed */
@@ -610,7 +610,7 @@ enum {
#define RXON_FLG_HT_OPERATING_MODE_POS (23)
#define RXON_FLG_HT_PROT_MSK cpu_to_le32(0x1 << 23)
-#define RXON_FLG_FAT_PROT_MSK cpu_to_le32(0x2 << 23)
+#define RXON_FLG_HT40_PROT_MSK cpu_to_le32(0x2 << 23)
#define RXON_FLG_CHANNEL_MODE_POS (25)
#define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25)
@@ -765,6 +765,8 @@ struct iwl5000_rxon_assoc_cmd {
} __attribute__ ((packed));
#define IWL_CONN_MAX_LISTEN_INTERVAL 10
+#define IWL_MAX_UCODE_BEACON_INTERVAL 4 /* 4096 */
+#define IWL39_MAX_UCODE_BEACON_INTERVAL 1 /* 1024 */
/*
* REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
@@ -884,12 +886,11 @@ struct iwl_qosparam_cmd {
#define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2);
#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8);
-#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8);
#define STA_FLG_RTS_MIMO_PROT_MSK cpu_to_le32(1 << 17)
#define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18)
#define STA_FLG_MAX_AGG_SIZE_POS (19)
#define STA_FLG_MAX_AGG_SIZE_MSK cpu_to_le32(3 << 19)
-#define STA_FLG_FAT_EN_MSK cpu_to_le32(1 << 21)
+#define STA_FLG_HT40_EN_MSK cpu_to_le32(1 << 21)
#define STA_FLG_MIMO_DIS_MSK cpu_to_le32(1 << 22)
#define STA_FLG_AGG_MPDU_DENSITY_POS (23)
#define STA_FLG_AGG_MPDU_DENSITY_MSK cpu_to_le32(7 << 23)
@@ -1154,6 +1155,7 @@ struct iwl_wep_cmd {
#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2)
#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3)
#define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0)
+#define RX_RES_PHY_FLAGS_ANTENNA_POS 4
#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8)
#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8)
@@ -1922,7 +1924,7 @@ struct iwl_link_qual_general_params {
#define LINK_QUAL_AGG_DISABLE_START_MIN (0)
#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31)
-#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (64)
+#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63)
#define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0)
/**
@@ -1982,10 +1984,10 @@ struct iwl_link_qual_agg_params {
* a) Use this same initial rate for first 3 entries.
* b) Find next lower available rate using same mode (SISO or MIMO),
* use for next 3 entries. If no lower rate available, switch to
- * legacy mode (no FAT channel, no MIMO, no short guard interval).
+ * legacy mode (no HT40 channel, no MIMO, no short guard interval).
* c) If using MIMO, set command's mimo_delimiter to number of entries
* using MIMO (3 or 6).
- * d) After trying 2 HT rates, switch to legacy mode (no FAT channel,
+ * d) After trying 2 HT rates, switch to legacy mode (no HT40 channel,
* no MIMO, no short guard interval), at the next lower bit rate
* (e.g. if second HT bit rate was 54, try 48 legacy), and follow
* legacy procedure for remaining table entries.
@@ -2311,15 +2313,22 @@ struct iwl_spectrum_notification {
* PM allow:
* bit 0 - '0' Driver not allow power management
* '1' Driver allow PM (use rest of parameters)
+ *
* uCode send sleep notifications:
* bit 1 - '0' Don't send sleep notification
* '1' send sleep notification (SEND_PM_NOTIFICATION)
+ *
* Sleep over DTIM
* bit 2 - '0' PM have to walk up every DTIM
* '1' PM could sleep over DTIM till listen Interval.
+ *
* PCI power managed
* bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1)
* '1' !(PCI_CFG_LINK_CTRL & 0x1)
+ *
+ * Fast PD
+ * bit 4 - '1' Put radio to sleep when receiving frame for others
+ *
* Force sleep Modes
* bit 31/30- '00' use both mac/xtal sleeps
* '01' force Mac sleep
@@ -2411,6 +2420,13 @@ struct iwl_ct_kill_config {
__le32 critical_temperature_R;
} __attribute__ ((packed));
+/* 1000, and 6x00 */
+struct iwl_ct_kill_throttling_config {
+ __le32 critical_temperature_exit;
+ __le32 reserved;
+ __le32 critical_temperature_enter;
+} __attribute__ ((packed));
+
/******************************************************************************
* (8)
* Scan Commands, Responses, Notifications:
@@ -2913,6 +2929,20 @@ struct statistics_rx {
struct statistics_rx_ht_phy ofdm_ht;
} __attribute__ ((packed));
+/**
+ * struct statistics_tx_power - current tx power
+ *
+ * @ant_a: current tx power on chain a in 1/2 dB step
+ * @ant_b: current tx power on chain b in 1/2 dB step
+ * @ant_c: current tx power on chain c in 1/2 dB step
+ */
+struct statistics_tx_power {
+ u8 ant_a;
+ u8 ant_b;
+ u8 ant_c;
+ u8 reserved;
+} __attribute__ ((packed));
+
struct statistics_tx_non_phy_agg {
__le32 ba_timeout;
__le32 ba_reschedule_frames;
@@ -2924,8 +2954,6 @@ struct statistics_tx_non_phy_agg {
__le32 underrun;
__le32 bt_prio_kill;
__le32 rx_ba_rsp_cnt;
- __le32 reserved2;
- __le32 reserved3;
} __attribute__ ((packed));
struct statistics_tx {
@@ -2944,6 +2972,8 @@ struct statistics_tx {
__le32 cts_timeout_collision;
__le32 ack_or_ba_timeout_collision;
struct statistics_tx_non_phy_agg agg;
+ struct statistics_tx_power tx_power;
+ __le32 reserved1;
} __attribute__ ((packed));
@@ -3008,7 +3038,7 @@ struct iwl_statistics_cmd {
* one channel that has just been scanned.
*/
#define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2)
-#define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8)
+#define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8)
struct iwl3945_notif_statistics {
__le32 flag;
@@ -3465,7 +3495,7 @@ struct iwl_wimax_coex_cmd {
*****************************************************************************/
struct iwl_rx_packet {
- __le32 len;
+ __le32 len_n_flags;
struct iwl_cmd_header hdr;
union {
struct iwl3945_rx_frame rx_frame;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 18b135f510e5..acfd7b40afb8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -59,6 +59,9 @@ MODULE_LICENSE("GPL");
IWL_RATE_##pp##M_INDEX, \
IWL_RATE_##np##M_INDEX }
+u32 iwl_debug_level;
+EXPORT_SYMBOL(iwl_debug_level);
+
static irqreturn_t iwl_isr(int irq, void *data);
/*
@@ -93,7 +96,6 @@ EXPORT_SYMBOL(iwl_rates);
void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
struct ieee80211_tx_info *info)
{
- int rate_index;
struct ieee80211_tx_rate *r = &info->control.rates[0];
info->antenna_sel_tx =
@@ -102,16 +104,13 @@ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
r->flags |= IEEE80211_TX_RC_MCS;
if (rate_n_flags & RATE_MCS_GF_MSK)
r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
- if (rate_n_flags & RATE_MCS_FAT_MSK)
+ if (rate_n_flags & RATE_MCS_HT40_MSK)
r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (rate_n_flags & RATE_MCS_DUP_MSK)
r->flags |= IEEE80211_TX_RC_DUP_DATA;
if (rate_n_flags & RATE_MCS_SGI_MSK)
r->flags |= IEEE80211_TX_RC_SHORT_GI;
- rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags);
- if (info->band == IEEE80211_BAND_5GHZ)
- rate_index -= IWL_FIRST_OFDM_RATE;
- r->idx = rate_index;
+ r->idx = iwl_hwrate_to_mac80211_idx(rate_n_flags, info->band);
}
EXPORT_SYMBOL(iwl_hwrate_to_tx_control);
@@ -146,6 +145,27 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
}
EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx);
+int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
+{
+ int idx = 0;
+ int band_offset = 0;
+
+ /* HT rate format: mac80211 wants an MCS number, which is just LSB */
+ if (rate_n_flags & RATE_MCS_HT_MSK) {
+ idx = (rate_n_flags & 0xff);
+ return idx;
+ /* Legacy rate format, search for match in table */
+ } else {
+ if (band == IEEE80211_BAND_5GHZ)
+ band_offset = IWL_FIRST_OFDM_RATE;
+ for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
+ if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
+ return idx - band_offset;
+ }
+
+ return -1;
+}
+
u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
{
int i;
@@ -391,13 +411,14 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
ht_info->ht_supported = true;
- ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
+ if (priv->cfg->ht_greenfield_support)
+ ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
(WLAN_HT_CAP_SM_PS_DISABLED << 2));
max_bit_rate = MAX_BIT_RATE_20_MHZ;
- if (priv->hw_params.fat_channel & BIT(band)) {
+ if (priv->hw_params.ht40_channel & BIT(band)) {
ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
ht_info->mcs.rx_mask[4] = 0x01;
@@ -435,12 +456,12 @@ static void iwlcore_init_hw_rates(struct iwl_priv *priv,
{
int i;
- for (i = 0; i < IWL_RATE_COUNT; i++) {
+ for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {
rates[i].bitrate = iwl_rates[i].ieee * 5;
rates[i].hw_value = i; /* Rate scaling will work on indexes */
rates[i].hw_value_short = i;
rates[i].flags = 0;
- if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) {
+ if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) {
/*
* If CCK != 1M then set short preamble rate flag.
*/
@@ -476,7 +497,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
if (!channels)
return -ENOMEM;
- rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)),
+ rates = kzalloc((sizeof(struct ieee80211_rate) * IWL_RATE_COUNT_LEGACY),
GFP_KERNEL);
if (!rates) {
kfree(channels);
@@ -488,7 +509,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
/* just OFDM */
sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
- sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE;
+ sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE;
if (priv->cfg->sku & IWL_SKU_N)
iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
@@ -498,7 +519,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
sband->channels = channels;
/* OFDM & CCK */
sband->bitrates = rates;
- sband->n_bitrates = IWL_RATE_COUNT;
+ sband->n_bitrates = IWL_RATE_COUNT_LEGACY;
if (priv->cfg->sku & IWL_SKU_N)
iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
@@ -537,17 +558,14 @@ int iwlcore_init_geos(struct iwl_priv *priv)
if (ch->flags & EEPROM_CHANNEL_RADAR)
geo_ch->flags |= IEEE80211_CHAN_RADAR;
- geo_ch->flags |= ch->fat_extension_channel;
+ geo_ch->flags |= ch->ht40_extension_channel;
- if (ch->max_power_avg > priv->tx_power_channel_lmt)
- priv->tx_power_channel_lmt = ch->max_power_avg;
+ if (ch->max_power_avg > priv->tx_power_device_lmt)
+ priv->tx_power_device_lmt = ch->max_power_avg;
} else {
geo_ch->flags |= IEEE80211_CHAN_DISABLED;
}
- /* Save flags for reg domain usage */
- geo_ch->orig_flags = geo_ch->flags;
-
IWL_DEBUG_INFO(priv, "Channel %d Freq=%d[%sGHz] %s flag=0x%X\n",
ch->channel, geo_ch->center_freq,
is_channel_a_band(ch) ? "5.2" : "2.4",
@@ -604,16 +622,16 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv,
return 0;
if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
- return !(ch_info->fat_extension_channel &
+ return !(ch_info->ht40_extension_channel &
IEEE80211_CHAN_NO_HT40PLUS);
else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
- return !(ch_info->fat_extension_channel &
+ return !(ch_info->ht40_extension_channel &
IEEE80211_CHAN_NO_HT40MINUS);
return 0;
}
-u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
+u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
struct ieee80211_sta_ht_cap *sta_ht_inf)
{
struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
@@ -629,11 +647,72 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
if (!sta_ht_inf->ht_supported)
return 0;
}
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (priv->disable_ht40)
+ return 0;
+#endif
return iwl_is_channel_extension(priv, priv->band,
le16_to_cpu(priv->staging_rxon.channel),
iwl_ht_conf->extension_chan_offset);
}
-EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
+EXPORT_SYMBOL(iwl_is_ht40_tx_allowed);
+
+static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
+{
+ u16 new_val = 0;
+ u16 beacon_factor = 0;
+
+ beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
+ new_val = beacon_val / beacon_factor;
+
+ if (!new_val)
+ new_val = max_beacon_val;
+
+ return new_val;
+}
+
+void iwl_setup_rxon_timing(struct iwl_priv *priv)
+{
+ u64 tsf;
+ s32 interval_tm, rem;
+ unsigned long flags;
+ struct ieee80211_conf *conf = NULL;
+ u16 beacon_int;
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
+ priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
+
+ if (priv->iw_mode == NL80211_IFTYPE_STATION) {
+ beacon_int = priv->beacon_int;
+ priv->rxon_timing.atim_window = 0;
+ } else {
+ beacon_int = priv->vif->bss_conf.beacon_int;
+
+ /* TODO: we need to get atim_window from upper stack
+ * for now we set to 0 */
+ priv->rxon_timing.atim_window = 0;
+ }
+
+ beacon_int = iwl_adjust_beacon_interval(beacon_int,
+ priv->hw_params.max_beacon_itrvl * 1024);
+ priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
+
+ tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
+ interval_tm = beacon_int * 1024;
+ rem = do_div(tsf, interval_tm);
+ priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_ASSOC(priv,
+ "beacon interval %d beacon timer %d beacon tim %d\n",
+ le16_to_cpu(priv->rxon_timing.beacon_interval),
+ le32_to_cpu(priv->rxon_timing.beacon_init_val),
+ le16_to_cpu(priv->rxon_timing.atim_window));
+}
+EXPORT_SYMBOL(iwl_setup_rxon_timing);
void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
{
@@ -805,7 +884,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
if (!ht_info->is_ht) {
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
- RXON_FLG_FAT_PROT_MSK |
+ RXON_FLG_HT40_PROT_MSK |
RXON_FLG_HT_PROT_MSK);
return;
}
@@ -816,12 +895,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS);
/* Set up channel bandwidth:
- * 20 MHz only, 20/40 mixed or pure 40 if fat ok */
+ * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
/* clear the HT channel mode before set the mode */
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
- if (iwl_is_fat_tx_allowed(priv, NULL)) {
- /* pure 40 fat */
+ if (iwl_is_ht40_tx_allowed(priv, NULL)) {
+ /* pure ht40 */
if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
/* Note: control channel is opposite of extension channel */
@@ -1076,7 +1155,6 @@ void iwl_set_flags_for_band(struct iwl_priv *priv,
priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
}
}
-EXPORT_SYMBOL(iwl_set_flags_for_band);
/*
* initialize rxon structure with default values from eeprom
@@ -1170,7 +1248,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
for (i = 0; i < hw->n_bitrates; i++) {
rate = &(hw->bitrates[i]);
- if (rate->hw_value < IWL_RATE_COUNT)
+ if (rate->hw_value < IWL_RATE_COUNT_LEGACY)
priv->active_rate |= (1 << rate->hw_value);
}
@@ -1231,9 +1309,191 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
}
-#endif
+
+static const char *desc_lookup_text[] = {
+ "OK",
+ "FAIL",
+ "BAD_PARAM",
+ "BAD_CHECKSUM",
+ "NMI_INTERRUPT_WDG",
+ "SYSASSERT",
+ "FATAL_ERROR",
+ "BAD_COMMAND",
+ "HW_ERROR_TUNE_LOCK",
+ "HW_ERROR_TEMPERATURE",
+ "ILLEGAL_CHAN_FREQ",
+ "VCC_NOT_STABLE",
+ "FH_ERROR",
+ "NMI_INTERRUPT_HOST",
+ "NMI_INTERRUPT_ACTION_PT",
+ "NMI_INTERRUPT_UNKNOWN",
+ "UCODE_VERSION_MISMATCH",
+ "HW_ERROR_ABS_LOCK",
+ "HW_ERROR_CAL_LOCK_FAIL",
+ "NMI_INTERRUPT_INST_ACTION_PT",
+ "NMI_INTERRUPT_DATA_ACTION_PT",
+ "NMI_TRM_HW_ER",
+ "NMI_INTERRUPT_TRM",
+ "NMI_INTERRUPT_BREAK_POINT"
+ "DEBUG_0",
+ "DEBUG_1",
+ "DEBUG_2",
+ "DEBUG_3",
+ "UNKNOWN"
+};
+
+static const char *desc_lookup(int i)
+{
+ int max = ARRAY_SIZE(desc_lookup_text) - 1;
+
+ if (i < 0 || i > max)
+ i = max;
+
+ return desc_lookup_text[i];
+}
+
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+ u32 data2, line;
+ u32 desc, time, count, base, data1;
+ u32 blink1, blink2, ilink1, ilink2;
+
+ if (priv->ucode_type == UCODE_INIT)
+ base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
+ else
+ base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+
+ if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+ IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
+ return;
+ }
+
+ count = iwl_read_targ_mem(priv, base);
+
+ if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+ IWL_ERR(priv, "Start IWL Error Log Dump:\n");
+ IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
+ priv->status, count);
+ }
+
+ desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
+ blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
+ blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
+ ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
+ ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
+ data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
+ data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
+ line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
+ time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
+
+ IWL_ERR(priv, "Desc Time "
+ "data1 data2 line\n");
+ IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
+ desc_lookup(desc), desc, time, data1, data2, line);
+ IWL_ERR(priv, "blink1 blink2 ilink1 ilink2\n");
+ IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
+ ilink1, ilink2);
+
+}
+
+#define EVENT_START_OFFSET (4 * sizeof(u32))
/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ */
+static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+ u32 num_events, u32 mode)
+{
+ u32 i;
+ u32 base; /* SRAM byte address of event log header */
+ u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+ u32 ptr; /* SRAM byte address of log data */
+ u32 ev, time, data; /* event log data */
+
+ if (num_events == 0)
+ return;
+ if (priv->ucode_type == UCODE_INIT)
+ base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+ else
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+ if (mode == 0)
+ event_size = 2 * sizeof(u32);
+ else
+ event_size = 3 * sizeof(u32);
+
+ ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+ /* "time" is actually "data" for mode 0 (no timestamp).
+ * place event id # at far right for easier visual parsing. */
+ for (i = 0; i < num_events; i++) {
+ ev = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ time = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ if (mode == 0) {
+ /* data, ev */
+ IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
+ } else {
+ data = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
+ time, data, ev);
+ }
+ }
+}
+
+void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+ u32 base; /* SRAM byte address of event log header */
+ u32 capacity; /* event log capacity in # entries */
+ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
+ u32 num_wraps; /* # times uCode wrapped to top of log */
+ u32 next_entry; /* index of next entry to be written by uCode */
+ u32 size; /* # entries that we'll print */
+
+ if (priv->ucode_type == UCODE_INIT)
+ base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+ else
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+ if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+ IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
+ return;
+ }
+
+ /* event log header */
+ capacity = iwl_read_targ_mem(priv, base);
+ mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
+ num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
+ next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+
+ size = num_wraps ? capacity : next_entry;
+
+ /* bail out if nothing in log */
+ if (size == 0) {
+ IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
+ return;
+ }
+
+ IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
+ size, num_wraps);
+
+ /* if uCode has wrapped back to top of log, start at the oldest entry,
+ * i.e the next one that uCode would fill. */
+ if (num_wraps)
+ iwl_print_event_log(priv, next_entry,
+ capacity - next_entry, mode);
+ /* (then/else) start at top of log */
+ iwl_print_event_log(priv, 0, next_entry, mode);
+
+}
+#endif
+/**
* iwl_irq_handle_error - called for HW or SW error interrupt from card
*/
void iwl_irq_handle_error(struct iwl_priv *priv)
@@ -1245,7 +1505,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_FW_ERRORS) {
+ if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) {
iwl_dump_nic_error_log(priv);
iwl_dump_nic_event_log(priv);
iwl_print_rx_config_cmd(priv);
@@ -1271,7 +1531,7 @@ EXPORT_SYMBOL(iwl_irq_handle_error);
void iwl_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
- int mc_count, struct dev_addr_list *mc_list)
+ u64 multicast)
{
struct iwl_priv *priv = hw->priv;
__le32 *filter_flags = &priv->staging_rxon.filter_flags;
@@ -1325,7 +1585,9 @@ int iwl_setup_mac(struct iwl_priv *priv)
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_SPECTRUM_MGMT;
+ IEEE80211_HW_SPECTRUM_MGMT |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
@@ -1335,6 +1597,12 @@ int iwl_setup_mac(struct iwl_priv *priv)
/* Firmware does not support this */
hw->wiphy->disable_beacon_hints = true;
+ /*
+ * For now, disable PS by default because it affects
+ * RX performance significantly.
+ */
+ hw->wiphy->ps_default = false;
+
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
/* we create the 802.11 header and a zero-length SSID element */
hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
@@ -1364,7 +1632,6 @@ EXPORT_SYMBOL(iwl_setup_mac);
int iwl_set_hw_params(struct iwl_priv *priv)
{
- priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto;
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
if (priv->cfg->mod_params->amsdu_size_8K)
@@ -1373,6 +1640,8 @@ int iwl_set_hw_params(struct iwl_priv *priv)
priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K;
priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256;
+ priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
+
if (priv->cfg->mod_params->disable_11n)
priv->cfg->sku &= ~IWL_SKU_N;
@@ -1419,9 +1688,10 @@ int iwl_init_drv(struct iwl_priv *priv)
priv->qos_data.qos_cap.val = 0;
priv->rates_mask = IWL_RATES_MASK;
- /* If power management is turned on, default to CAM mode */
- priv->power_mode = IWL_POWER_MODE_CAM;
- priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX;
+ /* Set the tx_power_user_lmt to the lowest power level
+ * this value will get overwritten by channel max power avg
+ * from eeprom */
+ priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MIN;
ret = iwl_init_channel_map(priv);
if (ret) {
@@ -1448,6 +1718,8 @@ EXPORT_SYMBOL(iwl_init_drv);
int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
{
int ret = 0;
+ s8 prev_tx_power = priv->tx_power_user_lmt;
+
if (tx_power < IWL_TX_POWER_TARGET_POWER_MIN) {
IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n",
tx_power,
@@ -1455,25 +1727,37 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
return -EINVAL;
}
- if (tx_power > IWL_TX_POWER_TARGET_POWER_MAX) {
- IWL_WARN(priv, "Requested user TXPOWER %d above upper limit %d.\n",
- tx_power,
- IWL_TX_POWER_TARGET_POWER_MAX);
+ if (tx_power > priv->tx_power_device_lmt) {
+ IWL_WARN(priv,
+ "Requested user TXPOWER %d above upper limit %d.\n",
+ tx_power, priv->tx_power_device_lmt);
return -EINVAL;
}
if (priv->tx_power_user_lmt != tx_power)
force = true;
- priv->tx_power_user_lmt = tx_power;
-
/* if nic is not up don't send command */
- if (!iwl_is_ready_rf(priv))
- return ret;
-
- if (force && priv->cfg->ops->lib->send_tx_power)
- ret = priv->cfg->ops->lib->send_tx_power(priv);
+ if (iwl_is_ready_rf(priv)) {
+ priv->tx_power_user_lmt = tx_power;
+ if (force && priv->cfg->ops->lib->send_tx_power)
+ ret = priv->cfg->ops->lib->send_tx_power(priv);
+ else if (!priv->cfg->ops->lib->send_tx_power)
+ ret = -EOPNOTSUPP;
+ /*
+ * if fail to set tx_power, restore the orig. tx power
+ */
+ if (ret)
+ priv->tx_power_user_lmt = prev_tx_power;
+ }
+ /*
+ * Even this is an async host command, the command
+ * will always report success from uCode
+ * So once driver can placing the command into the queue
+ * successfully, driver can use priv->tx_power_user_lmt
+ * to reflect the current tx power
+ */
return ret;
}
EXPORT_SYMBOL(iwl_set_tx_power);
@@ -1487,31 +1771,6 @@ void iwl_uninit_drv(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_uninit_drv);
-
-void iwl_disable_interrupts(struct iwl_priv *priv)
-{
- clear_bit(STATUS_INT_ENABLED, &priv->status);
-
- /* disable interrupts from uCode/NIC to host */
- iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
- /* acknowledge/clear/reset any interrupts still pending
- * from uCode or flow handler (Rx/Tx DMA) */
- iwl_write32(priv, CSR_INT, 0xffffffff);
- iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
- IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
-}
-EXPORT_SYMBOL(iwl_disable_interrupts);
-
-void iwl_enable_interrupts(struct iwl_priv *priv)
-{
- IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
- set_bit(STATUS_INT_ENABLED, &priv->status);
- iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
-}
-EXPORT_SYMBOL(iwl_enable_interrupts);
-
-
#define ICT_COUNT (PAGE_SIZE/sizeof(u32))
/* Free dram table */
@@ -1581,7 +1840,7 @@ int iwl_reset_ict(struct iwl_priv *priv)
spin_lock_irqsave(&priv->lock, flags);
iwl_disable_interrupts(priv);
- memset(&priv->ict_tbl[0],0, sizeof(u32) * ICT_COUNT);
+ memset(&priv->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT);
val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT;
@@ -1659,13 +1918,13 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
/* read all entries that not 0 start with ict_index */
while (priv->ict_tbl[priv->ict_index]) {
- val |= priv->ict_tbl[priv->ict_index];
+ val |= le32_to_cpu(priv->ict_tbl[priv->ict_index]);
IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n",
- priv->ict_index,
- priv->ict_tbl[priv->ict_index]);
+ priv->ict_index,
+ le32_to_cpu(priv->ict_tbl[priv->ict_index]));
priv->ict_tbl[priv->ict_index] = 0;
priv->ict_index = iwl_queue_inc_wrap(priv->ict_index,
- ICT_COUNT);
+ ICT_COUNT);
}
@@ -1745,7 +2004,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, "
"fh 0x%08x\n", inta, inta_mask, inta_fh);
@@ -1852,7 +2111,7 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
u32 stat_flags = 0;
struct iwl_host_cmd cmd = {
.id = REPLY_STATISTICS_CMD,
- .meta.flags = flags,
+ .flags = flags,
.len = sizeof(stat_flags),
.data = (u8 *) &stat_flags,
};
@@ -1984,194 +2243,10 @@ int iwl_verify_ucode(struct iwl_priv *priv)
EXPORT_SYMBOL(iwl_verify_ucode);
-static const char *desc_lookup_text[] = {
- "OK",
- "FAIL",
- "BAD_PARAM",
- "BAD_CHECKSUM",
- "NMI_INTERRUPT_WDG",
- "SYSASSERT",
- "FATAL_ERROR",
- "BAD_COMMAND",
- "HW_ERROR_TUNE_LOCK",
- "HW_ERROR_TEMPERATURE",
- "ILLEGAL_CHAN_FREQ",
- "VCC_NOT_STABLE",
- "FH_ERROR",
- "NMI_INTERRUPT_HOST",
- "NMI_INTERRUPT_ACTION_PT",
- "NMI_INTERRUPT_UNKNOWN",
- "UCODE_VERSION_MISMATCH",
- "HW_ERROR_ABS_LOCK",
- "HW_ERROR_CAL_LOCK_FAIL",
- "NMI_INTERRUPT_INST_ACTION_PT",
- "NMI_INTERRUPT_DATA_ACTION_PT",
- "NMI_TRM_HW_ER",
- "NMI_INTERRUPT_TRM",
- "NMI_INTERRUPT_BREAK_POINT"
- "DEBUG_0",
- "DEBUG_1",
- "DEBUG_2",
- "DEBUG_3",
- "UNKNOWN"
-};
-
-static const char *desc_lookup(int i)
-{
- int max = ARRAY_SIZE(desc_lookup_text) - 1;
-
- if (i < 0 || i > max)
- i = max;
-
- return desc_lookup_text[i];
-}
-
-#define ERROR_START_OFFSET (1 * sizeof(u32))
-#define ERROR_ELEM_SIZE (7 * sizeof(u32))
-
-void iwl_dump_nic_error_log(struct iwl_priv *priv)
-{
- u32 data2, line;
- u32 desc, time, count, base, data1;
- u32 blink1, blink2, ilink1, ilink2;
-
- if (priv->ucode_type == UCODE_INIT)
- base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
- else
- base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
-
- if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
- IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
- return;
- }
-
- count = iwl_read_targ_mem(priv, base);
-
- if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
- IWL_ERR(priv, "Start IWL Error Log Dump:\n");
- IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
- priv->status, count);
- }
-
- desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
- blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
- blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
- ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
- ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
- data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
- data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
- line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
- time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
-
- IWL_ERR(priv, "Desc Time "
- "data1 data2 line\n");
- IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
- desc_lookup(desc), desc, time, data1, data2, line);
- IWL_ERR(priv, "blink1 blink2 ilink1 ilink2\n");
- IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
- ilink1, ilink2);
-
-}
-EXPORT_SYMBOL(iwl_dump_nic_error_log);
-
-#define EVENT_START_OFFSET (4 * sizeof(u32))
-
-/**
- * iwl_print_event_log - Dump error event log to syslog
- *
- */
-static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
- u32 num_events, u32 mode)
-{
- u32 i;
- u32 base; /* SRAM byte address of event log header */
- u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
- u32 ptr; /* SRAM byte address of log data */
- u32 ev, time, data; /* event log data */
-
- if (num_events == 0)
- return;
- if (priv->ucode_type == UCODE_INIT)
- base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
- else
- base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-
- if (mode == 0)
- event_size = 2 * sizeof(u32);
- else
- event_size = 3 * sizeof(u32);
-
- ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
-
- /* "time" is actually "data" for mode 0 (no timestamp).
- * place event id # at far right for easier visual parsing. */
- for (i = 0; i < num_events; i++) {
- ev = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- time = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- if (mode == 0) {
- /* data, ev */
- IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
- } else {
- data = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
- time, data, ev);
- }
- }
-}
-
-void iwl_dump_nic_event_log(struct iwl_priv *priv)
-{
- u32 base; /* SRAM byte address of event log header */
- u32 capacity; /* event log capacity in # entries */
- u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
- u32 num_wraps; /* # times uCode wrapped to top of log */
- u32 next_entry; /* index of next entry to be written by uCode */
- u32 size; /* # entries that we'll print */
-
- if (priv->ucode_type == UCODE_INIT)
- base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
- else
- base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-
- if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
- IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
- return;
- }
-
- /* event log header */
- capacity = iwl_read_targ_mem(priv, base);
- mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
- num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
- next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
-
- size = num_wraps ? capacity : next_entry;
-
- /* bail out if nothing in log */
- if (size == 0) {
- IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
- return;
- }
-
- IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
- size, num_wraps);
-
- /* if uCode has wrapped back to top of log, start at the oldest entry,
- * i.e the next one that uCode would fill. */
- if (num_wraps)
- iwl_print_event_log(priv, next_entry,
- capacity - next_entry, mode);
- /* (then/else) start at top of log */
- iwl_print_event_log(priv, 0, next_entry, mode);
-
-}
-EXPORT_SYMBOL(iwl_dump_nic_event_log);
-
void iwl_rf_kill_ct_config(struct iwl_priv *priv)
{
struct iwl_ct_kill_config cmd;
+ struct iwl_ct_kill_throttling_config adv_cmd;
unsigned long flags;
int ret = 0;
@@ -2179,18 +2254,44 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
spin_unlock_irqrestore(&priv->lock, flags);
+ priv->thermal_throttle.ct_kill_toggle = false;
+
+ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+ case CSR_HW_REV_TYPE_1000:
+ case CSR_HW_REV_TYPE_6x00:
+ case CSR_HW_REV_TYPE_6x50:
+ adv_cmd.critical_temperature_enter =
+ cpu_to_le32(priv->hw_params.ct_kill_threshold);
+ adv_cmd.critical_temperature_exit =
+ cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
+
+ ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
+ sizeof(adv_cmd), &adv_cmd);
+ if (ret)
+ IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
+ else
+ IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
+ "succeeded, "
+ "critical temperature enter is %d,"
+ "exit is %d\n",
+ priv->hw_params.ct_kill_threshold,
+ priv->hw_params.ct_kill_exit_threshold);
+ break;
+ default:
+ cmd.critical_temperature_R =
+ cpu_to_le32(priv->hw_params.ct_kill_threshold);
- cmd.critical_temperature_R =
- cpu_to_le32(priv->hw_params.ct_kill_threshold);
-
- ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
- sizeof(cmd), &cmd);
- if (ret)
- IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
- else
- IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD succeeded, "
- "critical temperature is %d\n",
- cmd.critical_temperature_R);
+ ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
+ sizeof(cmd), &cmd);
+ if (ret)
+ IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
+ else
+ IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
+ "succeeded, "
+ "critical temperature is %d\n",
+ priv->hw_params.ct_kill_threshold);
+ break;
+ }
}
EXPORT_SYMBOL(iwl_rf_kill_ct_config);
@@ -2211,12 +2312,11 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
.id = REPLY_CARD_STATE_CMD,
.len = sizeof(u32),
.data = &flags,
- .meta.flags = meta_flag,
+ .flags = meta_flag,
};
return iwl_send_cmd(priv, &cmd);
}
-EXPORT_SYMBOL(iwl_send_card_state);
void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
@@ -2234,10 +2334,11 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
- "notification for %s:\n",
- le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
- iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+ "notification for %s:\n", len,
+ get_cmd_string(pkt->hdr.cmd));
+ iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len);
}
EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
@@ -2260,7 +2361,6 @@ void iwl_clear_isr_stats(struct iwl_priv *priv)
{
memset(&priv->isr_stats, 0, sizeof(priv->isr_stats));
}
-EXPORT_SYMBOL(iwl_clear_isr_stats);
int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
@@ -2333,39 +2433,10 @@ static void iwl_ht_conf(struct iwl_priv *priv,
}
ht_conf = &sta->ht_cap;
- if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
- iwl_conf->sgf |= HT_SHORT_GI_20MHZ;
- if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
- iwl_conf->sgf |= HT_SHORT_GI_40MHZ;
-
- iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
- iwl_conf->max_amsdu_size =
- !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
-
- iwl_conf->supported_chan_width =
- !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
-
- /*
- * XXX: The HT configuration needs to be moved into iwl_mac_config()
- * to be done there correctly.
- */
-
- iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
- if (conf_is_ht40_minus(&priv->hw->conf))
- iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
- else if (conf_is_ht40_plus(&priv->hw->conf))
- iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-
- /* If no above or below channel supplied disable FAT channel */
- if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE &&
- iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW)
- iwl_conf->supported_chan_width = 0;
-
iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
- iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0;
iwl_conf->ht_protection =
bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
iwl_conf->non_GF_STA_present =
@@ -2492,7 +2563,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
if (bss_conf->assoc) {
priv->assoc_id = bss_conf->aid;
priv->beacon_int = bss_conf->beacon_int;
- priv->power_data.dtim_period = bss_conf->dtim_period;
priv->timestamp = bss_conf->timestamp;
priv->assoc_capability = bss_conf->assoc_capability;
@@ -2679,6 +2749,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
struct iwl_priv *priv = hw->priv;
const struct iwl_channel_info *ch_info;
struct ieee80211_conf *conf = &hw->conf;
+ struct iwl_ht_info *ht_conf = &priv->current_ht_config;
unsigned long flags = 0;
int ret = 0;
u16 ch;
@@ -2720,10 +2791,32 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
goto set_ch_out;
}
- priv->current_ht_config.is_ht = conf_is_ht(conf);
-
spin_lock_irqsave(&priv->lock, flags);
+ /* Configure HT40 channels */
+ ht_conf->is_ht = conf_is_ht(conf);
+ if (ht_conf->is_ht) {
+ if (conf_is_ht40_minus(conf)) {
+ ht_conf->extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ ht_conf->supported_chan_width =
+ IWL_CHANNEL_WIDTH_40MHZ;
+ } else if (conf_is_ht40_plus(conf)) {
+ ht_conf->extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ ht_conf->supported_chan_width =
+ IWL_CHANNEL_WIDTH_40MHZ;
+ } else {
+ ht_conf->extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ ht_conf->supported_chan_width =
+ IWL_CHANNEL_WIDTH_20MHZ;
+ }
+ } else
+ ht_conf->supported_chan_width = IWL_CHANNEL_WIDTH_20MHZ;
+ /* Default to no protection. Protection mode will later be set
+ * from BSS config in iwl_ht_conf */
+ ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
/* if we are switching from ht to 2.4 clear flags
* from any ht related info since 2.4 does not
@@ -2742,13 +2835,10 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
iwl_set_rate(priv);
}
- if (changed & IEEE80211_CONF_CHANGE_PS &&
- priv->iw_mode == NL80211_IFTYPE_STATION) {
- priv->power_data.power_disabled =
- !(conf->flags & IEEE80211_CONF_PS);
- ret = iwl_power_update_mode(priv, 0);
+ if (changed & IEEE80211_CONF_CHANGE_PS) {
+ ret = iwl_power_update_mode(priv, false);
if (ret)
- IWL_DEBUG_MAC80211(priv, "Error setting power level\n");
+ IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
@@ -2881,6 +2971,248 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(iwl_mac_reset_tsf);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+
+#define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)
+
+void iwl_reset_traffic_log(struct iwl_priv *priv)
+{
+ priv->tx_traffic_idx = 0;
+ priv->rx_traffic_idx = 0;
+ if (priv->tx_traffic)
+ memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
+ if (priv->rx_traffic)
+ memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
+}
+
+int iwl_alloc_traffic_mem(struct iwl_priv *priv)
+{
+ u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE;
+
+ if (iwl_debug_level & IWL_DL_TX) {
+ if (!priv->tx_traffic) {
+ priv->tx_traffic =
+ kzalloc(traffic_size, GFP_KERNEL);
+ if (!priv->tx_traffic)
+ return -ENOMEM;
+ }
+ }
+ if (iwl_debug_level & IWL_DL_RX) {
+ if (!priv->rx_traffic) {
+ priv->rx_traffic =
+ kzalloc(traffic_size, GFP_KERNEL);
+ if (!priv->rx_traffic)
+ return -ENOMEM;
+ }
+ }
+ iwl_reset_traffic_log(priv);
+ return 0;
+}
+EXPORT_SYMBOL(iwl_alloc_traffic_mem);
+
+void iwl_free_traffic_mem(struct iwl_priv *priv)
+{
+ kfree(priv->tx_traffic);
+ priv->tx_traffic = NULL;
+
+ kfree(priv->rx_traffic);
+ priv->rx_traffic = NULL;
+}
+EXPORT_SYMBOL(iwl_free_traffic_mem);
+
+void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
+ u16 length, struct ieee80211_hdr *header)
+{
+ __le16 fc;
+ u16 len;
+
+ if (likely(!(iwl_debug_level & IWL_DL_TX)))
+ return;
+
+ if (!priv->tx_traffic)
+ return;
+
+ fc = header->frame_control;
+ if (ieee80211_is_data(fc)) {
+ len = (length > IWL_TRAFFIC_ENTRY_SIZE)
+ ? IWL_TRAFFIC_ENTRY_SIZE : length;
+ memcpy((priv->tx_traffic +
+ (priv->tx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
+ header, len);
+ priv->tx_traffic_idx =
+ (priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
+ }
+}
+EXPORT_SYMBOL(iwl_dbg_log_tx_data_frame);
+
+void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
+ u16 length, struct ieee80211_hdr *header)
+{
+ __le16 fc;
+ u16 len;
+
+ if (likely(!(iwl_debug_level & IWL_DL_RX)))
+ return;
+
+ if (!priv->rx_traffic)
+ return;
+
+ fc = header->frame_control;
+ if (ieee80211_is_data(fc)) {
+ len = (length > IWL_TRAFFIC_ENTRY_SIZE)
+ ? IWL_TRAFFIC_ENTRY_SIZE : length;
+ memcpy((priv->rx_traffic +
+ (priv->rx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
+ header, len);
+ priv->rx_traffic_idx =
+ (priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
+ }
+}
+EXPORT_SYMBOL(iwl_dbg_log_rx_data_frame);
+
+const char *get_mgmt_string(int cmd)
+{
+ switch (cmd) {
+ IWL_CMD(MANAGEMENT_ASSOC_REQ);
+ IWL_CMD(MANAGEMENT_ASSOC_RESP);
+ IWL_CMD(MANAGEMENT_REASSOC_REQ);
+ IWL_CMD(MANAGEMENT_REASSOC_RESP);
+ IWL_CMD(MANAGEMENT_PROBE_REQ);
+ IWL_CMD(MANAGEMENT_PROBE_RESP);
+ IWL_CMD(MANAGEMENT_BEACON);
+ IWL_CMD(MANAGEMENT_ATIM);
+ IWL_CMD(MANAGEMENT_DISASSOC);
+ IWL_CMD(MANAGEMENT_AUTH);
+ IWL_CMD(MANAGEMENT_DEAUTH);
+ IWL_CMD(MANAGEMENT_ACTION);
+ default:
+ return "UNKNOWN";
+
+ }
+}
+
+const char *get_ctrl_string(int cmd)
+{
+ switch (cmd) {
+ IWL_CMD(CONTROL_BACK_REQ);
+ IWL_CMD(CONTROL_BACK);
+ IWL_CMD(CONTROL_PSPOLL);
+ IWL_CMD(CONTROL_RTS);
+ IWL_CMD(CONTROL_CTS);
+ IWL_CMD(CONTROL_ACK);
+ IWL_CMD(CONTROL_CFEND);
+ IWL_CMD(CONTROL_CFENDACK);
+ default:
+ return "UNKNOWN";
+
+ }
+}
+
+void iwl_clear_tx_stats(struct iwl_priv *priv)
+{
+ memset(&priv->tx_stats, 0, sizeof(struct traffic_stats));
+
+}
+
+void iwl_clear_rx_stats(struct iwl_priv *priv)
+{
+ memset(&priv->rx_stats, 0, sizeof(struct traffic_stats));
+}
+
+/*
+ * if CONFIG_IWLWIFI_DEBUGFS defined, iwl_update_stats function will
+ * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass.
+ * Use debugFs to display the rx/rx_statistics
+ * if CONFIG_IWLWIFI_DEBUGFS not being defined, then no MGMT and CTRL
+ * information will be recorded, but DATA pkt still will be recorded
+ * for the reason of iwl_led.c need to control the led blinking based on
+ * number of tx and rx data.
+ *
+ */
+void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
+{
+ struct traffic_stats *stats;
+
+ if (is_tx)
+ stats = &priv->tx_stats;
+ else
+ stats = &priv->rx_stats;
+
+ if (ieee80211_is_mgmt(fc)) {
+ switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+ case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
+ stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
+ stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
+ stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
+ stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
+ stats->mgmt[MANAGEMENT_PROBE_REQ]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
+ stats->mgmt[MANAGEMENT_PROBE_RESP]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_BEACON):
+ stats->mgmt[MANAGEMENT_BEACON]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_ATIM):
+ stats->mgmt[MANAGEMENT_ATIM]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
+ stats->mgmt[MANAGEMENT_DISASSOC]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_AUTH):
+ stats->mgmt[MANAGEMENT_AUTH]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+ stats->mgmt[MANAGEMENT_DEAUTH]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_ACTION):
+ stats->mgmt[MANAGEMENT_ACTION]++;
+ break;
+ }
+ } else if (ieee80211_is_ctl(fc)) {
+ switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+ case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
+ stats->ctrl[CONTROL_BACK_REQ]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_BACK):
+ stats->ctrl[CONTROL_BACK]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
+ stats->ctrl[CONTROL_PSPOLL]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_RTS):
+ stats->ctrl[CONTROL_RTS]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_CTS):
+ stats->ctrl[CONTROL_CTS]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_ACK):
+ stats->ctrl[CONTROL_ACK]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_CFEND):
+ stats->ctrl[CONTROL_CFEND]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
+ stats->ctrl[CONTROL_CFENDACK]++;
+ break;
+ }
+ } else {
+ /* data */
+ stats->data_cnt++;
+ stats->data_bytes += len;
+ }
+}
+EXPORT_SYMBOL(iwl_update_stats);
+#endif
+
#ifdef CONFIG_PM
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 dabf663e36e5..c04d2a270819 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -83,6 +83,8 @@ struct iwl_cmd;
#define IWL_SKU_A 0x2
#define IWL_SKU_N 0x8
+#define IWL_CMD(x) case x: return #x
+
struct iwl_hcmd_ops {
int (*rxon_assoc)(struct iwl_priv *priv);
int (*commit_rxon)(struct iwl_priv *priv);
@@ -116,6 +118,17 @@ struct iwl_temp_ops {
void (*set_ct_kill)(struct iwl_priv *priv);
};
+struct iwl_ucode_ops {
+ u32 (*get_header_size)(u32);
+ u32 (*get_build)(const struct iwl_ucode_header *, u32);
+ u32 (*get_inst_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_data_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_init_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_boot_size)(const struct iwl_ucode_header *, u32);
+ u8 * (*get_data)(const struct iwl_ucode_header *, u32);
+};
+
struct iwl_lib_ops {
/* set hw dependent parameters */
int (*set_hw_params)(struct iwl_priv *priv);
@@ -171,6 +184,7 @@ struct iwl_lib_ops {
};
struct iwl_ops {
+ const struct iwl_ucode_ops *ucode;
const struct iwl_lib_ops *lib;
const struct iwl_hcmd_ops *hcmd;
const struct iwl_hcmd_utils_ops *utils;
@@ -178,7 +192,6 @@ struct iwl_ops {
struct iwl_mod_params {
int sw_crypto; /* def: 0 = using hardware encryption */
- u32 debug; /* def: 0 = minimal debug log messages */
int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_queues; /* def: HW dependent */
int num_of_ampdu_queues;/* def: HW dependent */
@@ -195,6 +208,9 @@ struct iwl_mod_params {
* filename is constructed as fw_name_pre<api>.ucode.
* @ucode_api_max: Highest version of uCode API supported by driver.
* @ucode_api_min: Lowest version of uCode API supported by driver.
+ * @pa_type: used by 6000 series only to identify the type of Power Amplifier
+ * @max_ll_items: max number of OTP blocks
+ * @shadow_ram_support: shadow support for OTP memory
*
* We enable the driver to be backward compatible wrt API version. The
* driver specifies which APIs it supports (with @ucode_api_max being the
@@ -215,6 +231,7 @@ struct iwl_mod_params {
* iwl_hcmd_utils_ops etc. we accommodate different command structures
* and flows between hardware versions (4965/5000) as well as their API
* versions.
+ *
*/
struct iwl_cfg {
const char *name;
@@ -231,6 +248,10 @@ struct iwl_cfg {
u8 valid_rx_ant;
bool need_pll_cfg;
bool use_isr_legacy;
+ enum iwl_pa_type pa_type;
+ const u16 max_ll_items;
+ const bool shadow_ram_support;
+ const bool ht_greenfield_support;
};
/***************************
@@ -250,7 +271,7 @@ int iwl_full_rxon_required(struct iwl_priv *priv);
void iwl_set_rxon_chain(struct iwl_priv *priv);
int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info);
-u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
+u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
struct ieee80211_sta_ht_cap *sta_ht_inf);
void iwl_set_flags_for_band(struct iwl_priv *priv, enum ieee80211_band band);
void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode);
@@ -261,8 +282,7 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv,
void iwl_irq_handle_error(struct iwl_priv *priv);
void iwl_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
- unsigned int *total_flags,
- int mc_count, struct dev_addr_list *mc_list);
+ unsigned int *total_flags, u64 multicast);
int iwl_hw_nic_init(struct iwl_priv *priv);
int iwl_setup_mac(struct iwl_priv *priv);
int iwl_set_hw_params(struct iwl_priv *priv);
@@ -286,7 +306,55 @@ void iwl_config_ap(struct iwl_priv *priv);
int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
struct ieee80211_tx_queue_stats *stats);
void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+int iwl_alloc_traffic_mem(struct iwl_priv *priv);
+void iwl_free_traffic_mem(struct iwl_priv *priv);
+void iwl_reset_traffic_log(struct iwl_priv *priv);
+void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
+ u16 length, struct ieee80211_hdr *header);
+void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
+ u16 length, struct ieee80211_hdr *header);
+const char *get_mgmt_string(int cmd);
+const char *get_ctrl_string(int cmd);
+void iwl_clear_tx_stats(struct iwl_priv *priv);
+void iwl_clear_rx_stats(struct iwl_priv *priv);
+void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc,
+ u16 len);
+#else
+static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv)
+{
+ return 0;
+}
+static inline void iwl_free_traffic_mem(struct iwl_priv *priv)
+{
+}
+static inline void iwl_reset_traffic_log(struct iwl_priv *priv)
+{
+}
+static inline void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
+ u16 length, struct ieee80211_hdr *header)
+{
+}
+static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
+ u16 length, struct ieee80211_hdr *header)
+{
+}
+static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx,
+ __le16 fc, u16 len)
+{
+ struct traffic_stats *stats;
+
+ if (is_tx)
+ stats = &priv->tx_stats;
+ else
+ stats = &priv->rx_stats;
+ if (ieee80211_is_data(fc)) {
+ /* data */
+ stats->data_bytes += len;
+ }
+}
+#endif
/*****************************************************
* RX handlers.
* **************************************************/
@@ -355,6 +423,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
struct ieee80211_tx_info *info);
int iwl_hwrate_to_plcp_idx(u32 rate_n_flags);
+int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv);
@@ -384,7 +453,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
void iwl_init_scan_params(struct iwl_priv *priv);
int iwl_scan_cancel(struct iwl_priv *priv);
int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
-int iwl_scan_initiate(struct iwl_priv *priv);
int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
const u8 *ie, int ie_len, int left);
@@ -398,7 +466,6 @@ void iwl_bg_scan_check(struct work_struct *data);
void iwl_bg_abort_scan(struct work_struct *work);
void iwl_bg_scan_completed(struct work_struct *work);
void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
-int iwl_send_scan_abort(struct iwl_priv *priv);
/* For faster active scanning, scan will move to the next channel if fewer than
* PLCP_QUIET_THRESH packets are heard on this channel within
@@ -437,9 +504,9 @@ int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id,
u16 len, const void *data);
int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
const void *data,
- int (*callback)(struct iwl_priv *priv,
- struct iwl_cmd *cmd,
- struct sk_buff *skb));
+ void (*callback)(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb));
int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
@@ -449,8 +516,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags,
/*****************************************************
* PCI *
*****************************************************/
-void iwl_disable_interrupts(struct iwl_priv *priv);
-void iwl_enable_interrupts(struct iwl_priv *priv);
irqreturn_t iwl_isr_legacy(int irq, void *data);
int iwl_reset_ict(struct iwl_priv *priv);
void iwl_disable_ict(struct iwl_priv *priv);
@@ -474,7 +539,6 @@ int iwl_pci_resume(struct pci_dev *pdev);
/*****************************************************
* Error Handling Debugging
******************************************************/
-void iwl_dump_nic_error_log(struct iwl_priv *priv);
void iwl_dump_nic_event_log(struct iwl_priv *priv);
void iwl_clear_isr_stats(struct iwl_priv *priv);
@@ -556,6 +620,7 @@ extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
+void iwl_setup_rxon_timing(struct iwl_priv *priv);
static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
{
return priv->cfg->ops->hcmd->rxon_assoc(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index f03dae1b2f36..06437d13e73e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -91,7 +91,8 @@
#define CSR_EEPROM_GP (CSR_BASE+0x030)
#define CSR_OTP_GP_REG (CSR_BASE+0x034)
#define CSR_GIO_REG (CSR_BASE+0x03C)
-#define CSR_GP_UCODE (CSR_BASE+0x044)
+#define CSR_GP_UCODE_REG (CSR_BASE+0x048)
+#define CSR_GP_DRIVER_REG (CSR_BASE+0x050)
#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054)
#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
@@ -245,6 +246,13 @@
#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004)
#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008)
+/* GP Driver */
+#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_MSK (0x00000003)
+#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_3x3_HYB (0x00000000)
+#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB (0x00000001)
+#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002)
+
+
/* GI Chicken Bits */
#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 2cf014f523be..cbc62904655d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -30,16 +30,23 @@
#define __iwl_debug_h__
struct iwl_priv;
+extern u32 iwl_debug_level;
#define IWL_ERR(p, f, a...) dev_err(&((p)->pci_dev->dev), f, ## a)
#define IWL_WARN(p, f, a...) dev_warn(&((p)->pci_dev->dev), f, ## a)
#define IWL_INFO(p, f, a...) dev_info(&((p)->pci_dev->dev), f, ## a)
#define IWL_CRIT(p, f, a...) dev_crit(&((p)->pci_dev->dev), f, ## a)
+#define iwl_print_hex_error(priv, p, len) \
+do { \
+ print_hex_dump(KERN_ERR, "iwl data: ", \
+ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
+} while (0)
+
#ifdef CONFIG_IWLWIFI_DEBUG
#define IWL_DEBUG(__priv, level, fmt, args...) \
do { \
- if (__priv->debug_level & (level)) \
+ if (iwl_get_debug_level(__priv) & (level)) \
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
__func__ , ## args); \
@@ -47,7 +54,7 @@ do { \
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \
do { \
- if ((__priv->debug_level & (level)) && net_ratelimit()) \
+ if ((iwl_get_debug_level(__priv) & (level)) && net_ratelimit()) \
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
__func__ , ## args); \
@@ -55,7 +62,7 @@ do { \
#define iwl_print_hex_dump(priv, level, p, len) \
do { \
- if (priv->debug_level & level) \
+ if (iwl_get_debug_level(priv) & level) \
print_hex_dump(KERN_DEBUG, "iwl data: ", \
DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
} while (0)
@@ -65,23 +72,43 @@ struct iwl_debugfs {
const char *name;
struct dentry *dir_drv;
struct dentry *dir_data;
+ struct dentry *dir_debug;
struct dentry *dir_rf;
struct dir_data_files {
struct dentry *file_sram;
struct dentry *file_nvm;
struct dentry *file_stations;
- struct dentry *file_rx_statistics;
- struct dentry *file_tx_statistics;
struct dentry *file_log_event;
struct dentry *file_channels;
struct dentry *file_status;
struct dentry *file_interrupt;
+ struct dentry *file_qos;
+ struct dentry *file_thermal_throttling;
+#ifdef CONFIG_IWLWIFI_LEDS
+ struct dentry *file_led;
+#endif
+ struct dentry *file_disable_ht40;
+ struct dentry *file_sleep_level_override;
+ struct dentry *file_current_sleep_command;
} dbgfs_data_files;
struct dir_rf_files {
struct dentry *file_disable_sensitivity;
struct dentry *file_disable_chain_noise;
struct dentry *file_disable_tx_power;
} dbgfs_rf_files;
+ struct dir_debug_files {
+ struct dentry *file_rx_statistics;
+ struct dentry *file_tx_statistics;
+ struct dentry *file_traffic_log;
+ struct dentry *file_rx_queue;
+ struct dentry *file_tx_queue;
+ struct dentry *file_ucode_rx_stats;
+ struct dentry *file_ucode_tx_stats;
+ struct dentry *file_ucode_general_stats;
+ struct dentry *file_sensitivity;
+ struct dentry *file_chain_noise;
+ struct dentry *file_tx_power;
+ } dbgfs_debug_files;
u32 sram_offset;
u32 sram_len;
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index ca00cc8ad4c7..fb844859a443 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -38,7 +38,7 @@
#include "iwl-debug.h"
#include "iwl-core.h"
#include "iwl-io.h"
-
+#include "iwl-calib.h"
/* create and remove of files */
#define DEBUGFS_ADD_DIR(name, parent) do { \
@@ -49,7 +49,8 @@
#define DEBUGFS_ADD_FILE(name, parent) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \
+ debugfs_create_file(#name, S_IWUSR | S_IRUSR, \
+ dbgfs->dir_##parent, priv, \
&iwl_dbgfs_##name##_ops); \
if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \
goto err; \
@@ -57,7 +58,8 @@
#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \
+ debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \
+ dbgfs->dir_##parent, ptr); \
if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
|| !dbgfs->dbgfs_##parent##_files.file_##name) \
goto err; \
@@ -65,7 +67,7 @@
#define DEBUGFS_ADD_X32(name, parent, ptr) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_x32(#name, 0444, dbgfs->dir_##parent, ptr); \
+ debugfs_create_x32(#name, S_IRUSR, dbgfs->dir_##parent, ptr); \
if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
|| !dbgfs->dbgfs_##parent##_files.file_##name) \
goto err; \
@@ -124,18 +126,58 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
size_t count, loff_t *ppos) {
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
- char buf[256];
+ char *buf;
int pos = 0;
- const size_t bufsz = sizeof(buf);
- pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n",
- priv->tx_stats[0].cnt);
- pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n",
- priv->tx_stats[1].cnt);
- pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n",
- priv->tx_stats[2].cnt);
+ int cnt;
+ ssize_t ret;
+ const size_t bufsz = 100 + sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX);
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
+ for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t%s\t\t: %u\n",
+ get_mgmt_string(cnt),
+ priv->tx_stats.mgmt[cnt]);
+ }
+ pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
+ for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t%s\t\t: %u\n",
+ get_ctrl_string(cnt),
+ priv->tx_stats.ctrl[cnt]);
+ }
+ pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
+ priv->tx_stats.data_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
+ priv->tx_stats.data_bytes);
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
- return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ u32 clear_flag;
+ char buf[8];
+ int buf_size;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%x", &clear_flag) != 1)
+ return -EFAULT;
+ if (clear_flag == 1)
+ iwl_clear_tx_stats(priv);
+
+ return count;
}
static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
@@ -143,18 +185,59 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
size_t count, loff_t *ppos) {
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
- char buf[256];
+ char *buf;
int pos = 0;
- const size_t bufsz = sizeof(buf);
+ int cnt;
+ ssize_t ret;
+ const size_t bufsz = 100 +
+ sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX);
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n",
- priv->rx_stats[0].cnt);
- pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n",
- priv->rx_stats[1].cnt);
- pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n",
- priv->rx_stats[2].cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
+ for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t%s\t\t: %u\n",
+ get_mgmt_string(cnt),
+ priv->rx_stats.mgmt[cnt]);
+ }
+ pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
+ for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t%s\t\t: %u\n",
+ get_ctrl_string(cnt),
+ priv->rx_stats.ctrl[cnt]);
+ }
+ pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
+ priv->rx_stats.data_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
+ priv->rx_stats.data_bytes);
- return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_rx_statistics_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ u32 clear_flag;
+ char buf[8];
+ int buf_size;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%x", &clear_flag) != 1)
+ return -EFAULT;
+ if (clear_flag == 1)
+ iwl_clear_rx_stats(priv);
+ return count;
}
#define BYTE1_MASK 0x000000ff;
@@ -566,16 +649,982 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
return count;
}
+static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0, i;
+ char buf[256];
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ for (i = 0; i < AC_NUM; i++) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tcw_min\tcw_max\taifsn\ttxop\n");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "AC[%d]\t%u\t%u\t%u\t%u\n", i,
+ priv->qos_data.def_qos_parm.ac[i].cw_min,
+ priv->qos_data.def_qos_parm.ac[i].cw_max,
+ priv->qos_data.def_qos_parm.ac[i].aifsn,
+ priv->qos_data.def_qos_parm.ac[i].edca_txop);
+ }
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
+
+#ifdef CONFIG_IWLWIFI_LEDS
+static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ char buf[256];
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "allow blinking: %s\n",
+ (priv->allow_blinking) ? "True" : "False");
+ if (priv->allow_blinking) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Led blinking rate: %u\n",
+ priv->last_blink_rate);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Last blink time: %lu\n",
+ priv->last_blink_time);
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
+#endif
+
+static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ struct iwl_tt_restriction *restriction;
+ char buf[100];
+ int pos = 0;
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Thermal Throttling Mode: %s\n",
+ tt->advanced_tt ? "Advance" : "Legacy");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Thermal Throttling State: %d\n",
+ tt->state);
+ if (tt->advanced_tt) {
+ restriction = tt->restriction + tt->state;
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Tx mode: %d\n",
+ restriction->tx_stream);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Rx mode: %d\n",
+ restriction->rx_stream);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "HT mode: %d\n",
+ restriction->is_ht);
+ }
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+ int ht40;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%d", &ht40) != 1)
+ return -EFAULT;
+ if (!iwl_is_associated(priv))
+ priv->disable_ht40 = ht40 ? true : false;
+ else {
+ IWL_ERR(priv, "Sta associated with AP - "
+ "Change to 40MHz channel support is not allowed\n");
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ char buf[100];
+ int pos = 0;
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "11n 40MHz Mode: %s\n",
+ priv->disable_ht40 ? "Disabled" : "Enabled");
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+ int value;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ if (sscanf(buf, "%d", &value) != 1)
+ return -EINVAL;
+
+ /*
+ * Our users expect 0 to be "CAM", but 0 isn't actually
+ * valid here. However, let's not confuse them and present
+ * IWL_POWER_INDEX_1 as "1", not "0".
+ */
+ if (value > 0)
+ value -= 1;
+
+ if (value != -1 && (value < 0 || value >= IWL_POWER_NUM))
+ return -EINVAL;
+
+ priv->power_data.debug_sleep_level_override = value;
+
+ iwl_power_update_mode(priv, false);
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ char buf[10];
+ int pos, value;
+ const size_t bufsz = sizeof(buf);
+
+ /* see the write function */
+ value = priv->power_data.debug_sleep_level_override;
+ if (value >= 0)
+ value += 1;
+
+ pos = scnprintf(buf, bufsz, "%d\n", value);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ char buf[200];
+ int pos = 0, i;
+ const size_t bufsz = sizeof(buf);
+ struct iwl_powertable_cmd *cmd = &priv->power_data.sleep_cmd;
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "flags: %#.2x\n", le16_to_cpu(cmd->flags));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "RX/TX timeout: %d/%d usec\n",
+ le32_to_cpu(cmd->rx_data_timeout),
+ le32_to_cpu(cmd->tx_data_timeout));
+ for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sleep_interval[%d]: %d\n", i,
+ le32_to_cpu(cmd->sleep_interval[i]));
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
DEBUGFS_READ_WRITE_FILE_OPS(sram);
DEBUGFS_WRITE_FILE_OPS(log_event);
DEBUGFS_READ_FILE_OPS(nvm);
DEBUGFS_READ_FILE_OPS(stations);
-DEBUGFS_READ_FILE_OPS(rx_statistics);
-DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_FILE_OPS(channels);
DEBUGFS_READ_FILE_OPS(status);
DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
+DEBUGFS_READ_FILE_OPS(qos);
+#ifdef CONFIG_IWLWIFI_LEDS
+DEBUGFS_READ_FILE_OPS(led);
+#endif
+DEBUGFS_READ_FILE_OPS(thermal_throttling);
+DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
+DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
+DEBUGFS_READ_FILE_OPS(current_sleep_command);
+
+static ssize_t iwl_dbgfs_traffic_log_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ int pos = 0, ofs = 0;
+ int cnt = 0, entry;
+ struct iwl_tx_queue *txq;
+ struct iwl_queue *q;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ char *buf;
+ int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
+ (IWL_MAX_NUM_QUEUES * 32 * 8) + 400;
+ const u8 *ptr;
+ ssize_t ret;
+
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf) {
+ IWL_ERR(priv, "Can not allocate buffer\n");
+ return -ENOMEM;
+ }
+ pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n");
+ for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
+ txq = &priv->txq[cnt];
+ q = &txq->q;
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "q[%d]: read_ptr: %u, write_ptr: %u\n",
+ cnt, q->read_ptr, q->write_ptr);
+ }
+ if (priv->tx_traffic && (iwl_debug_level & IWL_DL_TX)) {
+ ptr = priv->tx_traffic;
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Tx Traffic idx: %u\n", priv->tx_traffic_idx);
+ for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
+ for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
+ entry++, ofs += 16) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "0x%.4x ", ofs);
+ hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
+ buf + pos, bufsz - pos, 0);
+ pos += strlen(buf);
+ if (bufsz - pos > 0)
+ buf[pos++] = '\n';
+ }
+ }
+ }
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "read: %u, write: %u\n",
+ rxq->read, rxq->write);
+
+ if (priv->rx_traffic && (iwl_debug_level & IWL_DL_RX)) {
+ ptr = priv->rx_traffic;
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Rx Traffic idx: %u\n", priv->rx_traffic_idx);
+ for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
+ for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
+ entry++, ofs += 16) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "0x%.4x ", ofs);
+ hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
+ buf + pos, bufsz - pos, 0);
+ pos += strlen(buf);
+ if (bufsz - pos > 0)
+ buf[pos++] = '\n';
+ }
+ }
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_traffic_log_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+ int traffic_log;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%d", &traffic_log) != 1)
+ return -EFAULT;
+ if (traffic_log == 0)
+ iwl_reset_traffic_log(priv);
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_tx_queue *txq;
+ struct iwl_queue *q;
+ char *buf;
+ int pos = 0;
+ int cnt;
+ int ret;
+ const size_t bufsz = sizeof(char) * 60 * IWL_MAX_NUM_QUEUES;
+
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
+ txq = &priv->txq[cnt];
+ q = &txq->q;
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "hwq %.2d: read=%u write=%u stop=%d"
+ " swq_id=%#.2x (ac %d/hwq %d)\n",
+ cnt, q->read_ptr, q->write_ptr,
+ !!test_bit(cnt, priv->queue_stopped),
+ txq->swq_id,
+ txq->swq_id & 0x80 ? txq->swq_id & 3 :
+ txq->swq_id,
+ txq->swq_id & 0x80 ? (txq->swq_id >> 2) &
+ 0x1f : txq->swq_id);
+ if (cnt >= 4)
+ continue;
+ /* for the ACs, display the stop count too */
+ pos += scnprintf(buf + pos, bufsz - pos,
+ " stop-count: %d\n",
+ atomic_read(&priv->queue_stop_count[cnt]));
+ }
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ char buf[256];
+ int pos = 0;
+ const size_t bufsz = sizeof(buf);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
+ rxq->read);
+ pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
+ rxq->write);
+ pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
+ rxq->free_count);
+ pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
+ le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+#define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0)
+#define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1)
+#define UCODE_STATISTICS_NARROW_BAND_MSK (0x1 << 2)
+
+static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf,
+ int bufsz)
+{
+ int p = 0;
+
+ p += scnprintf(buf + p, bufsz - p,
+ "Statistics Flag(0x%X):\n",
+ le32_to_cpu(priv->statistics.flag));
+ if (le32_to_cpu(priv->statistics.flag) & UCODE_STATISTICS_CLEAR_MSK)
+ p += scnprintf(buf + p, bufsz - p,
+ "\tStatistics have been cleared\n");
+ p += scnprintf(buf + p, bufsz - p,
+ "\tOperational Frequency: %s\n",
+ (le32_to_cpu(priv->statistics.flag) &
+ UCODE_STATISTICS_FREQUENCY_MSK)
+ ? "2.4 GHz" : "5.2 GHz");
+ p += scnprintf(buf + p, bufsz - p,
+ "\tTGj Narrow Band: %s\n",
+ (le32_to_cpu(priv->statistics.flag) &
+ UCODE_STATISTICS_NARROW_BAND_MSK)
+ ? "enabled" : "disabled");
+ return p;
+}
+
+
+static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ char *buf;
+ int bufsz = sizeof(struct statistics_rx_phy) * 20 +
+ sizeof(struct statistics_rx_non_phy) * 20 +
+ sizeof(struct statistics_rx_ht_phy) * 20 + 400;
+ ssize_t ret;
+ struct statistics_rx_phy *ofdm;
+ struct statistics_rx_phy *cck;
+ struct statistics_rx_non_phy *general;
+ struct statistics_rx_ht_phy *ht;
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ /* make request to uCode to retrieve statistics information */
+ mutex_lock(&priv->mutex);
+ ret = iwl_send_statistics_request(priv, 0);
+ mutex_unlock(&priv->mutex);
+
+ if (ret) {
+ IWL_ERR(priv,
+ "Error sending statistics request: %zd\n", ret);
+ return -EAGAIN;
+ }
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf) {
+ IWL_ERR(priv, "Can not allocate Buffer\n");
+ return -ENOMEM;
+ }
+
+ /* the statistic information display here is based on
+ * the last statistics notification from uCode
+ * might not reflect the current uCode activity
+ */
+ ofdm = &priv->statistics.rx.ofdm;
+ cck = &priv->statistics.rx.cck;
+ general = &priv->statistics.rx.general;
+ ht = &priv->statistics.rx.ofdm_ht;
+ pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n",
+ le32_to_cpu(ofdm->ina_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n",
+ le32_to_cpu(ofdm->fina_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n",
+ le32_to_cpu(ofdm->plcp_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n",
+ le32_to_cpu(ofdm->crc32_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n",
+ le32_to_cpu(ofdm->overrun_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n",
+ le32_to_cpu(ofdm->early_overrun_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n",
+ le32_to_cpu(ofdm->crc32_good));
+ pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n",
+ le32_to_cpu(ofdm->false_alarm_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n",
+ le32_to_cpu(ofdm->fina_sync_err_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n",
+ le32_to_cpu(ofdm->sfd_timeout));
+ pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n",
+ le32_to_cpu(ofdm->fina_timeout));
+ pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n",
+ le32_to_cpu(ofdm->unresponded_rts));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "rxe_frame_limit_overrun: %u\n",
+ le32_to_cpu(ofdm->rxe_frame_limit_overrun));
+ pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n",
+ le32_to_cpu(ofdm->sent_ack_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n",
+ le32_to_cpu(ofdm->sent_cts_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n",
+ le32_to_cpu(ofdm->sent_ba_rsp_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n",
+ le32_to_cpu(ofdm->dsp_self_kill));
+ pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n",
+ le32_to_cpu(ofdm->mh_format_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n",
+ le32_to_cpu(ofdm->re_acq_main_rssi_sum));
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n",
+ le32_to_cpu(cck->ina_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n",
+ le32_to_cpu(cck->fina_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n",
+ le32_to_cpu(cck->plcp_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n",
+ le32_to_cpu(cck->crc32_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n",
+ le32_to_cpu(cck->overrun_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n",
+ le32_to_cpu(cck->early_overrun_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n",
+ le32_to_cpu(cck->crc32_good));
+ pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n",
+ le32_to_cpu(cck->false_alarm_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n",
+ le32_to_cpu(cck->fina_sync_err_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n",
+ le32_to_cpu(cck->sfd_timeout));
+ pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n",
+ le32_to_cpu(cck->fina_timeout));
+ pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n",
+ le32_to_cpu(cck->unresponded_rts));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "rxe_frame_limit_overrun: %u\n",
+ le32_to_cpu(cck->rxe_frame_limit_overrun));
+ pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n",
+ le32_to_cpu(cck->sent_ack_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n",
+ le32_to_cpu(cck->sent_cts_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n",
+ le32_to_cpu(cck->sent_ba_rsp_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n",
+ le32_to_cpu(cck->dsp_self_kill));
+ pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n",
+ le32_to_cpu(cck->mh_format_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n",
+ le32_to_cpu(cck->re_acq_main_rssi_sum));
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts: %u\n",
+ le32_to_cpu(general->bogus_cts));
+ pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack: %u\n",
+ le32_to_cpu(general->bogus_ack));
+ pos += scnprintf(buf + pos, bufsz - pos, "non_bssid_frames: %u\n",
+ le32_to_cpu(general->non_bssid_frames));
+ pos += scnprintf(buf + pos, bufsz - pos, "filtered_frames: %u\n",
+ le32_to_cpu(general->filtered_frames));
+ pos += scnprintf(buf + pos, bufsz - pos, "non_channel_beacons: %u\n",
+ le32_to_cpu(general->non_channel_beacons));
+ pos += scnprintf(buf + pos, bufsz - pos, "channel_beacons: %u\n",
+ le32_to_cpu(general->channel_beacons));
+ pos += scnprintf(buf + pos, bufsz - pos, "num_missed_bcon: %u\n",
+ le32_to_cpu(general->num_missed_bcon));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "adc_rx_saturation_time: %u\n",
+ le32_to_cpu(general->adc_rx_saturation_time));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "ina_detection_search_time: %u\n",
+ le32_to_cpu(general->ina_detection_search_time));
+ pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_a: %u\n",
+ le32_to_cpu(general->beacon_silence_rssi_a));
+ pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_b: %u\n",
+ le32_to_cpu(general->beacon_silence_rssi_b));
+ pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_c: %u\n",
+ le32_to_cpu(general->beacon_silence_rssi_c));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "interference_data_flag: %u\n",
+ le32_to_cpu(general->interference_data_flag));
+ pos += scnprintf(buf + pos, bufsz - pos, "channel_load: %u\n",
+ le32_to_cpu(general->channel_load));
+ pos += scnprintf(buf + pos, bufsz - pos, "dsp_false_alarms: %u\n",
+ le32_to_cpu(general->dsp_false_alarms));
+ pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_a: %u\n",
+ le32_to_cpu(general->beacon_rssi_a));
+ pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_b: %u\n",
+ le32_to_cpu(general->beacon_rssi_b));
+ pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_c: %u\n",
+ le32_to_cpu(general->beacon_rssi_c));
+ pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_a: %u\n",
+ le32_to_cpu(general->beacon_energy_a));
+ pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_b: %u\n",
+ le32_to_cpu(general->beacon_energy_b));
+ pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_c: %u\n",
+ le32_to_cpu(general->beacon_energy_c));
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n",
+ le32_to_cpu(ht->plcp_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n",
+ le32_to_cpu(ht->overrun_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n",
+ le32_to_cpu(ht->early_overrun_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n",
+ le32_to_cpu(ht->crc32_good));
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n",
+ le32_to_cpu(ht->crc32_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n",
+ le32_to_cpu(ht->mh_format_err));
+ pos += scnprintf(buf + pos, bufsz - pos, "agg_crc32_good: %u\n",
+ le32_to_cpu(ht->agg_crc32_good));
+ pos += scnprintf(buf + pos, bufsz - pos, "agg_mpdu_cnt: %u\n",
+ le32_to_cpu(ht->agg_mpdu_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt: %u\n",
+ le32_to_cpu(ht->agg_cnt));
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ char *buf;
+ int bufsz = (sizeof(struct statistics_tx) * 24) + 250;
+ ssize_t ret;
+ struct statistics_tx *tx;
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ /* make request to uCode to retrieve statistics information */
+ mutex_lock(&priv->mutex);
+ ret = iwl_send_statistics_request(priv, 0);
+ mutex_unlock(&priv->mutex);
+
+ if (ret) {
+ IWL_ERR(priv,
+ "Error sending statistics request: %zd\n", ret);
+ return -EAGAIN;
+ }
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf) {
+ IWL_ERR(priv, "Can not allocate Buffer\n");
+ return -ENOMEM;
+ }
+
+ /* the statistic information display here is based on
+ * the last statistics notification from uCode
+ * might not reflect the current uCode activity
+ */
+ tx = &priv->statistics.tx;
+ pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "preamble: %u\n",
+ le32_to_cpu(tx->preamble_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "rx_detected_cnt: %u\n",
+ le32_to_cpu(tx->rx_detected_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_defer_cnt: %u\n",
+ le32_to_cpu(tx->bt_prio_defer_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_kill_cnt: %u\n",
+ le32_to_cpu(tx->bt_prio_kill_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "few_bytes_cnt: %u\n",
+ le32_to_cpu(tx->few_bytes_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout: %u\n",
+ le32_to_cpu(tx->cts_timeout));
+ pos += scnprintf(buf + pos, bufsz - pos, "ack_timeout: %u\n",
+ le32_to_cpu(tx->ack_timeout));
+ pos += scnprintf(buf + pos, bufsz - pos, "expected_ack_cnt: %u\n",
+ le32_to_cpu(tx->expected_ack_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "actual_ack_cnt: %u\n",
+ le32_to_cpu(tx->actual_ack_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "dump_msdu_cnt: %u\n",
+ le32_to_cpu(tx->dump_msdu_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "burst_abort_next_frame_mismatch_cnt: %u\n",
+ le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "burst_abort_missing_next_frame_cnt: %u\n",
+ le32_to_cpu(tx->burst_abort_missing_next_frame_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout_collision: %u\n",
+ le32_to_cpu(tx->cts_timeout_collision));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "ack_or_ba_timeout_collision: %u\n",
+ le32_to_cpu(tx->ack_or_ba_timeout_collision));
+ pos += scnprintf(buf + pos, bufsz - pos, "agg ba_timeout: %u\n",
+ le32_to_cpu(tx->agg.ba_timeout));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg ba_reschedule_frames: %u\n",
+ le32_to_cpu(tx->agg.ba_reschedule_frames));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg scd_query_agg_frame_cnt: %u\n",
+ le32_to_cpu(tx->agg.scd_query_agg_frame_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_no_agg: %u\n",
+ le32_to_cpu(tx->agg.scd_query_no_agg));
+ pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_agg: %u\n",
+ le32_to_cpu(tx->agg.scd_query_agg));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg scd_query_mismatch: %u\n",
+ le32_to_cpu(tx->agg.scd_query_mismatch));
+ pos += scnprintf(buf + pos, bufsz - pos, "agg frame_not_ready: %u\n",
+ le32_to_cpu(tx->agg.frame_not_ready));
+ pos += scnprintf(buf + pos, bufsz - pos, "agg underrun: %u\n",
+ le32_to_cpu(tx->agg.underrun));
+ pos += scnprintf(buf + pos, bufsz - pos, "agg bt_prio_kill: %u\n",
+ le32_to_cpu(tx->agg.bt_prio_kill));
+ pos += scnprintf(buf + pos, bufsz - pos, "agg rx_ba_rsp_cnt: %u\n",
+ le32_to_cpu(tx->agg.rx_ba_rsp_cnt));
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ char *buf;
+ int bufsz = sizeof(struct statistics_general) * 4 + 250;
+ ssize_t ret;
+ struct statistics_general *general;
+ struct statistics_dbg *dbg;
+ struct statistics_div *div;
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ /* make request to uCode to retrieve statistics information */
+ mutex_lock(&priv->mutex);
+ ret = iwl_send_statistics_request(priv, 0);
+ mutex_unlock(&priv->mutex);
+
+ if (ret) {
+ IWL_ERR(priv,
+ "Error sending statistics request: %zd\n", ret);
+ return -EAGAIN;
+ }
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf) {
+ IWL_ERR(priv, "Can not allocate Buffer\n");
+ return -ENOMEM;
+ }
+
+ /* the statistic information display here is based on
+ * the last statistics notification from uCode
+ * might not reflect the current uCode activity
+ */
+ general = &priv->statistics.general;
+ dbg = &priv->statistics.general.dbg;
+ div = &priv->statistics.general.div;
+ pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "temperature: %u\n",
+ le32_to_cpu(general->temperature));
+ pos += scnprintf(buf + pos, bufsz - pos, "temperature_m: %u\n",
+ le32_to_cpu(general->temperature_m));
+ pos += scnprintf(buf + pos, bufsz - pos, "burst_check: %u\n",
+ le32_to_cpu(dbg->burst_check));
+ pos += scnprintf(buf + pos, bufsz - pos, "burst_count: %u\n",
+ le32_to_cpu(dbg->burst_count));
+ pos += scnprintf(buf + pos, bufsz - pos, "sleep_time: %u\n",
+ le32_to_cpu(general->sleep_time));
+ pos += scnprintf(buf + pos, bufsz - pos, "slots_out: %u\n",
+ le32_to_cpu(general->slots_out));
+ pos += scnprintf(buf + pos, bufsz - pos, "slots_idle: %u\n",
+ le32_to_cpu(general->slots_idle));
+ pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp: %u\n",
+ le32_to_cpu(general->ttl_timestamp));
+ pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a: %u\n",
+ le32_to_cpu(div->tx_on_a));
+ pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b: %u\n",
+ le32_to_cpu(div->tx_on_b));
+ pos += scnprintf(buf + pos, bufsz - pos, "exec_time: %u\n",
+ le32_to_cpu(div->exec_time));
+ pos += scnprintf(buf + pos, bufsz - pos, "probe_time: %u\n",
+ le32_to_cpu(div->probe_time));
+ pos += scnprintf(buf + pos, bufsz - pos, "rx_enable_counter: %u\n",
+ le32_to_cpu(general->rx_enable_counter));
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ int cnt = 0;
+ char *buf;
+ int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100;
+ ssize_t ret;
+ struct iwl_sensitivity_data *data;
+
+ data = &priv->sensitivity_data;
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf) {
+ IWL_ERR(priv, "Can not allocate Buffer\n");
+ return -ENOMEM;
+ }
+
+ pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
+ data->auto_corr_ofdm);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "auto_corr_ofdm_mrc:\t\t %u\n",
+ data->auto_corr_ofdm_mrc);
+ pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
+ data->auto_corr_ofdm_x1);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "auto_corr_ofdm_mrc_x1:\t\t %u\n",
+ data->auto_corr_ofdm_mrc_x1);
+ pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
+ data->auto_corr_cck);
+ pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
+ data->auto_corr_cck_mrc);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "last_bad_plcp_cnt_ofdm:\t\t %u\n",
+ data->last_bad_plcp_cnt_ofdm);
+ pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
+ data->last_fa_cnt_ofdm);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "last_bad_plcp_cnt_cck:\t\t %u\n",
+ data->last_bad_plcp_cnt_cck);
+ pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
+ data->last_fa_cnt_cck);
+ pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
+ data->nrg_curr_state);
+ pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
+ data->nrg_prev_state);
+ pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
+ for (cnt = 0; cnt < 10; cnt++) {
+ pos += scnprintf(buf + pos, bufsz - pos, " %u",
+ data->nrg_value[cnt]);
+ }
+ pos += scnprintf(buf + pos, bufsz - pos, "\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
+ for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
+ pos += scnprintf(buf + pos, bufsz - pos, " %u",
+ data->nrg_silence_rssi[cnt]);
+ }
+ pos += scnprintf(buf + pos, bufsz - pos, "\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
+ data->nrg_silence_ref);
+ pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
+ data->nrg_energy_idx);
+ pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
+ data->nrg_silence_idx);
+ pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
+ data->nrg_th_cck);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "nrg_auto_corr_silence_diff:\t %u\n",
+ data->nrg_auto_corr_silence_diff);
+ pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
+ data->num_in_cck_no_fa);
+ pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
+ data->nrg_th_ofdm);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+
+static ssize_t iwl_dbgfs_chain_noise_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ int cnt = 0;
+ char *buf;
+ int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100;
+ ssize_t ret;
+ struct iwl_chain_noise_data *data;
+
+ data = &priv->chain_noise_data;
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf) {
+ IWL_ERR(priv, "Can not allocate Buffer\n");
+ return -ENOMEM;
+ }
+
+ pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
+ data->active_chains);
+ pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
+ data->chain_noise_a);
+ pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
+ data->chain_noise_b);
+ pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
+ data->chain_noise_c);
+ pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
+ data->chain_signal_a);
+ pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
+ data->chain_signal_b);
+ pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
+ data->chain_signal_c);
+ pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
+ data->beacon_count);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
+ for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
+ pos += scnprintf(buf + pos, bufsz - pos, " %u",
+ data->disconn_array[cnt]);
+ }
+ pos += scnprintf(buf + pos, bufsz - pos, "\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
+ for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
+ pos += scnprintf(buf + pos, bufsz - pos, " %u",
+ data->delta_gain_code[cnt]);
+ }
+ pos += scnprintf(buf + pos, bufsz - pos, "\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
+ data->radio_write);
+ pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
+ data->state);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ char buf[128];
+ int pos = 0;
+ ssize_t ret;
+ const size_t bufsz = sizeof(buf);
+ struct statistics_tx *tx;
+
+ if (!iwl_is_alive(priv))
+ pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
+ else {
+ /* make request to uCode to retrieve statistics information */
+ mutex_lock(&priv->mutex);
+ ret = iwl_send_statistics_request(priv, 0);
+ mutex_unlock(&priv->mutex);
+
+ if (ret) {
+ IWL_ERR(priv, "Error sending statistics request: %zd\n",
+ ret);
+ return -EAGAIN;
+ }
+ tx = &priv->statistics.tx;
+ if (tx->tx_power.ant_a ||
+ tx->tx_power.ant_b ||
+ tx->tx_power.ant_c) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "tx power: (1/2 dB step)\n");
+ if ((priv->cfg->valid_tx_ant & ANT_A) &&
+ tx->tx_power.ant_a)
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tantenna A: 0x%X\n",
+ tx->tx_power.ant_a);
+ if ((priv->cfg->valid_tx_ant & ANT_B) &&
+ tx->tx_power.ant_b)
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tantenna B: 0x%X\n",
+ tx->tx_power.ant_b);
+ if ((priv->cfg->valid_tx_ant & ANT_C) &&
+ tx->tx_power.ant_c)
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tantenna C: 0x%X\n",
+ tx->tx_power.ant_c);
+ } else
+ pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
+ }
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics);
+DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics);
+DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
+DEBUGFS_READ_FILE_OPS(rx_queue);
+DEBUGFS_READ_FILE_OPS(tx_queue);
+DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
+DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
+DEBUGFS_READ_FILE_OPS(ucode_general_stats);
+DEBUGFS_READ_FILE_OPS(sensitivity);
+DEBUGFS_READ_FILE_OPS(chain_noise);
+DEBUGFS_READ_FILE_OPS(tx_power);
/*
* Create the debugfs files and directories
@@ -603,19 +1652,42 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_DIR(data, dbgfs->dir_drv);
DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv);
+ DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv);
DEBUGFS_ADD_FILE(nvm, data);
DEBUGFS_ADD_FILE(sram, data);
DEBUGFS_ADD_FILE(log_event, data);
DEBUGFS_ADD_FILE(stations, data);
- DEBUGFS_ADD_FILE(rx_statistics, data);
- DEBUGFS_ADD_FILE(tx_statistics, data);
DEBUGFS_ADD_FILE(channels, data);
DEBUGFS_ADD_FILE(status, data);
DEBUGFS_ADD_FILE(interrupt, data);
+ DEBUGFS_ADD_FILE(qos, data);
+#ifdef CONFIG_IWLWIFI_LEDS
+ DEBUGFS_ADD_FILE(led, data);
+#endif
+ DEBUGFS_ADD_FILE(sleep_level_override, data);
+ DEBUGFS_ADD_FILE(current_sleep_command, data);
+ DEBUGFS_ADD_FILE(thermal_throttling, data);
+ DEBUGFS_ADD_FILE(disable_ht40, data);
+ DEBUGFS_ADD_FILE(rx_statistics, debug);
+ DEBUGFS_ADD_FILE(tx_statistics, debug);
+ DEBUGFS_ADD_FILE(traffic_log, debug);
+ DEBUGFS_ADD_FILE(rx_queue, debug);
+ DEBUGFS_ADD_FILE(tx_queue, debug);
+ DEBUGFS_ADD_FILE(tx_power, debug);
+ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
+ DEBUGFS_ADD_FILE(ucode_rx_stats, debug);
+ DEBUGFS_ADD_FILE(ucode_tx_stats, debug);
+ DEBUGFS_ADD_FILE(ucode_general_stats, debug);
+ DEBUGFS_ADD_FILE(sensitivity, debug);
+ DEBUGFS_ADD_FILE(chain_noise, debug);
+ }
DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
&priv->disable_chain_noise_cal);
- DEBUGFS_ADD_BOOL(disable_tx_power, rf, &priv->disable_tx_power_cal);
+ if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
+ ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
+ DEBUGFS_ADD_BOOL(disable_tx_power, rf,
+ &priv->disable_tx_power_cal);
return 0;
err:
@@ -634,19 +1706,46 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
if (!priv->dbgfs)
return;
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sleep_level_override);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_current_sleep_command);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos);
+#ifdef CONFIG_IWLWIFI_LEDS
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
+#endif
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40);
DEBUGFS_REMOVE(priv->dbgfs->dir_data);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_statistics);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_statistics);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power);
+ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
+ file_ucode_rx_stats);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
+ file_ucode_tx_stats);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
+ file_ucode_general_stats);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
+ file_sensitivity);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
+ file_chain_noise);
+ }
+ DEBUGFS_REMOVE(priv->dbgfs->dir_debug);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power);
+ if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
+ ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power);
DEBUGFS_REMOVE(priv->dbgfs->dir_rf);
DEBUGFS_REMOVE(priv->dbgfs->dir_drv);
kfree(priv->dbgfs);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 650e20af20fa..028d50599550 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -56,16 +56,19 @@ extern struct iwl_cfg iwl5350_agn_cfg;
extern struct iwl_cfg iwl5100_bg_cfg;
extern struct iwl_cfg iwl5100_abg_cfg;
extern struct iwl_cfg iwl5150_agn_cfg;
-extern struct iwl_cfg iwl6000_2ag_cfg;
-extern struct iwl_cfg iwl6000_2agn_cfg;
+extern struct iwl_cfg iwl6000h_2agn_cfg;
+extern struct iwl_cfg iwl6000i_2agn_cfg;
extern struct iwl_cfg iwl6000_3agn_cfg;
extern struct iwl_cfg iwl6050_2agn_cfg;
extern struct iwl_cfg iwl6050_3agn_cfg;
extern struct iwl_cfg iwl1000_bgn_cfg;
+struct iwl_tx_queue;
+
/* shared structures from iwl-5000.c */
extern struct iwl_mod_params iwl50_mod_params;
extern struct iwl_ops iwl5000_ops;
+extern struct iwl_ucode_ops iwl5000_ucode;
extern struct iwl_lib_ops iwl5000_lib;
extern struct iwl_hcmd_ops iwl5000_hcmd;
extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
@@ -78,9 +81,37 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
__le32 *tx_flags);
extern int iwl5000_calc_rssi(struct iwl_priv *priv,
struct iwl_rx_phy_res *rx_resp);
+extern int iwl5000_apm_init(struct iwl_priv *priv);
+extern void iwl5000_apm_stop(struct iwl_priv *priv);
+extern int iwl5000_apm_reset(struct iwl_priv *priv);
+extern void iwl5000_nic_config(struct iwl_priv *priv);
+extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv);
+extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
+ size_t offset);
+extern void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq,
+ u16 byte_cnt);
+extern void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq);
+extern int iwl5000_load_ucode(struct iwl_priv *priv);
+extern void iwl5000_init_alive_start(struct iwl_priv *priv);
+extern int iwl5000_alive_notify(struct iwl_priv *priv);
+extern int iwl5000_hw_set_hw_params(struct iwl_priv *priv);
+extern int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
+ int tx_fifo, int sta_id, int tid, u16 ssn_idx);
+extern int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+ u16 ssn_idx, u8 tx_fifo);
+extern void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask);
+extern void iwl5000_setup_deferred_work(struct iwl_priv *priv);
+extern void iwl5000_rx_handler_setup(struct iwl_priv *priv);
+extern int iwl5000_hw_valid_rtc_data_addr(u32 addr);
+extern int iwl5000_send_tx_power(struct iwl_priv *priv);
+extern void iwl5000_temperature(struct iwl_priv *priv);
/* CT-KILL constants */
-#define CT_KILL_THRESHOLD 110 /* in Celsius */
+#define CT_KILL_THRESHOLD_LEGACY 110 /* in Celsius */
+#define CT_KILL_THRESHOLD 114 /* in Celsius */
+#define CT_KILL_EXIT_THRESHOLD 95 /* in Celsius */
/* Default noise level to report when noise measurement is not available.
* This may be because we're:
@@ -119,6 +150,31 @@ struct iwl_rx_mem_buffer {
struct list_head list;
};
+/* defined below */
+struct iwl_device_cmd;
+
+struct iwl_cmd_meta {
+ /* only for SYNC commands, iff the reply skb is wanted */
+ struct iwl_host_cmd *source;
+ /*
+ * only for ASYNC commands
+ * (which is somewhat stupid -- look at iwl-sta.c for instance
+ * which duplicates a bunch of code because the callback isn't
+ * invoked for SYNC commands, if it were and its result passed
+ * through it would be simpler...)
+ */
+ void (*callback)(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb);
+
+ /* The CMD_SIZE_HUGE flag bit indicates that the command
+ * structure is stored at the end of the shared queue memory. */
+ u32 flags;
+
+ DECLARE_PCI_UNMAP_ADDR(mapping)
+ DECLARE_PCI_UNMAP_LEN(len)
+};
+
/*
* Generic queue structure
*
@@ -146,7 +202,8 @@ struct iwl_tx_info {
* struct iwl_tx_queue - Tx Queue for DMA
* @q: generic Rx/Tx queue descriptor
* @bd: base of circular buffer of TFDs
- * @cmd: array of command/Tx buffers
+ * @cmd: array of command/TX buffer pointers
+ * @meta: array of meta data for each command/tx buffer
* @dma_addr_cmd: physical address of cmd/tx buffer array
* @txb: array of per-TFD driver data
* @need_update: indicates need to update read/write index
@@ -161,7 +218,8 @@ struct iwl_tx_info {
struct iwl_tx_queue {
struct iwl_queue q;
void *tfds;
- struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS];
+ struct iwl_device_cmd **cmd;
+ struct iwl_cmd_meta *meta;
struct iwl_tx_info *txb;
u8 need_update;
u8 sched_retry;
@@ -219,8 +277,8 @@ struct iwl_channel_info {
struct iwl4965_channel_tgd_info tgd;
struct iwl4965_channel_tgh_info tgh;
struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */
- struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for
- * FAT channel */
+ struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for
+ * HT40 channel */
u8 channel; /* channel number */
u8 flags; /* flags copied from EEPROM */
@@ -233,13 +291,13 @@ struct iwl_channel_info {
u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */
enum ieee80211_band band;
- /* FAT channel info */
- s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
- s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */
- s8 fat_min_power; /* always 0 */
- s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */
- u8 fat_flags; /* flags copied from EEPROM */
- u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */
+ /* HT40 channel info */
+ s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
+ s8 ht40_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */
+ s8 ht40_min_power; /* always 0 */
+ s8 ht40_scan_power; /* (dBm) eeprom, direct scans, any rate */
+ u8 ht40_flags; /* flags copied from EEPROM */
+ u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */
/* Radio/DSP gain settings for each "normal" data Tx rate.
* These include, in addition to RF and DSP gain, a few fields for
@@ -298,35 +356,16 @@ enum {
CMD_WANT_SKB = (1 << 2),
};
-struct iwl_cmd;
-struct iwl_priv;
-
-struct iwl_cmd_meta {
- struct iwl_cmd_meta *source;
- union {
- struct sk_buff *skb;
- int (*callback)(struct iwl_priv *priv,
- struct iwl_cmd *cmd, struct sk_buff *skb);
- } __attribute__ ((packed)) u;
-
- /* The CMD_SIZE_HUGE flag bit indicates that the command
- * structure is stored at the end of the shared queue memory. */
- u32 flags;
- DECLARE_PCI_UNMAP_ADDR(mapping)
- DECLARE_PCI_UNMAP_LEN(len)
-} __attribute__ ((packed));
-
#define IWL_CMD_MAX_PAYLOAD 320
/**
- * struct iwl_cmd
+ * struct iwl_device_cmd
*
* For allocation of the command and tx queues, this establishes the overall
* size of the largest command we send to uCode, except for a scan command
* (which is relatively huge; space is allocated separately).
*/
-struct iwl_cmd {
- struct iwl_cmd_meta meta; /* driver data */
+struct iwl_device_cmd {
struct iwl_cmd_header hdr; /* uCode API */
union {
u32 flags;
@@ -338,17 +377,20 @@ struct iwl_cmd {
} __attribute__ ((packed)) cmd;
} __attribute__ ((packed));
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
+
struct iwl_host_cmd {
- u8 id;
- u16 len;
- struct iwl_cmd_meta meta;
const void *data;
+ struct sk_buff *reply_skb;
+ void (*callback)(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb);
+ u32 flags;
+ u16 len;
+ u8 id;
};
-#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
- sizeof(struct iwl_cmd_meta))
-
/*
* RX related structures and functions
*/
@@ -449,23 +491,25 @@ union iwl_ht_rate_supp {
};
#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3)
-#define CFG_HT_MPDU_DENSITY_2USEC (0x5)
-#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
+
+/*
+ * Maximal MPDU density for TX aggregation
+ * 4 - 2us density
+ * 5 - 4us density
+ * 6 - 8us density
+ * 7 - 16us density
+ */
+#define CFG_HT_MPDU_DENSITY_4USEC (0x5)
+#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC
struct iwl_ht_info {
/* self configuration data */
u8 is_ht;
u8 supported_chan_width;
u8 sm_ps;
- u8 is_green_field;
- u8 sgf; /* HT_SHORT_GI_* short guard interval */
- u8 max_amsdu_size;
- u8 ampdu_factor;
- u8 mpdu_density;
struct ieee80211_mcs_info mcs;
/* BSS related data */
u8 extension_chan_offset;
- u8 tx_chan_width;
u8 ht_protection;
u8 non_GF_STA_present;
};
@@ -525,15 +569,29 @@ struct fw_desc {
};
/* uCode file layout */
-struct iwl_ucode {
- __le32 ver; /* major/minor/API/serial */
- __le32 inst_size; /* bytes of runtime instructions */
- __le32 data_size; /* bytes of runtime data */
- __le32 init_size; /* bytes of initialization instructions */
- __le32 init_data_size; /* bytes of initialization data */
- __le32 boot_size; /* bytes of bootstrap instructions */
- u8 data[0]; /* data in same order as "size" elements */
+struct iwl_ucode_header {
+ __le32 ver; /* major/minor/API/serial */
+ union {
+ struct {
+ __le32 inst_size; /* bytes of runtime code */
+ __le32 data_size; /* bytes of runtime data */
+ __le32 init_size; /* bytes of init code */
+ __le32 init_data_size; /* bytes of init data */
+ __le32 boot_size; /* bytes of bootstrap code */
+ u8 data[0]; /* in same order as sizes */
+ } v1;
+ struct {
+ __le32 build; /* build number */
+ __le32 inst_size; /* bytes of runtime code */
+ __le32 data_size; /* bytes of runtime data */
+ __le32 init_size; /* bytes of init code */
+ __le32 init_data_size; /* bytes of init data */
+ __le32 boot_size; /* bytes of bootstrap code */
+ u8 data[0]; /* in same order as sizes */
+ } v2;
+ } u;
};
+#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28)
struct iwl4965_ibss_seq {
u8 mac[ETH_ALEN];
@@ -585,7 +643,7 @@ struct iwl_sensitivity_ranges {
* @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR
* @max_stations:
* @bcast_sta_id:
- * @fat_channel: is 40MHz width possible in band 2.4
+ * @ht40_channel: is 40MHz width possible in band 2.4
* BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ)
* @sw_crypto: 0 for hw, 1 for sw
* @max_xxx_size: for ucode uses
@@ -609,12 +667,14 @@ struct iwl_hw_params {
u32 max_pkt_size;
u8 max_stations;
u8 bcast_sta_id;
- u8 fat_channel;
- u8 sw_crypto;
+ u8 ht40_channel;
+ u8 max_beacon_itrvl; /* in 1024 ms */
u32 max_inst_size;
u32 max_data_size;
u32 max_bsm_size;
u32 ct_kill_threshold; /* value in hw-dependent units */
+ u32 ct_kill_exit_threshold; /* value in hw-dependent units */
+ /* for 1000, 6000 series and up */
u32 calib_init_cfg;
const struct iwl_sensitivity_ranges *sens;
};
@@ -666,9 +726,6 @@ struct iwl_dma_ptr {
size_t size;
};
-#define HT_SHORT_GI_20MHZ (1 << 0)
-#define HT_SHORT_GI_40MHZ (1 << 1)
-
#define IWL_CHANNEL_WIDTH_20MHZ 0
#define IWL_CHANNEL_WIDTH_40MHZ 1
@@ -809,6 +866,8 @@ struct iwl_chain_noise_data {
#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */
#define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */
+#define IWL_TRAFFIC_ENTRIES (256)
+#define IWL_TRAFFIC_ENTRY_SIZE (64)
enum {
MEASUREMENT_READY = (1 << 0),
@@ -820,6 +879,30 @@ enum iwl_nvm_type {
NVM_DEVICE_TYPE_OTP,
};
+/*
+ * Two types of OTP memory access modes
+ * IWL_OTP_ACCESS_ABSOLUTE - absolute address mode,
+ * based on physical memory addressing
+ * IWL_OTP_ACCESS_RELATIVE - relative address mode,
+ * based on logical memory addressing
+ */
+enum iwl_access_mode {
+ IWL_OTP_ACCESS_ABSOLUTE,
+ IWL_OTP_ACCESS_RELATIVE,
+};
+
+/**
+ * enum iwl_pa_type - Power Amplifier type
+ * @IWL_PA_SYSTEM: based on uCode configuration
+ * @IWL_PA_HYBRID: use both Internal and external PA
+ * @IWL_PA_INTERNAL: use Internal only
+ */
+enum iwl_pa_type {
+ IWL_PA_SYSTEM = 0,
+ IWL_PA_HYBRID = 1,
+ IWL_PA_INTERNAL = 2,
+};
+
/* interrupt statistics */
struct isr_statistics {
u32 hw;
@@ -836,6 +919,48 @@ struct isr_statistics {
u32 unhandled;
};
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+/* management statistics */
+enum iwl_mgmt_stats {
+ MANAGEMENT_ASSOC_REQ = 0,
+ MANAGEMENT_ASSOC_RESP,
+ MANAGEMENT_REASSOC_REQ,
+ MANAGEMENT_REASSOC_RESP,
+ MANAGEMENT_PROBE_REQ,
+ MANAGEMENT_PROBE_RESP,
+ MANAGEMENT_BEACON,
+ MANAGEMENT_ATIM,
+ MANAGEMENT_DISASSOC,
+ MANAGEMENT_AUTH,
+ MANAGEMENT_DEAUTH,
+ MANAGEMENT_ACTION,
+ MANAGEMENT_MAX,
+};
+/* control statistics */
+enum iwl_ctrl_stats {
+ CONTROL_BACK_REQ = 0,
+ CONTROL_BACK,
+ CONTROL_PSPOLL,
+ CONTROL_RTS,
+ CONTROL_CTS,
+ CONTROL_ACK,
+ CONTROL_CFEND,
+ CONTROL_CFENDACK,
+ CONTROL_MAX,
+};
+
+struct traffic_stats {
+ u32 mgmt[MANAGEMENT_MAX];
+ u32 ctrl[CONTROL_MAX];
+ u32 data_cnt;
+ u64 data_bytes;
+};
+#else
+struct traffic_stats {
+ u64 data_bytes;
+};
+#endif
+
#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */
struct iwl_priv {
@@ -981,15 +1106,14 @@ struct iwl_priv {
int last_rx_noise; /* From beacon statistics */
/* counts mgmt, ctl, and data packets */
- struct traffic_stats {
- u32 cnt;
- u64 bytes;
- } tx_stats[3], rx_stats[3];
+ struct traffic_stats tx_stats;
+ struct traffic_stats rx_stats;
/* counts interrupts */
struct isr_statistics isr_stats;
struct iwl_power_mgr power_data;
+ struct iwl_tt_mgmt thermal_throttle;
struct iwl_notif_statistics statistics;
unsigned long last_statistics_time;
@@ -997,7 +1121,6 @@ struct iwl_priv {
/* context information */
u16 rates_mask;
- u32 power_mode;
u8 bssid[ETH_ALEN];
u16 rts_threshold;
u8 mac_addr[ETH_ALEN];
@@ -1047,7 +1170,7 @@ struct iwl_priv {
struct iwl_hw_params hw_params;
/* INT ICT Table */
- u32 *ict_tbl;
+ __le32 *ict_tbl;
dma_addr_t ict_tbl_dma;
dma_addr_t aligned_ict_tbl_dma;
int ict_index;
@@ -1076,6 +1199,9 @@ struct iwl_priv {
struct work_struct report_work;
struct work_struct request_scan;
struct work_struct beacon_update;
+ struct work_struct tt_work;
+ struct work_struct ct_enter;
+ struct work_struct ct_exit;
struct tasklet_struct irq_tasklet;
@@ -1089,16 +1215,22 @@ struct iwl_priv {
/* TX Power */
s8 tx_power_user_lmt;
- s8 tx_power_channel_lmt;
+ s8 tx_power_device_lmt;
#ifdef CONFIG_IWLWIFI_DEBUG
/* debugging info */
- u32 debug_level;
+ u32 debug_level; /* per device debugging will override global
+ iwl_debug_level if set */
u32 framecnt_to_us;
atomic_t restrict_refcnt;
+ bool disable_ht40;
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* debugfs */
+ u16 tx_traffic_idx;
+ u16 rx_traffic_idx;
+ u8 *tx_traffic;
+ u8 *rx_traffic;
struct iwl_debugfs *dbgfs;
#endif /* CONFIG_IWLWIFI_DEBUGFS */
#endif /* CONFIG_IWLWIFI_DEBUG */
@@ -1130,8 +1262,27 @@ static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
#ifdef CONFIG_IWLWIFI_DEBUG
const char *iwl_get_tx_fail_reason(u32 status);
+/*
+ * iwl_get_debug_level: Return active debug level for device
+ *
+ * Using sysfs it is possible to set per device debug level. This debug
+ * level will be used if set, otherwise the global debug level which can be
+ * set via module parameter is used.
+ */
+static inline u32 iwl_get_debug_level(struct iwl_priv *priv)
+{
+ if (priv->debug_level)
+ return priv->debug_level;
+ else
+ return iwl_debug_level;
+}
#else
static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; }
+
+static inline u32 iwl_get_debug_level(struct iwl_priv *priv)
+{
+ return iwl_debug_level;
+}
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 7d7554a2f341..3d2b93a61e62 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -127,14 +127,86 @@ static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */
145, 149, 153, 157, 161, 165
};
-static const u8 iwl_eeprom_band_6[] = { /* 2.4 FAT channel */
+static const u8 iwl_eeprom_band_6[] = { /* 2.4 ht40 channel */
1, 2, 3, 4, 5, 6, 7
};
-static const u8 iwl_eeprom_band_7[] = { /* 5.2 FAT channel */
+static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */
36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
};
+/**
+ * struct iwl_txpwr_section: eeprom section information
+ * @offset: indirect address into eeprom image
+ * @count: number of "struct iwl_eeprom_enhanced_txpwr" in this section
+ * @band: band type for the section
+ * @is_common - true: common section, false: channel section
+ * @is_cck - true: cck section, false: not cck section
+ * @is_ht_40 - true: all channel in the section are HT40 channel,
+ * false: legacy or HT 20 MHz
+ * ignore if it is common section
+ * @iwl_eeprom_section_channel: channel array in the section,
+ * ignore if common section
+ */
+struct iwl_txpwr_section {
+ u32 offset;
+ u8 count;
+ enum ieee80211_band band;
+ bool is_common;
+ bool is_cck;
+ bool is_ht40;
+ u8 iwl_eeprom_section_channel[EEPROM_MAX_TXPOWER_SECTION_ELEMENTS];
+};
+
+/**
+ * section 1 - 3 are regulatory tx power apply to all channels based on
+ * modulation: CCK, OFDM
+ * Band: 2.4GHz, 5.2GHz
+ * section 4 - 10 are regulatory tx power apply to specified channels
+ * For example:
+ * 1L - Channel 1 Legacy
+ * 1HT - Channel 1 HT
+ * (1,+1) - Channel 1 HT40 "_above_"
+ *
+ * Section 1: all CCK channels
+ * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40) channels
+ * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels
+ * Section 4: 2.4 GHz 20MHz channels: 1L, 1HT, 2L, 2HT, 10L, 10HT, 11L, 11HT
+ * Section 5: 2.4 GHz 40MHz channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1)
+ * Section 6: 5.2 GHz 20MHz channels: 36L, 64L, 100L, 36HT, 64HT, 100HT
+ * Section 7: 5.2 GHz 40MHz channels: (36,+1) (60,+1) (100,+1)
+ * Section 8: 2.4 GHz channel: 13L, 13HT
+ * Section 9: 2.4 GHz channel: 140L, 140HT
+ * Section 10: 2.4 GHz 40MHz channels: (132,+1) (44,+1)
+ *
+ */
+static const struct iwl_txpwr_section enhinfo[] = {
+ { EEPROM_LB_CCK_20_COMMON, 1, IEEE80211_BAND_2GHZ, true, true, false },
+ { EEPROM_LB_OFDM_COMMON, 3, IEEE80211_BAND_2GHZ, true, false, false },
+ { EEPROM_HB_OFDM_COMMON, 3, IEEE80211_BAND_5GHZ, true, false, false },
+ { EEPROM_LB_OFDM_20_BAND, 8, IEEE80211_BAND_2GHZ,
+ false, false, false,
+ {1, 1, 2, 2, 10, 10, 11, 11 } },
+ { EEPROM_LB_OFDM_HT40_BAND, 5, IEEE80211_BAND_2GHZ,
+ false, false, true,
+ { 1, 2, 6, 7, 9 } },
+ { EEPROM_HB_OFDM_20_BAND, 6, IEEE80211_BAND_5GHZ,
+ false, false, false,
+ { 36, 64, 100, 36, 64, 100 } },
+ { EEPROM_HB_OFDM_HT40_BAND, 3, IEEE80211_BAND_5GHZ,
+ false, false, true,
+ { 36, 60, 100 } },
+ { EEPROM_LB_OFDM_20_CHANNEL_13, 2, IEEE80211_BAND_2GHZ,
+ false, false, false,
+ { 13, 13 } },
+ { EEPROM_HB_OFDM_20_CHANNEL_140, 2, IEEE80211_BAND_5GHZ,
+ false, false, false,
+ { 140, 140 } },
+ { EEPROM_HB_OFDM_HT40_BAND_1, 2, IEEE80211_BAND_5GHZ,
+ false, false, true,
+ { 132, 44 } },
+};
+
/******************************************************************************
*
* EEPROM related functions
@@ -152,6 +224,19 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
+static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
+{
+ u32 otpgp;
+
+ otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
+ if (mode == IWL_OTP_ACCESS_ABSOLUTE)
+ iwl_clear_bit(priv, CSR_OTP_GP_REG,
+ CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+ else
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
+ CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+}
+
static int iwlcore_get_nvm_type(struct iwl_priv *priv)
{
u32 otpgp;
@@ -159,6 +244,9 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv)
/* OTP only valid for CP/PP and after */
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+ case CSR_HW_REV_TYPE_NONE:
+ IWL_ERR(priv, "Unknown hardware type\n");
+ return -ENOENT;
case CSR_HW_REV_TYPE_3945:
case CSR_HW_REV_TYPE_4965:
case CSR_HW_REV_TYPE_5300:
@@ -249,6 +337,124 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
return ret;
}
+static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data)
+{
+ int ret = 0;
+ u32 r;
+ u32 otpgp;
+
+ _iwl_write32(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+ ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_READ_VALID_MSK,
+ IWL_EEPROM_ACCESS_TIMEOUT);
+ if (ret < 0) {
+ IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
+ return ret;
+ }
+ r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
+ /* check for ECC errors: */
+ otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
+ if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
+ /* stop in this case */
+ /* set the uncorrectable OTP ECC bit for acknowledgement */
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
+ CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
+ IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n");
+ return -EINVAL;
+ }
+ if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
+ /* continue in this case */
+ /* set the correctable OTP ECC bit for acknowledgement */
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
+ CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
+ IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
+ }
+ *eeprom_data = le16_to_cpu((__force __le16)(r >> 16));
+ return 0;
+}
+
+/*
+ * iwl_is_otp_empty: check for empty OTP
+ */
+static bool iwl_is_otp_empty(struct iwl_priv *priv)
+{
+ u16 next_link_addr = 0, link_value;
+ bool is_empty = false;
+
+ /* locate the beginning of OTP link list */
+ if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) {
+ if (!link_value) {
+ IWL_ERR(priv, "OTP is empty\n");
+ is_empty = true;
+ }
+ } else {
+ IWL_ERR(priv, "Unable to read first block of OTP list.\n");
+ is_empty = true;
+ }
+
+ return is_empty;
+}
+
+
+/*
+ * iwl_find_otp_image: find EEPROM image in OTP
+ * finding the OTP block that contains the EEPROM image.
+ * the last valid block on the link list (the block _before_ the last block)
+ * is the block we should read and used to configure the device.
+ * If all the available OTP blocks are full, the last block will be the block
+ * we should read and used to configure the device.
+ * only perform this operation if shadow RAM is disabled
+ */
+static int iwl_find_otp_image(struct iwl_priv *priv,
+ u16 *validblockaddr)
+{
+ u16 next_link_addr = 0, link_value = 0, valid_addr;
+ int ret = 0;
+ int usedblocks = 0;
+
+ /* set addressing mode to absolute to traverse the link list */
+ iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE);
+
+ /* checking for empty OTP or error */
+ if (iwl_is_otp_empty(priv))
+ return -EINVAL;
+
+ /*
+ * start traverse link list
+ * until reach the max number of OTP blocks
+ * different devices have different number of OTP blocks
+ */
+ do {
+ /* save current valid block address
+ * check for more block on the link list
+ */
+ valid_addr = next_link_addr;
+ next_link_addr = link_value;
+ IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n",
+ usedblocks, next_link_addr);
+ if (iwl_read_otp_word(priv, next_link_addr, &link_value))
+ return -EINVAL;
+ if (!link_value) {
+ /*
+ * reach the end of link list,
+ * set address point to the starting address
+ * of the image
+ */
+ goto done;
+ }
+ /* more in the link list, continue */
+ usedblocks++;
+ } while (usedblocks < priv->cfg->max_ll_items);
+ /* OTP full, use last block */
+ IWL_DEBUG_INFO(priv, "OTP is full, use last block\n");
+done:
+ *validblockaddr = valid_addr;
+ /* skip first 2 bytes (link list pointer) */
+ *validblockaddr += 2;
+ return ret;
+}
+
/**
* iwl_eeprom_init - read EEPROM contents
*
@@ -263,14 +469,14 @@ int iwl_eeprom_init(struct iwl_priv *priv)
int sz;
int ret;
u16 addr;
- u32 otpgp;
+ u16 validblockaddr = 0;
+ u16 cache_addr = 0;
priv->nvm_device_type = iwlcore_get_nvm_type(priv);
-
+ if (priv->nvm_device_type == -ENOENT)
+ return -ENOENT;
/* allocate eeprom */
- if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
- priv->cfg->eeprom_size =
- OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL;
+ IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size);
sz = priv->cfg->eeprom_size;
priv->eeprom = kzalloc(sz, GFP_KERNEL);
if (!priv->eeprom) {
@@ -298,46 +504,31 @@ int iwl_eeprom_init(struct iwl_priv *priv)
if (ret) {
IWL_ERR(priv, "Failed to initialize OTP access.\n");
ret = -ENOENT;
- goto err;
+ goto done;
}
_iwl_write32(priv, CSR_EEPROM_GP,
iwl_read32(priv, CSR_EEPROM_GP) &
~CSR_EEPROM_GP_IF_OWNER_MSK);
- /* clear */
- _iwl_write32(priv, CSR_OTP_GP_REG,
- iwl_read32(priv, CSR_OTP_GP_REG) |
+
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
-
- for (addr = 0; addr < sz; addr += sizeof(u16)) {
- u32 r;
-
- _iwl_write32(priv, CSR_EEPROM_REG,
- CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-
- ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
- CSR_EEPROM_REG_READ_VALID_MSK,
- IWL_EEPROM_ACCESS_TIMEOUT);
- if (ret < 0) {
- IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
+ /* traversing the linked list if no shadow ram supported */
+ if (!priv->cfg->shadow_ram_support) {
+ if (iwl_find_otp_image(priv, &validblockaddr)) {
+ ret = -ENOENT;
goto done;
}
- r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
- /* check for ECC errors: */
- otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
- if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
- /* stop in this case */
- IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n");
+ }
+ for (addr = validblockaddr; addr < validblockaddr + sz;
+ addr += sizeof(u16)) {
+ u16 eeprom_data;
+
+ ret = iwl_read_otp_word(priv, addr, &eeprom_data);
+ if (ret)
goto done;
- }
- if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
- /* continue in this case */
- _iwl_write32(priv, CSR_OTP_GP_REG,
- iwl_read32(priv, CSR_OTP_GP_REG) |
- CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
- IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
- }
- e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
+ e[cache_addr / 2] = eeprom_data;
+ cache_addr += sizeof(u16);
}
} else {
/* eeprom is an array of 16bit values */
@@ -458,13 +649,13 @@ static void iwl_init_band_reference(const struct iwl_priv *priv,
iwl_eeprom_query_addr(priv, offset);
*eeprom_ch_index = iwl_eeprom_band_5;
break;
- case 6: /* 2.4GHz FAT channels */
+ case 6: /* 2.4GHz ht40 channels */
*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
*eeprom_ch_info = (struct iwl_eeprom_channel *)
iwl_eeprom_query_addr(priv, offset);
*eeprom_ch_index = iwl_eeprom_band_6;
break;
- case 7: /* 5 GHz FAT channels */
+ case 7: /* 5 GHz ht40 channels */
*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
*eeprom_ch_info = (struct iwl_eeprom_channel *)
iwl_eeprom_query_addr(priv, offset);
@@ -480,14 +671,14 @@ static void iwl_init_band_reference(const struct iwl_priv *priv,
? # x " " : "")
/**
- * iwl_set_fat_chan_info - Copy fat channel info into driver's priv.
+ * iwl_mod_ht40_chan_info - Copy ht40 channel info into driver's priv.
*
* Does not set up a command, or touch hardware.
*/
-static int iwl_set_fat_chan_info(struct iwl_priv *priv,
+static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
enum ieee80211_band band, u16 channel,
const struct iwl_eeprom_channel *eeprom_ch,
- u8 fat_extension_channel)
+ u8 clear_ht40_extension_channel)
{
struct iwl_channel_info *ch_info;
@@ -497,7 +688,7 @@ static int iwl_set_fat_chan_info(struct iwl_priv *priv,
if (!is_channel_valid(ch_info))
return -1;
- IWL_DEBUG_INFO(priv, "FAT Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):"
+ IWL_DEBUG_INFO(priv, "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):"
" Ad-Hoc %ssupported\n",
ch_info->channel,
is_channel_a_band(ch_info) ?
@@ -513,17 +704,189 @@ static int iwl_set_fat_chan_info(struct iwl_priv *priv,
&& !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ?
"" : "not ");
- ch_info->fat_eeprom = *eeprom_ch;
- ch_info->fat_max_power_avg = eeprom_ch->max_power_avg;
- ch_info->fat_curr_txpow = eeprom_ch->max_power_avg;
- ch_info->fat_min_power = 0;
- ch_info->fat_scan_power = eeprom_ch->max_power_avg;
- ch_info->fat_flags = eeprom_ch->flags;
- ch_info->fat_extension_channel = fat_extension_channel;
+ ch_info->ht40_eeprom = *eeprom_ch;
+ ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg;
+ ch_info->ht40_curr_txpow = eeprom_ch->max_power_avg;
+ ch_info->ht40_min_power = 0;
+ ch_info->ht40_scan_power = eeprom_ch->max_power_avg;
+ ch_info->ht40_flags = eeprom_ch->flags;
+ ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel;
return 0;
}
+/**
+ * iwl_get_max_txpower_avg - get the highest tx power from all chains.
+ * find the highest tx power from all chains for the channel
+ */
+static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
+ struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element)
+{
+ s8 max_txpower_avg = 0; /* (dBm) */
+
+ IWL_DEBUG_INFO(priv, "%d - "
+ "chain_a: %d dB chain_b: %d dB "
+ "chain_c: %d dB mimo2: %d dB mimo3: %d dB\n",
+ element,
+ enhanced_txpower[element].chain_a_max >> 1,
+ enhanced_txpower[element].chain_b_max >> 1,
+ enhanced_txpower[element].chain_c_max >> 1,
+ enhanced_txpower[element].mimo2_max >> 1,
+ enhanced_txpower[element].mimo3_max >> 1);
+ /* Take the highest tx power from any valid chains */
+ if ((priv->cfg->valid_tx_ant & ANT_A) &&
+ (enhanced_txpower[element].chain_a_max > max_txpower_avg))
+ max_txpower_avg = enhanced_txpower[element].chain_a_max;
+ if ((priv->cfg->valid_tx_ant & ANT_B) &&
+ (enhanced_txpower[element].chain_b_max > max_txpower_avg))
+ max_txpower_avg = enhanced_txpower[element].chain_b_max;
+ if ((priv->cfg->valid_tx_ant & ANT_C) &&
+ (enhanced_txpower[element].chain_c_max > max_txpower_avg))
+ max_txpower_avg = enhanced_txpower[element].chain_c_max;
+ if (((priv->cfg->valid_tx_ant == ANT_AB) |
+ (priv->cfg->valid_tx_ant == ANT_BC) |
+ (priv->cfg->valid_tx_ant == ANT_AC)) &&
+ (enhanced_txpower[element].mimo2_max > max_txpower_avg))
+ max_txpower_avg = enhanced_txpower[element].mimo2_max;
+ if ((priv->cfg->valid_tx_ant == ANT_ABC) &&
+ (enhanced_txpower[element].mimo3_max > max_txpower_avg))
+ max_txpower_avg = enhanced_txpower[element].mimo3_max;
+
+ /* max. tx power in EEPROM is in 1/2 dBm format
+ * convert from 1/2 dBm to dBm
+ */
+ return max_txpower_avg >> 1;
+}
+
+/**
+ * iwl_update_common_txpower: update channel tx power
+ * update tx power per band based on EEPROM enhanced tx power info.
+ */
+static s8 iwl_update_common_txpower(struct iwl_priv *priv,
+ struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
+ int section, int element)
+{
+ struct iwl_channel_info *ch_info;
+ int ch;
+ bool is_ht40 = false;
+ s8 max_txpower_avg; /* (dBm) */
+
+ /* it is common section, contain all type (Legacy, HT and HT40)
+ * based on the element in the section to determine
+ * is it HT 40 or not
+ */
+ if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX)
+ is_ht40 = true;
+ max_txpower_avg =
+ iwl_get_max_txpower_avg(priv, enhanced_txpower, element);
+ ch_info = priv->channel_info;
+
+ for (ch = 0; ch < priv->channel_count; ch++) {
+ /* find matching band and update tx power if needed */
+ if ((ch_info->band == enhinfo[section].band) &&
+ (ch_info->max_power_avg < max_txpower_avg) && (!is_ht40)) {
+ /* Update regulatory-based run-time data */
+ ch_info->max_power_avg = ch_info->curr_txpow =
+ max_txpower_avg;
+ ch_info->scan_power = max_txpower_avg;
+ }
+ if ((ch_info->band == enhinfo[section].band) && is_ht40 &&
+ ch_info->ht40_max_power_avg &&
+ (ch_info->ht40_max_power_avg < max_txpower_avg)) {
+ /* Update regulatory-based run-time data */
+ ch_info->ht40_max_power_avg = max_txpower_avg;
+ ch_info->ht40_curr_txpow = max_txpower_avg;
+ ch_info->ht40_scan_power = max_txpower_avg;
+ }
+ ch_info++;
+ }
+ return max_txpower_avg;
+}
+
+/**
+ * iwl_update_channel_txpower: update channel tx power
+ * update channel tx power based on EEPROM enhanced tx power info.
+ */
+static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
+ struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
+ int section, int element)
+{
+ struct iwl_channel_info *ch_info;
+ int ch;
+ u8 channel;
+ s8 max_txpower_avg; /* (dBm) */
+
+ channel = enhinfo[section].iwl_eeprom_section_channel[element];
+ max_txpower_avg =
+ iwl_get_max_txpower_avg(priv, enhanced_txpower, element);
+
+ ch_info = priv->channel_info;
+ for (ch = 0; ch < priv->channel_count; ch++) {
+ /* find matching channel and update tx power if needed */
+ if (ch_info->channel == channel) {
+ if ((ch_info->max_power_avg < max_txpower_avg) &&
+ (!enhinfo[section].is_ht40)) {
+ /* Update regulatory-based run-time data */
+ ch_info->max_power_avg = max_txpower_avg;
+ ch_info->curr_txpow = max_txpower_avg;
+ ch_info->scan_power = max_txpower_avg;
+ }
+ if ((enhinfo[section].is_ht40) &&
+ (ch_info->ht40_max_power_avg) &&
+ (ch_info->ht40_max_power_avg < max_txpower_avg)) {
+ /* Update regulatory-based run-time data */
+ ch_info->ht40_max_power_avg = max_txpower_avg;
+ ch_info->ht40_curr_txpow = max_txpower_avg;
+ ch_info->ht40_scan_power = max_txpower_avg;
+ }
+ break;
+ }
+ ch_info++;
+ }
+ return max_txpower_avg;
+}
+
+/**
+ * iwlcore_eeprom_enhanced_txpower: process enhanced tx power info
+ */
+void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
+{
+ int eeprom_section_count = 0;
+ int section, element;
+ struct iwl_eeprom_enhanced_txpwr *enhanced_txpower;
+ u32 offset;
+ s8 max_txpower_avg; /* (dBm) */
+
+ /* Loop through all the sections
+ * adjust bands and channel's max tx power
+ * Set the tx_power_user_lmt to the highest power
+ * supported by any channels and chains
+ */
+ for (section = 0; section < ARRAY_SIZE(enhinfo); section++) {
+ eeprom_section_count = enhinfo[section].count;
+ offset = enhinfo[section].offset;
+ enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *)
+ iwl_eeprom_query_addr(priv, offset);
+
+ for (element = 0; element < eeprom_section_count; element++) {
+ if (enhinfo[section].is_common)
+ max_txpower_avg =
+ iwl_update_common_txpower(priv,
+ enhanced_txpower, section, element);
+ else
+ max_txpower_avg =
+ iwl_update_channel_txpower(priv,
+ enhanced_txpower, section, element);
+
+ /* Update the tx_power_user_lmt to the highest power
+ * supported by any channel */
+ if (max_txpower_avg > priv->tx_power_user_lmt)
+ priv->tx_power_user_lmt = max_txpower_avg;
+ }
+ }
+}
+EXPORT_SYMBOL(iwlcore_eeprom_enhanced_txpower);
+
#define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
? # x " " : "")
@@ -585,11 +948,10 @@ int iwl_init_channel_map(struct iwl_priv *priv)
/* Copy the run-time flags so they are there even on
* invalid channels */
ch_info->flags = eeprom_ch_info[ch].flags;
- /* First write that fat is not enabled, and then enable
+ /* First write that ht40 is not enabled, and then enable
* one by one */
- ch_info->fat_extension_channel =
- (IEEE80211_CHAN_NO_HT40PLUS |
- IEEE80211_CHAN_NO_HT40MINUS);
+ ch_info->ht40_extension_channel =
+ IEEE80211_CHAN_NO_HT40;
if (!(is_channel_valid(ch_info))) {
IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - "
@@ -638,17 +1000,16 @@ int iwl_init_channel_map(struct iwl_priv *priv)
}
}
- /* Check if we do have FAT channels */
+ /* Check if we do have HT40 channels */
if (priv->cfg->ops->lib->eeprom_ops.regulatory_bands[5] ==
- EEPROM_REGULATORY_BAND_NO_FAT &&
+ EEPROM_REGULATORY_BAND_NO_HT40 &&
priv->cfg->ops->lib->eeprom_ops.regulatory_bands[6] ==
- EEPROM_REGULATORY_BAND_NO_FAT)
+ EEPROM_REGULATORY_BAND_NO_HT40)
return 0;
- /* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */
+ /* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */
for (band = 6; band <= 7; band++) {
enum ieee80211_band ieeeband;
- u8 fat_extension_chan;
iwl_init_band_reference(priv, band, &eeprom_ch_count,
&eeprom_ch_info, &eeprom_ch_index);
@@ -659,31 +1020,28 @@ int iwl_init_channel_map(struct iwl_priv *priv)
/* Loop through each band adding each of the channels */
for (ch = 0; ch < eeprom_ch_count; ch++) {
-
- if ((band == 6) &&
- ((eeprom_ch_index[ch] == 5) ||
- (eeprom_ch_index[ch] == 6) ||
- (eeprom_ch_index[ch] == 7)))
- /* both are allowed: above and below */
- fat_extension_chan = 0;
- else
- fat_extension_chan =
- IEEE80211_CHAN_NO_HT40MINUS;
-
/* Set up driver's info for lower half */
- iwl_set_fat_chan_info(priv, ieeeband,
+ iwl_mod_ht40_chan_info(priv, ieeeband,
eeprom_ch_index[ch],
- &(eeprom_ch_info[ch]),
- fat_extension_chan);
+ &eeprom_ch_info[ch],
+ IEEE80211_CHAN_NO_HT40PLUS);
/* Set up driver's info for upper half */
- iwl_set_fat_chan_info(priv, ieeeband,
- (eeprom_ch_index[ch] + 4),
- &(eeprom_ch_info[ch]),
- IEEE80211_CHAN_NO_HT40PLUS);
+ iwl_mod_ht40_chan_info(priv, ieeeband,
+ eeprom_ch_index[ch] + 4,
+ &eeprom_ch_info[ch],
+ IEEE80211_CHAN_NO_HT40MINUS);
}
}
+ /* for newer device (6000 series and up)
+ * EEPROM contain enhanced tx power information
+ * driver need to process addition information
+ * to determine the max channel tx power limits
+ */
+ if (priv->cfg->ops->lib->eeprom_ops.update_enhanced_txpower)
+ priv->cfg->ops->lib->eeprom_ops.update_enhanced_txpower(priv);
+
return 0;
}
EXPORT_SYMBOL(iwl_init_channel_map);
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 195b4ef12c27..6b68db7b1b81 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -88,10 +88,10 @@ struct iwl_priv;
* requirement for establishing a new network for legal operation on channels
* requiring RADAR detection or restricting ACTIVE scanning.
*
- * NOTE: "WIDE" flag does not indicate anything about "FAT" 40 MHz channels.
- * It only indicates that 20 MHz channel use is supported; FAT channel
+ * NOTE: "WIDE" flag does not indicate anything about "HT40" 40 MHz channels.
+ * It only indicates that 20 MHz channel use is supported; HT40 channel
* usage is indicated by a separate set of regulatory flags for each
- * FAT channel pair.
+ * HT40 channel pair.
*
* NOTE: Using a channel inappropriately will result in a uCode error!
*/
@@ -112,12 +112,36 @@ enum {
#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1)
/* *regulatory* channel data format in eeprom, one for each channel.
- * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */
+ * There are separate entries for HT40 (40 MHz) vs. normal (20 MHz) channels. */
struct iwl_eeprom_channel {
u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */
s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
} __attribute__ ((packed));
+/**
+ * iwl_eeprom_enhanced_txpwr structure
+ * This structure presents the enhanced regulatory tx power limit layout
+ * in eeprom image
+ * Enhanced regulatory tx power portion of eeprom image can be broken down
+ * into individual structures; each one is 8 bytes in size and contain the
+ * following information
+ * @chain_a_max_pwr: chain a max power in 1/2 dBm
+ * @chain_b_max_pwr: chain b max power in 1/2 dBm
+ * @chain_c_max_pwr: chain c max power in 1/2 dBm
+ * @mimo2_max_pwr: mimo2 max power in 1/2 dBm
+ * @mimo3_max_pwr: mimo3 max power in 1/2 dBm
+ *
+ */
+struct iwl_eeprom_enhanced_txpwr {
+ u16 reserved;
+ s8 chain_a_max;
+ s8 chain_b_max;
+ s8 chain_c_max;
+ s8 reserved1;
+ s8 mimo2_max;
+ s8 mimo3_max;
+} __attribute__ ((packed));
+
/* 3945 Specific */
#define EEPROM_3945_EEPROM_VERSION (0x2f)
@@ -170,18 +194,77 @@ struct iwl_eeprom_channel {
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */
#define EEPROM_5000_REG_BAND_5_CHANNELS ((0x74)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 12 bytes */
-#define EEPROM_5000_REG_BAND_24_FAT_CHANNELS ((0x82)\
+#define EEPROM_5000_REG_BAND_24_HT40_CHANNELS ((0x82)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */
-#define EEPROM_5000_REG_BAND_52_FAT_CHANNELS ((0x92)\
+#define EEPROM_5000_REG_BAND_52_HT40_CHANNELS ((0x92)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */
+/* 6000 and up regulatory tx power - indirect access */
+/* max. elements per section */
+#define EEPROM_MAX_TXPOWER_SECTION_ELEMENTS (8)
+#define EEPROM_TXPOWER_COMMON_HT40_INDEX (2)
+
+/**
+ * Partition the enhanced tx power portion of eeprom image into
+ * 10 sections based on band, modulation, frequency and channel
+ *
+ * Section 1: all CCK channels
+ * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40 ) channels
+ * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels
+ * Section 4: 2.4 GHz 20MHz channels: 1, 2, 10, 11. Both Legacy and HT
+ * Section 5: 2.4 GHz 40MHz channels: 1, 2, 6, 7, 9, (_above_)
+ * Section 6: 5.2 GHz 20MHz channels: 36, 64, 100, both Legacy and HT
+ * Section 7: 5.2 GHz 40MHz channels: 36, 60, 100 (_above_)
+ * Section 8: 2.4 GHz channel 13, Both Legacy and HT
+ * Section 9: 2.4 GHz channel 140, Both Legacy and HT
+ * Section 10: 2.4 GHz 40MHz channels: 132, 44 (_above_)
+ */
+/* 2.4 GHz band: CCK */
+#define EEPROM_LB_CCK_20_COMMON ((0xAA)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 8 bytes */
+/* 2.4 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */
+#define EEPROM_LB_OFDM_COMMON ((0xB2)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
+/* 5.2 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */
+#define EEPROM_HB_OFDM_COMMON ((0xCA)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
+/* 2.4GHz band channels:
+ * 1Legacy, 1HT, 2Legacy, 2HT, 10Legacy, 10HT, 11Legacy, 11HT */
+#define EEPROM_LB_OFDM_20_BAND ((0xE2)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 64 bytes */
+/* 2.4 GHz band HT40 channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1) */
+#define EEPROM_LB_OFDM_HT40_BAND ((0x122)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 40 bytes */
+/* 5.2GHz band channels: 36Legacy, 36HT, 64Legacy, 64HT, 100Legacy, 100HT */
+#define EEPROM_HB_OFDM_20_BAND ((0x14A)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 48 bytes */
+/* 5.2 GHz band HT40 channels: (36,+1) (60,+1) (100,+1) */
+#define EEPROM_HB_OFDM_HT40_BAND ((0x17A)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
+/* 2.4 GHz band, channnel 13: Legacy, HT */
+#define EEPROM_LB_OFDM_20_CHANNEL_13 ((0x192)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
+/* 5.2 GHz band, channnel 140: Legacy, HT */
+#define EEPROM_HB_OFDM_20_CHANNEL_140 ((0x1A2)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
+/* 5.2 GHz band, HT40 channnels (132,+1) (44,+1) */
+#define EEPROM_HB_OFDM_HT40_BAND_1 ((0x1B2)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
+
+
/* 5050 Specific */
#define EEPROM_5050_TX_POWER_VERSION (4)
#define EEPROM_5050_EEPROM_VERSION (0x21E)
/* OTP */
-#define OTP_LOWER_BLOCKS_TOTAL (3)
-#define OTP_BLOCK_SIZE (0x400)
+/* lower blocks contain EEPROM image and calibration data */
+#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */
+/* high blocks contain PAPD data */
+#define OTP_HIGH_IMAGE_SIZE_6x00 (6 * 512 * sizeof(u16)) /* 6 KB */
+#define OTP_HIGH_IMAGE_SIZE_1000 (0x200 * sizeof(u16)) /* 1024 bytes */
+#define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */
+#define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */
+#define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */
/* 2.4 GHz */
extern const u8 iwl_eeprom_band_1[14];
@@ -313,7 +396,7 @@ struct iwl_eeprom_calib_info {
* in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
* txpower (MSB).
*
- * Entries immediately below are for 20 MHz channel width. FAT (40 MHz)
+ * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz)
* channels (only for 4965, not supported by 3945) appear later in the EEPROM.
*
* 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
@@ -352,29 +435,29 @@ struct iwl_eeprom_calib_info {
#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */
/*
- * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11)
+ * 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11)
*
* The channel listed is the center of the lower 20 MHz half of the channel.
* The overall center frequency is actually 2 channels (10 MHz) above that,
- * and the upper half of each FAT channel is centered 4 channels (20 MHz) away
- * from the lower half; e.g. the upper half of FAT channel 1 is channel 5,
- * and the overall FAT channel width centers on channel 3.
+ * and the upper half of each HT40 channel is centered 4 channels (20 MHz) away
+ * from the lower half; e.g. the upper half of HT40 channel 1 is channel 5,
+ * and the overall HT40 channel width centers on channel 3.
*
* NOTE: The RXON command uses 20 MHz channel numbers to specify the
* control channel to which to tune. RXON also specifies whether the
- * control channel is the upper or lower half of a FAT channel.
+ * control channel is the upper or lower half of a HT40 channel.
*
- * NOTE: 4965 does not support FAT channels on 2.4 GHz.
+ * NOTE: 4965 does not support HT40 channels on 2.4 GHz.
*/
-#define EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */
+#define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */
/*
- * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64),
+ * 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64),
* 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161)
*/
-#define EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */
+#define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */
-#define EEPROM_REGULATORY_BAND_NO_FAT (0)
+#define EEPROM_REGULATORY_BAND_NO_HT40 (0)
struct iwl_eeprom_ops {
const u32 regulatory_bands[7];
@@ -383,6 +466,7 @@ struct iwl_eeprom_ops {
void (*release_semaphore) (struct iwl_priv *priv);
u16 (*calib_version) (struct iwl_priv *priv);
const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset);
+ void (*update_enhanced_txpower) (struct iwl_priv *priv);
};
@@ -397,7 +481,7 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv);
int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv);
void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
-
+void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv);
int iwl_init_channel_map(struct iwl_priv *priv);
void iwl_free_channel_map(struct iwl_priv *priv);
const struct iwl_channel_info *iwl_get_channel_info(
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 17d61ac8ed61..532c8d6cd8da 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -36,8 +36,6 @@
#include "iwl-core.h"
-#define IWL_CMD(x) case x: return #x
-
const char *get_cmd_string(u8 cmd)
{
switch (cmd) {
@@ -103,22 +101,23 @@ EXPORT_SYMBOL(get_cmd_string);
#define HOST_COMPLETE_TIMEOUT (HZ / 2)
-static int iwl_generic_cmd_callback(struct iwl_priv *priv,
- struct iwl_cmd *cmd, struct sk_buff *skb)
+static void iwl_generic_cmd_callback(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb)
{
struct iwl_rx_packet *pkt = NULL;
if (!skb) {
IWL_ERR(priv, "Error: Response NULL in %s.\n",
get_cmd_string(cmd->hdr.cmd));
- return 1;
+ return;
}
pkt = (struct iwl_rx_packet *)skb->data;
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from %s (0x%08X)\n",
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
- return 1;
+ return;
}
#ifdef CONFIG_IWLWIFI_DEBUG
@@ -127,29 +126,26 @@ static int iwl_generic_cmd_callback(struct iwl_priv *priv,
case SENSITIVITY_CMD:
IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n",
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
- break;
+ break;
default:
IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n",
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
}
#endif
-
- /* Let iwl_tx_complete free the response skb */
- return 1;
}
static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{
int ret;
- BUG_ON(!(cmd->meta.flags & CMD_ASYNC));
+ BUG_ON(!(cmd->flags & CMD_ASYNC));
/* An asynchronous command can not expect an SKB to be set. */
- BUG_ON(cmd->meta.flags & CMD_WANT_SKB);
+ BUG_ON(cmd->flags & CMD_WANT_SKB);
/* Assign a generic callback if one is not provided */
- if (!cmd->meta.u.callback)
- cmd->meta.u.callback = iwl_generic_cmd_callback;
+ if (!cmd->callback)
+ cmd->callback = iwl_generic_cmd_callback;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return -EBUSY;
@@ -168,10 +164,10 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
int cmd_idx;
int ret;
- BUG_ON(cmd->meta.flags & CMD_ASYNC);
+ BUG_ON(cmd->flags & CMD_ASYNC);
/* A synchronous command can not have a callback set. */
- BUG_ON(cmd->meta.u.callback != NULL);
+ BUG_ON(cmd->callback);
if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) {
IWL_ERR(priv,
@@ -183,9 +179,6 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
set_bit(STATUS_HCMD_ACTIVE, &priv->status);
- if (cmd->meta.flags & CMD_WANT_SKB)
- cmd->meta.source = &cmd->meta;
-
cmd_idx = iwl_enqueue_hcmd(priv, cmd);
if (cmd_idx < 0) {
ret = cmd_idx;
@@ -222,7 +215,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
ret = -EIO;
goto fail;
}
- if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {
+ if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_skb) {
IWL_ERR(priv, "Error: Response NULL in '%s'\n",
get_cmd_string(cmd->id));
ret = -EIO;
@@ -233,20 +226,20 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
goto out;
cancel:
- if (cmd->meta.flags & CMD_WANT_SKB) {
- struct iwl_cmd *qcmd;
-
- /* Cancel the CMD_WANT_SKB flag for the cmd in the
+ if (cmd->flags & CMD_WANT_SKB) {
+ /*
+ * Cancel the CMD_WANT_SKB flag for the cmd in the
* TX cmd queue. Otherwise in case the cmd comes
* in later, it will possibly set an invalid
- * address (cmd->meta.source). */
- qcmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
- qcmd->meta.flags &= ~CMD_WANT_SKB;
+ * address (cmd->meta.source).
+ */
+ priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_idx].flags &=
+ ~CMD_WANT_SKB;
}
fail:
- if (cmd->meta.u.skb) {
- dev_kfree_skb_any(cmd->meta.u.skb);
- cmd->meta.u.skb = NULL;
+ if (cmd->reply_skb) {
+ dev_kfree_skb_any(cmd->reply_skb);
+ cmd->reply_skb = NULL;
}
out:
clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
@@ -256,7 +249,7 @@ EXPORT_SYMBOL(iwl_send_cmd_sync);
int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{
- if (cmd->meta.flags & CMD_ASYNC)
+ if (cmd->flags & CMD_ASYNC)
return iwl_send_cmd_async(priv, cmd);
return iwl_send_cmd_sync(priv, cmd);
@@ -277,9 +270,9 @@ EXPORT_SYMBOL(iwl_send_cmd_pdu);
int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
u8 id, u16 len, const void *data,
- int (*callback)(struct iwl_priv *priv,
- struct iwl_cmd *cmd,
- struct sk_buff *skb))
+ void (*callback)(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb))
{
struct iwl_host_cmd cmd = {
.id = id,
@@ -287,8 +280,8 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
.data = data,
};
- cmd.meta.flags |= CMD_ASYNC;
- cmd.meta.u.callback = callback;
+ cmd.flags |= CMD_ASYNC;
+ cmd.callback = callback;
return iwl_send_cmd_async(priv, &cmd);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index a1328c3c81ae..bd0b12efb5c7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -145,4 +145,25 @@ static inline void iwl_stop_queue(struct iwl_priv *priv, u8 queue)
#define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue
#define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue
+static inline void iwl_disable_interrupts(struct iwl_priv *priv)
+{
+ clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+ /* disable interrupts from uCode/NIC to host */
+ iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+ /* acknowledge/clear/reset any interrupts still pending
+ * from uCode or flow handler (Rx/Tx DMA) */
+ iwl_write32(priv, CSR_INT, 0xffffffff);
+ iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+ IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
+}
+
+static inline void iwl_enable_interrupts(struct iwl_priv *priv)
+{
+ IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
+ set_bit(STATUS_INT_ENABLED, &priv->status);
+ iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
+}
+
#endif /* __iwl_helpers_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index 5e64252f80f6..f420c99e7240 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -54,7 +54,7 @@ static const char *led_type_str[] = {
static const struct {
- u16 tpt;
+ u16 tpt; /* Mb/s */
u8 on_time;
u8 off_time;
} blink_tbl[] =
@@ -91,8 +91,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
.id = REPLY_LEDS_CMD,
.len = sizeof(struct iwl_led_cmd),
.data = led_cmd,
- .meta.flags = CMD_ASYNC,
- .meta.u.callback = NULL,
+ .flags = CMD_ASYNC,
+ .callback = NULL,
};
u32 reg;
@@ -104,7 +104,7 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
}
/* Set led pattern command */
-static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
+static int iwl_led_pattern(struct iwl_priv *priv, int led_id,
unsigned int idx)
{
struct iwl_led_cmd led_cmd = {
@@ -121,7 +121,7 @@ static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
}
/* Set led register off */
-static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
+static int iwl_led_on_reg(struct iwl_priv *priv, int led_id)
{
IWL_DEBUG_LED(priv, "led on %d\n", led_id);
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
@@ -130,7 +130,7 @@ static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
#if 0
/* Set led on command */
-static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
+static int iwl_led_on(struct iwl_priv *priv, int led_id)
{
struct iwl_led_cmd led_cmd = {
.id = led_id,
@@ -142,7 +142,7 @@ static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
}
/* Set led off command */
-int iwl4965_led_off(struct iwl_priv *priv, int led_id)
+int iwl_led_off(struct iwl_priv *priv, int led_id)
{
struct iwl_led_cmd led_cmd = {
.id = led_id,
@@ -157,7 +157,7 @@ int iwl4965_led_off(struct iwl_priv *priv, int led_id)
/* Set led register off */
-static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id)
+static int iwl_led_off_reg(struct iwl_priv *priv, int led_id)
{
IWL_DEBUG_LED(priv, "LED Reg off\n");
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF);
@@ -171,7 +171,7 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id)
{
IWL_DEBUG_LED(priv, "Associated\n");
priv->allow_blinking = 1;
- return iwl4965_led_on_reg(priv, led_id);
+ return iwl_led_on_reg(priv, led_id);
}
static int iwl_led_disassociate(struct iwl_priv *priv, int led_id)
{
@@ -264,13 +264,16 @@ static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led,
/*
- * calculate blink rate according to last 2 sec Tx/Rx activities
+ * calculate blink rate according to last second Tx/Rx activities
*/
static int iwl_get_blink_rate(struct iwl_priv *priv)
{
int i;
- u64 current_tpt = priv->tx_stats[2].bytes;
- /* FIXME: + priv->rx_stats[2].bytes; */
+ /* count both tx and rx traffic to be able to
+ * handle traffic in either direction
+ */
+ u64 current_tpt = priv->tx_stats.data_bytes +
+ priv->rx_stats.data_bytes;
s64 tpt = current_tpt - priv->led_tpt;
if (tpt < 0) /* wraparound */
@@ -314,7 +317,7 @@ void iwl_leds_background(struct iwl_priv *priv)
priv->last_blink_time = 0;
if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
- iwl4965_led_pattern(priv, IWL_LED_LINK,
+ iwl_led_pattern(priv, IWL_LED_LINK,
IWL_SOLID_BLINK_IDX);
}
return;
@@ -328,12 +331,11 @@ void iwl_leds_background(struct iwl_priv *priv)
/* call only if blink rate change */
if (blink_idx != priv->last_blink_rate)
- iwl4965_led_pattern(priv, IWL_LED_LINK, blink_idx);
+ iwl_led_pattern(priv, IWL_LED_LINK, blink_idx);
priv->last_blink_time = jiffies;
priv->last_blink_rate = blink_idx;
}
-EXPORT_SYMBOL(iwl_leds_background);
/* Register all led handler */
int iwl_leds_register(struct iwl_priv *priv)
@@ -351,8 +353,8 @@ int iwl_leds_register(struct iwl_priv *priv)
sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
wiphy_name(priv->hw->wiphy));
- priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg;
- priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg;
+ priv->led[IWL_LED_TRG_RADIO].led_on = iwl_led_on_reg;
+ priv->led[IWL_LED_TRG_RADIO].led_off = iwl_led_off_reg;
priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO],
@@ -386,7 +388,7 @@ int iwl_leds_register(struct iwl_priv *priv)
priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated;
priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated;
- priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern;
+ priv->led[IWL_LED_TRG_RX].led_pattern = iwl_led_pattern;
if (ret)
goto exit_fail;
@@ -401,7 +403,7 @@ int iwl_leds_register(struct iwl_priv *priv)
priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated;
priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated;
- priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern;
+ priv->led[IWL_LED_TRG_TX].led_pattern = iwl_led_pattern;
if (ret)
goto exit_fail;
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index f2ea3f05f6e1..4ec6a8307cc6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -36,25 +36,41 @@
#include "iwl-eeprom.h"
#include "iwl-dev.h"
#include "iwl-core.h"
+#include "iwl-io.h"
#include "iwl-commands.h"
#include "iwl-debug.h"
#include "iwl-power.h"
/*
- * Setting power level allow the card to go to sleep when not busy.
+ * Setting power level allows the card to go to sleep when not busy.
*
- * The power level is set to INDEX_1 (the least deep state) by
- * default, and will, in the future, be the deepest state unless
- * otherwise required by pm_qos network latency requirements.
- *
- * Using INDEX_1 without pm_qos is ok because mac80211 will disable
- * PS when even checking every beacon for the TIM bit would exceed
- * the required latency.
+ * We calculate a sleep command based on the required latency, which
+ * we get from mac80211. In order to handle thermal throttling, we can
+ * also use pre-defined power levels.
*/
-#define IWL_POWER_RANGE_0_MAX (2)
-#define IWL_POWER_RANGE_1_MAX (10)
+/*
+ * For now, keep using power level 1 instead of automatically
+ * adjusting ...
+ */
+bool no_sleep_autoadjust = true;
+module_param(no_sleep_autoadjust, bool, S_IRUGO);
+MODULE_PARM_DESC(no_sleep_autoadjust,
+ "don't automatically adjust sleep level "
+ "according to maximum network latency");
+/*
+ * This defines the old power levels. They are still used by default
+ * (level 1) and for thermal throttle (levels 3 through 5)
+ */
+
+struct iwl_power_vec_entry {
+ struct iwl_powertable_cmd cmd;
+ u8 no_dtim;
+};
+
+#define IWL_DTIM_RANGE_0_MAX 2
+#define IWL_DTIM_RANGE_1_MAX 10
#define NOSLP cpu_to_le16(0), 0, 0
#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
@@ -66,9 +82,8 @@
cpu_to_le32(X3), \
cpu_to_le32(X4)}
/* default power management (not Tx power) table values */
-/* for DTIM period 0 through IWL_POWER_RANGE_0_MAX */
+/* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */
static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
- {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0},
@@ -77,9 +92,8 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
};
-/* for DTIM period IWL_POWER_RANGE_0_MAX + 1 through IWL_POWER_RANGE_1_MAX */
+/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */
static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
- {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0},
@@ -87,9 +101,8 @@ static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2}
};
-/* for DTIM period > IWL_POWER_RANGE_1_MAX */
+/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
- {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
@@ -97,80 +110,29 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
};
-
-/* set card power command */
-static int iwl_set_power(struct iwl_priv *priv, void *cmd)
-{
- return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD,
- sizeof(struct iwl_powertable_cmd), cmd);
-}
-
-/* initialize to default */
-static void iwl_power_init_handle(struct iwl_priv *priv)
-{
- struct iwl_power_mgr *pow_data;
- int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_NUM;
- struct iwl_powertable_cmd *cmd;
- int i;
- u16 lctl;
-
- IWL_DEBUG_POWER(priv, "Initialize power \n");
-
- pow_data = &priv->power_data;
-
- memset(pow_data, 0, sizeof(*pow_data));
-
- memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
- memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
- memcpy(&pow_data->pwr_range_2[0], &range_2[0], size);
-
- lctl = iwl_pcie_link_ctl(priv);
-
- IWL_DEBUG_POWER(priv, "adjust power command flags\n");
-
- for (i = 0; i < IWL_POWER_NUM; i++) {
- cmd = &pow_data->pwr_range_0[i].cmd;
-
- if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN)
- cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
- else
- cmd->flags |= IWL_POWER_PCI_PM_MSK;
- }
-}
-
-/* adjust power command according to DTIM period and power level*/
-static int iwl_update_power_cmd(struct iwl_priv *priv,
- struct iwl_powertable_cmd *cmd, u16 mode)
+static void iwl_static_sleep_cmd(struct iwl_priv *priv,
+ struct iwl_powertable_cmd *cmd,
+ enum iwl_power_level lvl, int period)
{
- struct iwl_power_vec_entry *range;
- struct iwl_power_mgr *pow_data;
- int i;
- u32 max_sleep = 0;
- u8 period;
+ const struct iwl_power_vec_entry *table;
+ int max_sleep, i;
bool skip;
- if (mode > IWL_POWER_INDEX_5) {
- IWL_DEBUG_POWER(priv, "Error invalid power mode \n");
- return -EINVAL;
- }
+ table = range_2;
+ if (period < IWL_DTIM_RANGE_1_MAX)
+ table = range_1;
+ if (period < IWL_DTIM_RANGE_0_MAX)
+ table = range_0;
- pow_data = &priv->power_data;
+ BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM);
- if (pow_data->dtim_period <= IWL_POWER_RANGE_0_MAX)
- range = &pow_data->pwr_range_0[0];
- else if (pow_data->dtim_period <= IWL_POWER_RANGE_1_MAX)
- range = &pow_data->pwr_range_1[0];
- else
- range = &pow_data->pwr_range_2[0];
-
- period = pow_data->dtim_period;
- memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd));
+ *cmd = table[lvl].cmd;
if (period == 0) {
- period = 1;
skip = false;
+ period = 1;
} else {
- skip = !!range[mode].no_dtim;
+ skip = !!table[lvl].no_dtim;
}
if (skip) {
@@ -178,7 +140,7 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
max_sleep = le32_to_cpu(slp_itrvl);
if (max_sleep == 0xFF)
max_sleep = period * (skip + 1);
- else if (max_sleep > period)
+ else if (max_sleep > period)
max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
} else {
@@ -190,6 +152,112 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
+ if (priv->power_data.pci_pm)
+ cmd->flags |= IWL_POWER_PCI_PM_MSK;
+ else
+ cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+
+ IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
+}
+
+/* default Thermal Throttling transaction table
+ * Current state | Throttling Down | Throttling Up
+ *=============================================================================
+ * Condition Nxt State Condition Nxt State Condition Nxt State
+ *-----------------------------------------------------------------------------
+ * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A
+ * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0
+ * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1
+ * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
+ *=============================================================================
+ */
+static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
+ {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
+ {IWL_TI_1, 105, CT_KILL_THRESHOLD},
+ {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
+ {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
+ {IWL_TI_2, 110, CT_KILL_THRESHOLD},
+ {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
+ {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
+ {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
+ {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
+ {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
+ {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
+ {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+};
+
+/* Advance Thermal Throttling default restriction table */
+static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
+ {IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
+ {IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
+ {IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
+ {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
+};
+
+
+static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv,
+ struct iwl_powertable_cmd *cmd)
+{
+ memset(cmd, 0, sizeof(*cmd));
+
+ if (priv->power_data.pci_pm)
+ cmd->flags |= IWL_POWER_PCI_PM_MSK;
+
+ IWL_DEBUG_POWER(priv, "Sleep command for CAM\n");
+}
+
+static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv,
+ struct iwl_powertable_cmd *cmd,
+ int dynps_ms, int wakeup_period)
+{
+ /*
+ * These are the original power level 3 sleep successions. The
+ * device may behave better with such succession and was also
+ * only tested with that. Just like the original sleep commands,
+ * also adjust the succession here to the wakeup_period below.
+ * The ranges are the same as for the sleep commands, 0-2, 3-9
+ * and >10, which is selected based on the DTIM interval for
+ * the sleep index but here we use the wakeup period since that
+ * is what we need to do for the latency requirements.
+ */
+ static const u8 slp_succ_r0[IWL_POWER_VEC_SIZE] = { 2, 2, 2, 2, 2 };
+ static const u8 slp_succ_r1[IWL_POWER_VEC_SIZE] = { 2, 4, 6, 7, 9 };
+ static const u8 slp_succ_r2[IWL_POWER_VEC_SIZE] = { 2, 7, 9, 9, 0xFF };
+ const u8 *slp_succ = slp_succ_r0;
+ int i;
+
+ if (wakeup_period > IWL_DTIM_RANGE_0_MAX)
+ slp_succ = slp_succ_r1;
+ if (wakeup_period > IWL_DTIM_RANGE_1_MAX)
+ slp_succ = slp_succ_r2;
+
+ memset(cmd, 0, sizeof(*cmd));
+
+ cmd->flags = IWL_POWER_DRIVER_ALLOW_SLEEP_MSK |
+ IWL_POWER_FAST_PD; /* no use seeing frames for others */
+
+ if (priv->power_data.pci_pm)
+ cmd->flags |= IWL_POWER_PCI_PM_MSK;
+
+ cmd->rx_data_timeout = cpu_to_le32(1000 * dynps_ms);
+ cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms);
+
+ for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
+ cmd->sleep_interval[i] =
+ cpu_to_le32(min_t(int, slp_succ[i], wakeup_period));
+
+ IWL_DEBUG_POWER(priv, "Automatic sleep command\n");
+}
+
+static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
+{
+ IWL_DEBUG_POWER(priv, "Sending power/sleep command\n");
IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags);
IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
@@ -200,79 +268,587 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
le32_to_cpu(cmd->sleep_interval[3]),
le32_to_cpu(cmd->sleep_interval[4]));
- return 0;
+ return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD,
+ sizeof(struct iwl_powertable_cmd), cmd);
}
-/*
- * compute the final power mode index
- */
int iwl_power_update_mode(struct iwl_priv *priv, bool force)
{
- struct iwl_power_mgr *setting = &(priv->power_data);
int ret = 0;
- u16 uninitialized_var(final_mode);
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ bool enabled = (priv->iw_mode == NL80211_IFTYPE_STATION) &&
+ (priv->hw->conf.flags & IEEE80211_CONF_PS);
bool update_chains;
+ struct iwl_powertable_cmd cmd;
+ int dtimper;
/* Don't update the RX chain when chain noise calibration is running */
update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
- final_mode = priv->power_data.user_power_setting;
-
- if (setting->power_disabled)
- final_mode = IWL_POWER_MODE_CAM;
+ if (priv->vif)
+ dtimper = priv->vif->bss_conf.dtim_period;
+ else
+ dtimper = 1;
+
+ /* TT power setting overwrites everything */
+ if (tt->state >= IWL_TI_1)
+ iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper);
+ else if (!enabled)
+ iwl_power_sleep_cam_cmd(priv, &cmd);
+ else if (priv->power_data.debug_sleep_level_override >= 0)
+ iwl_static_sleep_cmd(priv, &cmd,
+ priv->power_data.debug_sleep_level_override,
+ dtimper);
+ else if (no_sleep_autoadjust)
+ iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_1, dtimper);
+ else
+ iwl_power_fill_sleep_cmd(priv, &cmd,
+ priv->hw->conf.dynamic_ps_timeout,
+ priv->hw->conf.max_sleep_period);
if (iwl_is_ready_rf(priv) &&
- ((setting->power_mode != final_mode) || force)) {
- struct iwl_powertable_cmd cmd;
-
- if (final_mode != IWL_POWER_MODE_CAM)
+ (memcmp(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)) || force)) {
+ if (cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
set_bit(STATUS_POWER_PMI, &priv->status);
- iwl_update_power_cmd(priv, &cmd, final_mode);
- cmd.keep_alive_beacons = 0;
-
- if (final_mode == IWL_POWER_INDEX_5)
- cmd.flags |= IWL_POWER_FAST_PD;
-
ret = iwl_set_power(priv, &cmd);
-
- if (final_mode == IWL_POWER_MODE_CAM)
- clear_bit(STATUS_POWER_PMI, &priv->status);
-
- if (priv->cfg->ops->lib->update_chain_flags && update_chains)
- priv->cfg->ops->lib->update_chain_flags(priv);
- else
- IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise "
+ if (!ret) {
+ if (!(cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
+ clear_bit(STATUS_POWER_PMI, &priv->status);
+
+ if (priv->cfg->ops->lib->update_chain_flags &&
+ update_chains)
+ priv->cfg->ops->lib->update_chain_flags(priv);
+ else if (priv->cfg->ops->lib->update_chain_flags)
+ IWL_DEBUG_POWER(priv,
+ "Cannot update the power, chain noise "
"calibration running: %d\n",
priv->chain_noise_data.state);
- if (!ret)
- setting->power_mode = final_mode;
+ memcpy(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd));
+ } else
+ IWL_ERR(priv, "set power fail, ret = %d", ret);
}
return ret;
}
EXPORT_SYMBOL(iwl_power_update_mode);
-/* set user_power_setting */
-int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
+bool iwl_ht_enabled(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ struct iwl_tt_restriction *restriction;
+
+ if (!priv->thermal_throttle.advanced_tt)
+ return true;
+ restriction = tt->restriction + tt->state;
+ return restriction->is_ht;
+}
+EXPORT_SYMBOL(iwl_ht_enabled);
+
+enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
{
- if (mode >= IWL_POWER_NUM)
- return -EINVAL;
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ struct iwl_tt_restriction *restriction;
- priv->power_data.user_power_setting = mode;
+ if (!priv->thermal_throttle.advanced_tt)
+ return IWL_ANT_OK_MULTI;
+ restriction = tt->restriction + tt->state;
+ return restriction->tx_stream;
+}
+EXPORT_SYMBOL(iwl_tx_ant_restriction);
+
+enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ struct iwl_tt_restriction *restriction;
+
+ if (!priv->thermal_throttle.advanced_tt)
+ return IWL_ANT_OK_MULTI;
+ restriction = tt->restriction + tt->state;
+ return restriction->rx_stream;
+}
+
+#define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */
+
+/*
+ * toggle the bit to wake up uCode and check the temperature
+ * if the temperature is below CT, uCode will stay awake and send card
+ * state notification with CT_KILL bit clear to inform Thermal Throttling
+ * Management to change state. Otherwise, uCode will go back to sleep
+ * without doing anything, driver should continue the 5 seconds timer
+ * to wake up uCode for temperature check until temperature drop below CT
+ */
+static void iwl_tt_check_exit_ct_kill(unsigned long data)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)data;
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ unsigned long flags;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (tt->state == IWL_TI_CT_KILL) {
+ if (priv->thermal_throttle.ct_kill_toggle) {
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+ priv->thermal_throttle.ct_kill_toggle = false;
+ } else {
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+ priv->thermal_throttle.ct_kill_toggle = true;
+ }
+ iwl_read32(priv, CSR_UCODE_DRV_GP1);
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ if (!iwl_grab_nic_access(priv))
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+
+ /* Reschedule the ct_kill timer to occur in
+ * CT_KILL_EXIT_DURATION seconds to ensure we get a
+ * thermal update */
+ mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies +
+ CT_KILL_EXIT_DURATION * HZ);
+ }
+}
+
+static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
+ bool stop)
+{
+ if (stop) {
+ IWL_DEBUG_POWER(priv, "Stop all queues\n");
+ if (priv->mac80211_registered)
+ ieee80211_stop_queues(priv->hw);
+ IWL_DEBUG_POWER(priv,
+ "Schedule 5 seconds CT_KILL Timer\n");
+ mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies +
+ CT_KILL_EXIT_DURATION * HZ);
+ } else {
+ IWL_DEBUG_POWER(priv, "Wake all queues\n");
+ if (priv->mac80211_registered)
+ ieee80211_wake_queues(priv->hw);
+ }
+}
+
+#define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY)
+#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100)
+#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90)
+
+/*
+ * Legacy thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ * Chip will identify dangerously high temperatures that can
+ * harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ * Throttle early enough to lower the power consumption before
+ * drastic steps are needed
+ */
+static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ enum iwl_tt_state old_state;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if ((tt->tt_previous_temp) &&
+ (temp > tt->tt_previous_temp) &&
+ ((temp - tt->tt_previous_temp) >
+ IWL_TT_INCREASE_MARGIN)) {
+ IWL_DEBUG_POWER(priv,
+ "Temperature increase %d degree Celsius\n",
+ (temp - tt->tt_previous_temp));
+ }
+#endif
+ old_state = tt->state;
+ /* in Celsius */
+ if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
+ tt->state = IWL_TI_CT_KILL;
+ else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
+ tt->state = IWL_TI_2;
+ else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
+ tt->state = IWL_TI_1;
+ else
+ tt->state = IWL_TI_0;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ tt->tt_previous_temp = temp;
+#endif
+ if (tt->state != old_state) {
+ switch (tt->state) {
+ case IWL_TI_0:
+ /*
+ * When the system is ready to go back to IWL_TI_0
+ * we only have to call iwl_power_update_mode() to
+ * do so.
+ */
+ break;
+ case IWL_TI_1:
+ tt->tt_power_mode = IWL_POWER_INDEX_3;
+ break;
+ case IWL_TI_2:
+ tt->tt_power_mode = IWL_POWER_INDEX_4;
+ break;
+ default:
+ tt->tt_power_mode = IWL_POWER_INDEX_5;
+ break;
+ }
+ mutex_lock(&priv->mutex);
+ if (iwl_power_update_mode(priv, true)) {
+ /* TT state not updated
+ * try again during next temperature read
+ */
+ tt->state = old_state;
+ IWL_ERR(priv, "Cannot update power mode, "
+ "TT state not updated\n");
+ } else {
+ if (tt->state == IWL_TI_CT_KILL)
+ iwl_perform_ct_kill_task(priv, true);
+ else if (old_state == IWL_TI_CT_KILL &&
+ tt->state != IWL_TI_CT_KILL)
+ iwl_perform_ct_kill_task(priv, false);
+ IWL_DEBUG_POWER(priv, "Temperature state changed %u\n",
+ tt->state);
+ IWL_DEBUG_POWER(priv, "Power Index change to %u\n",
+ tt->tt_power_mode);
+ }
+ mutex_unlock(&priv->mutex);
+ }
+}
- return iwl_power_update_mode(priv, 0);
+/*
+ * Advance thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ * Chip will identify dangerously high temperatures that can
+ * harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ * Throttle early enough to lower the power consumption before
+ * drastic steps are needed
+ * Actions include relaxing the power down sleep thresholds and
+ * decreasing the number of TX streams
+ * 3) Avoid throughput performance impact as much as possible
+ *
+ *=============================================================================
+ * Condition Nxt State Condition Nxt State Condition Nxt State
+ *-----------------------------------------------------------------------------
+ * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A
+ * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0
+ * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1
+ * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
+ *=============================================================================
+ */
+static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ int i;
+ bool changed = false;
+ enum iwl_tt_state old_state;
+ struct iwl_tt_trans *transaction;
+
+ old_state = tt->state;
+ for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
+ /* based on the current TT state,
+ * find the curresponding transaction table
+ * each table has (IWL_TI_STATE_MAX - 1) entries
+ * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
+ * will advance to the correct table.
+ * then based on the current temperature
+ * find the next state need to transaction to
+ * go through all the possible (IWL_TI_STATE_MAX - 1) entries
+ * in the current table to see if transaction is needed
+ */
+ transaction = tt->transaction +
+ ((old_state * (IWL_TI_STATE_MAX - 1)) + i);
+ if (temp >= transaction->tt_low &&
+ temp <= transaction->tt_high) {
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if ((tt->tt_previous_temp) &&
+ (temp > tt->tt_previous_temp) &&
+ ((temp - tt->tt_previous_temp) >
+ IWL_TT_INCREASE_MARGIN)) {
+ IWL_DEBUG_POWER(priv,
+ "Temperature increase %d "
+ "degree Celsius\n",
+ (temp - tt->tt_previous_temp));
+ }
+ tt->tt_previous_temp = temp;
+#endif
+ if (old_state !=
+ transaction->next_state) {
+ changed = true;
+ tt->state =
+ transaction->next_state;
+ }
+ break;
+ }
+ }
+ if (changed) {
+ struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+
+ if (tt->state >= IWL_TI_1) {
+ /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
+ tt->tt_power_mode = IWL_POWER_INDEX_5;
+ if (!iwl_ht_enabled(priv))
+ /* disable HT */
+ rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
+ RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
+ RXON_FLG_HT40_PROT_MSK |
+ RXON_FLG_HT_PROT_MSK);
+ else {
+ /* check HT capability and set
+ * according to the system HT capability
+ * in case get disabled before */
+ iwl_set_rxon_ht(priv, &priv->current_ht_config);
+ }
+
+ } else {
+ /*
+ * restore system power setting -- it will be
+ * recalculated automatically.
+ */
+
+ /* check HT capability and set
+ * according to the system HT capability
+ * in case get disabled before */
+ iwl_set_rxon_ht(priv, &priv->current_ht_config);
+ }
+ mutex_lock(&priv->mutex);
+ if (iwl_power_update_mode(priv, true)) {
+ /* TT state not updated
+ * try again during next temperature read
+ */
+ IWL_ERR(priv, "Cannot update power mode, "
+ "TT state not updated\n");
+ tt->state = old_state;
+ } else {
+ IWL_DEBUG_POWER(priv,
+ "Thermal Throttling to new state: %u\n",
+ tt->state);
+ if (old_state != IWL_TI_CT_KILL &&
+ tt->state == IWL_TI_CT_KILL) {
+ IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n");
+ iwl_perform_ct_kill_task(priv, true);
+
+ } else if (old_state == IWL_TI_CT_KILL &&
+ tt->state != IWL_TI_CT_KILL) {
+ IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n");
+ iwl_perform_ct_kill_task(priv, false);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+ }
+}
+
+/* Card State Notification indicated reach critical temperature
+ * if PSP not enable, no Thermal Throttling function will be performed
+ * just set the GP1 bit to acknowledge the event
+ * otherwise, go into IWL_TI_CT_KILL state
+ * since Card State Notification will not provide any temperature reading
+ * for Legacy mode
+ * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
+ * for advance mode
+ * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
+ */
+static void iwl_bg_ct_enter(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (!iwl_is_ready(priv))
+ return;
+
+ if (tt->state != IWL_TI_CT_KILL) {
+ IWL_ERR(priv, "Device reached critical temperature "
+ "- ucode going to sleep!\n");
+ if (!priv->thermal_throttle.advanced_tt)
+ iwl_legacy_tt_handler(priv,
+ IWL_MINIMAL_POWER_THRESHOLD);
+ else
+ iwl_advance_tt_handler(priv,
+ CT_KILL_THRESHOLD + 1);
+ }
}
-EXPORT_SYMBOL(iwl_power_set_user_mode);
+
+/* Card State Notification indicated out of critical temperature
+ * since Card State Notification will not provide any temperature reading
+ * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
+ * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
+ */
+static void iwl_bg_ct_exit(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (!iwl_is_ready(priv))
+ return;
+
+ /* stop ct_kill_exit_tm timer */
+ del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
+
+ if (tt->state == IWL_TI_CT_KILL) {
+ IWL_ERR(priv,
+ "Device temperature below critical"
+ "- ucode awake!\n");
+ if (!priv->thermal_throttle.advanced_tt)
+ iwl_legacy_tt_handler(priv,
+ IWL_REDUCED_PERFORMANCE_THRESHOLD_2);
+ else
+ iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD);
+ }
+}
+
+void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
+{
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n");
+ queue_work(priv->workqueue, &priv->ct_enter);
+}
+EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
+
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
+{
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n");
+ queue_work(priv->workqueue, &priv->ct_exit);
+}
+EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
+
+static void iwl_bg_tt_work(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
+ s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
+ temp = KELVIN_TO_CELSIUS(priv->temperature);
+
+ if (!priv->thermal_throttle.advanced_tt)
+ iwl_legacy_tt_handler(priv, temp);
+ else
+ iwl_advance_tt_handler(priv, temp);
+}
+
+void iwl_tt_handler(struct iwl_priv *priv)
+{
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n");
+ queue_work(priv->workqueue, &priv->tt_work);
+}
+EXPORT_SYMBOL(iwl_tt_handler);
+
+/* Thermal throttling initialization
+ * For advance thermal throttling:
+ * Initialize Thermal Index and temperature threshold table
+ * Initialize thermal throttling restriction table
+ */
+void iwl_tt_initialize(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
+ struct iwl_tt_trans *transaction;
+
+ IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n");
+
+ memset(tt, 0, sizeof(struct iwl_tt_mgmt));
+
+ tt->state = IWL_TI_0;
+ init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
+ priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
+ priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill;
+
+ /* setup deferred ct kill work */
+ INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
+ INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
+ INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
+
+ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+ case CSR_HW_REV_TYPE_6x00:
+ case CSR_HW_REV_TYPE_6x50:
+ IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n");
+ tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
+ IWL_TI_STATE_MAX, GFP_KERNEL);
+ tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) *
+ IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1),
+ GFP_KERNEL);
+ if (!tt->restriction || !tt->transaction) {
+ IWL_ERR(priv, "Fallback to Legacy Throttling\n");
+ priv->thermal_throttle.advanced_tt = false;
+ kfree(tt->restriction);
+ tt->restriction = NULL;
+ kfree(tt->transaction);
+ tt->transaction = NULL;
+ } else {
+ transaction = tt->transaction +
+ (IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
+ memcpy(transaction, &tt_range_0[0], size);
+ transaction = tt->transaction +
+ (IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
+ memcpy(transaction, &tt_range_1[0], size);
+ transaction = tt->transaction +
+ (IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
+ memcpy(transaction, &tt_range_2[0], size);
+ transaction = tt->transaction +
+ (IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
+ memcpy(transaction, &tt_range_3[0], size);
+ size = sizeof(struct iwl_tt_restriction) *
+ IWL_TI_STATE_MAX;
+ memcpy(tt->restriction,
+ &restriction_range[0], size);
+ priv->thermal_throttle.advanced_tt = true;
+ }
+ break;
+ default:
+ IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
+ priv->thermal_throttle.advanced_tt = false;
+ break;
+ }
+}
+EXPORT_SYMBOL(iwl_tt_initialize);
+
+/* cleanup thermal throttling management related memory and timer */
+void iwl_tt_exit(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+ /* stop ct_kill_exit_tm timer if activated */
+ del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
+ cancel_work_sync(&priv->tt_work);
+ cancel_work_sync(&priv->ct_enter);
+ cancel_work_sync(&priv->ct_exit);
+
+ if (priv->thermal_throttle.advanced_tt) {
+ /* free advance thermal throttling memory */
+ kfree(tt->restriction);
+ tt->restriction = NULL;
+ kfree(tt->transaction);
+ tt->transaction = NULL;
+ }
+}
+EXPORT_SYMBOL(iwl_tt_exit);
/* initialize to default */
void iwl_power_initialize(struct iwl_priv *priv)
{
- iwl_power_init_handle(priv);
- priv->power_data.user_power_setting = IWL_POWER_INDEX_1;
- /* default to disabled until mac80211 says otherwise */
- priv->power_data.power_disabled = 1;
+ u16 lctl = iwl_pcie_link_ctl(priv);
+
+ priv->power_data.pci_pm = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN);
+
+ priv->power_data.debug_sleep_level_override = -1;
+
+ memset(&priv->power_data.sleep_cmd, 0,
+ sizeof(priv->power_data.sleep_cmd));
}
EXPORT_SYMBOL(iwl_power_initialize);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index 37ba3bb7a25a..df6f6a49712b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -28,13 +28,91 @@
#ifndef __iwl_power_setting_h__
#define __iwl_power_setting_h__
-#include <net/mac80211.h>
#include "iwl-commands.h"
-struct iwl_priv;
+#define IWL_ABSOLUTE_ZERO 0
+#define IWL_ABSOLUTE_MAX 0xFFFFFFFF
+#define IWL_TT_INCREASE_MARGIN 5
-enum {
- IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */
+enum iwl_antenna_ok {
+ IWL_ANT_OK_NONE,
+ IWL_ANT_OK_SINGLE,
+ IWL_ANT_OK_MULTI,
+};
+
+/* Thermal Throttling State Machine states */
+enum iwl_tt_state {
+ IWL_TI_0, /* normal temperature, system power state */
+ IWL_TI_1, /* high temperature detect, low power state */
+ IWL_TI_2, /* higher temperature detected, lower power state */
+ IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
+ IWL_TI_STATE_MAX
+};
+
+/**
+ * struct iwl_tt_restriction - Thermal Throttling restriction table
+ * @tx_stream: number of tx stream allowed
+ * @is_ht: ht enable/disable
+ * @rx_stream: number of rx stream allowed
+ *
+ * This table is used by advance thermal throttling management
+ * based on the current thermal throttling state, and determines
+ * the number of tx/rx streams and the status of HT operation.
+ */
+struct iwl_tt_restriction {
+ enum iwl_antenna_ok tx_stream;
+ enum iwl_antenna_ok rx_stream;
+ bool is_ht;
+};
+
+/**
+ * struct iwl_tt_trans - Thermal Throttling transaction table
+ * @next_state: next thermal throttling mode
+ * @tt_low: low temperature threshold to change state
+ * @tt_high: high temperature threshold to change state
+ *
+ * This is used by the advanced thermal throttling algorithm
+ * to determine the next thermal state to go based on the
+ * current temperature.
+ */
+struct iwl_tt_trans {
+ enum iwl_tt_state next_state;
+ u32 tt_low;
+ u32 tt_high;
+};
+
+/**
+ * struct iwl_tt_mgnt - Thermal Throttling Management structure
+ * @advanced_tt: advanced thermal throttle required
+ * @state: current Thermal Throttling state
+ * @tt_power_mode: Thermal Throttling power mode index
+ * being used to set power level when
+ * when thermal throttling state != IWL_TI_0
+ * the tt_power_mode should set to different
+ * power mode based on the current tt state
+ * @tt_previous_temperature: last measured temperature
+ * @iwl_tt_restriction: ptr to restriction tbl, used by advance
+ * thermal throttling to determine how many tx/rx streams
+ * should be used in tt state; and can HT be enabled or not
+ * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
+ * state transaction
+ * @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature
+ * @ct_kill_exit_tm: timer to exit thermal kill
+ */
+struct iwl_tt_mgmt {
+ enum iwl_tt_state state;
+ bool advanced_tt;
+ u8 tt_power_mode;
+ bool ct_kill_toggle;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ s32 tt_previous_temp;
+#endif
+ struct iwl_tt_restriction *restriction;
+ struct iwl_tt_trans *transaction;
+ struct timer_list ct_kill_exit_tm;
+};
+
+enum iwl_power_level {
IWL_POWER_INDEX_1,
IWL_POWER_INDEX_2,
IWL_POWER_INDEX_3,
@@ -43,26 +121,23 @@ enum {
IWL_POWER_NUM
};
-/* Power management (not Tx power) structures */
-
-struct iwl_power_vec_entry {
- struct iwl_powertable_cmd cmd;
- u8 no_dtim;
-};
-
struct iwl_power_mgr {
- struct iwl_power_vec_entry pwr_range_0[IWL_POWER_NUM];
- struct iwl_power_vec_entry pwr_range_1[IWL_POWER_NUM];
- struct iwl_power_vec_entry pwr_range_2[IWL_POWER_NUM];
- u32 dtim_period;
- /* final power level that used to calculate final power command */
- u8 power_mode;
- u8 user_power_setting; /* set by user through sysfs */
- u8 power_disabled; /* set by mac80211's CONF_PS */
+ struct iwl_powertable_cmd sleep_cmd;
+ int debug_sleep_level_override;
+ bool pci_pm;
};
int iwl_power_update_mode(struct iwl_priv *priv, bool force);
-int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);
+bool iwl_ht_enabled(struct iwl_priv *priv);
+enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv);
+enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv);
+void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
+void iwl_tt_handler(struct iwl_priv *priv);
+void iwl_tt_initialize(struct iwl_priv *priv);
+void iwl_tt_exit(struct iwl_priv *priv);
void iwl_power_initialize(struct iwl_priv *priv);
+extern bool no_sleep_autoadjust;
+
#endif /* __iwl_power_setting_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 3b9cac3fd216..d393e8f02102 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -80,6 +80,8 @@
#define APMG_RFKILL_REG (APMG_BASE + 0x0014)
#define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c)
#define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020)
+#define APMG_DIGITAL_SVR_REG (APMG_BASE + 0x0058)
+#define APMG_ANALOG_SVR_REG (APMG_BASE + 0x006C)
#define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200)
#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800)
@@ -91,7 +93,8 @@
#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000)
#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */
#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000)
-
+#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */
+#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060)
#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 2b8d40b37a1c..8150c5c3a16b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -406,7 +406,6 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
rxq->free_count = 0;
spin_unlock_irqrestore(&rxq->lock, flags);
}
-EXPORT_SYMBOL(iwl_rx_queue_reset);
int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
@@ -540,13 +539,14 @@ void iwl_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
- (int)sizeof(priv->statistics), pkt->len);
+ (int)sizeof(priv->statistics),
+ le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
change = ((priv->statistics.general.temperature !=
pkt->u.stats.general.temperature) ||
((priv->statistics.flag &
- STATISTICS_REPLY_FLG_FAT_MODE_MSK) !=
- (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)));
+ STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
+ (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
@@ -646,7 +646,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
u32 tsf_low;
int rssi;
- if (likely(!(priv->debug_level & IWL_DL_RX)))
+ if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX)))
return;
/* MAC header */
@@ -746,14 +746,6 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
}
#endif
-static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len)
-{
- /* 0 - mgmt, 1 - cnt, 2 - data */
- int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2;
- priv->rx_stats[idx].cnt++;
- priv->rx_stats[idx].bytes += len;
-}
-
/*
* returns non-zero if packet should be dropped
*/
@@ -862,61 +854,12 @@ static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
}
static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
- int include_phy,
- struct iwl_rx_mem_buffer *rxb,
- struct ieee80211_rx_status *stats)
+ struct ieee80211_hdr *hdr,
+ u16 len,
+ u32 ampdu_status,
+ struct iwl_rx_mem_buffer *rxb,
+ struct ieee80211_rx_status *stats)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
- struct iwl_rx_phy_res *rx_start = (include_phy) ?
- (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : NULL;
- struct ieee80211_hdr *hdr;
- u16 len;
- __le32 *rx_end;
- unsigned int skblen;
- u32 ampdu_status;
- u32 ampdu_status_legacy;
-
- if (!include_phy && priv->last_phy_res[0])
- rx_start = (struct iwl_rx_phy_res *)&priv->last_phy_res[1];
-
- if (!rx_start) {
- IWL_ERR(priv, "MPDU frame without a PHY data\n");
- return;
- }
- if (include_phy) {
- hdr = (struct ieee80211_hdr *)((u8 *) &rx_start[1] +
- rx_start->cfg_phy_cnt);
-
- len = le16_to_cpu(rx_start->byte_count);
-
- rx_end = (__le32 *)((u8 *) &pkt->u.raw[0] +
- sizeof(struct iwl_rx_phy_res) +
- rx_start->cfg_phy_cnt + len);
-
- } else {
- struct iwl4965_rx_mpdu_res_start *amsdu =
- (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
-
- hdr = (struct ieee80211_hdr *)(pkt->u.raw +
- sizeof(struct iwl4965_rx_mpdu_res_start));
- len = le16_to_cpu(amsdu->byte_count);
- rx_start->byte_count = amsdu->byte_count;
- rx_end = (__le32 *) (((u8 *) hdr) + len);
- }
-
- ampdu_status = le32_to_cpu(*rx_end);
- skblen = ((u8 *) rx_end - (u8 *) &pkt->u.raw[0]) + sizeof(u32);
-
- if (!include_phy) {
- /* New status scheme, need to translate */
- ampdu_status_legacy = ampdu_status;
- ampdu_status = iwl_translate_rx_status(priv, ampdu_status);
- }
-
- /* start from MAC */
- skb_reserve(rxb->skb, (void *)hdr - (void *)pkt);
- skb_put(rxb->skb, len); /* end where data ends */
-
/* We only process data packets if the interface is open */
if (unlikely(!priv->is_open)) {
IWL_DEBUG_DROP_LIMIT(priv,
@@ -924,15 +867,18 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
return;
}
- hdr = (struct ieee80211_hdr *)rxb->skb->data;
-
- /* in case of HW accelerated crypto and bad decryption, drop */
- if (!priv->hw_params.sw_crypto &&
+ /* In case of HW accelerated crypto and bad decryption, drop */
+ if (!priv->cfg->mod_params->sw_crypto &&
iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
return;
- iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len);
- ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ /* Resize SKB from mac header to end of packet */
+ skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data);
+ skb_put(rxb->skb, len);
+
+ iwl_update_stats(priv, false, hdr->frame_control, len);
+ memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb);
priv->alloc_rxb_skb--;
rxb->skb = NULL;
}
@@ -963,82 +909,80 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
struct ieee80211_hdr *header;
struct ieee80211_rx_status rx_status;
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
- /* Use phy data (Rx signal strength, etc.) contained within
- * this rx packet for legacy frames,
- * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */
- int include_phy = (pkt->hdr.cmd == REPLY_RX);
- struct iwl_rx_phy_res *rx_start = (include_phy) ?
- (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) :
- (struct iwl_rx_phy_res *)&priv->last_phy_res[1];
- __le32 *rx_end;
- unsigned int len = 0;
+ struct iwl_rx_phy_res *phy_res;
+ __le32 rx_pkt_status;
+ struct iwl4965_rx_mpdu_res_start *amsdu;
+ u32 len;
+ u32 ampdu_status;
u16 fc;
- u8 network_packet;
-
- rx_status.mactime = le64_to_cpu(rx_start->timestamp);
- rx_status.freq =
- ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel));
- rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
- IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
- rx_status.rate_idx =
- iwl_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags));
- if (rx_status.band == IEEE80211_BAND_5GHZ)
- rx_status.rate_idx -= IWL_FIRST_OFDM_RATE;
-
- rx_status.flag = 0;
+ u32 rate_n_flags;
- /* TSF isn't reliable. In order to allow smooth user experience,
- * this W/A doesn't propagate it to the mac80211 */
- /*rx_status.flag |= RX_FLAG_TSFT;*/
+ /**
+ * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently.
+ * REPLY_RX: physical layer info is in this buffer
+ * REPLY_RX_MPDU_CMD: physical layer info was sent in separate
+ * command and cached in priv->last_phy_res
+ *
+ * Here we set up local variables depending on which command is
+ * received.
+ */
+ if (pkt->hdr.cmd == REPLY_RX) {
+ phy_res = (struct iwl_rx_phy_res *)pkt->u.raw;
+ header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res)
+ + phy_res->cfg_phy_cnt);
+
+ len = le16_to_cpu(phy_res->byte_count);
+ rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) +
+ phy_res->cfg_phy_cnt + len);
+ ampdu_status = le32_to_cpu(rx_pkt_status);
+ } else {
+ if (!priv->last_phy_res[0]) {
+ IWL_ERR(priv, "MPDU frame without cached PHY data\n");
+ return;
+ }
+ phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1];
+ amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
+ header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu));
+ len = le16_to_cpu(amsdu->byte_count);
+ rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len);
+ ampdu_status = iwl_translate_rx_status(priv,
+ le32_to_cpu(rx_pkt_status));
+ }
- if ((unlikely(rx_start->cfg_phy_cnt > 20))) {
+ if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n",
- rx_start->cfg_phy_cnt);
+ phy_res->cfg_phy_cnt);
return;
}
- if (!include_phy) {
- if (priv->last_phy_res[0])
- rx_start = (struct iwl_rx_phy_res *)
- &priv->last_phy_res[1];
- else
- rx_start = NULL;
- }
-
- if (!rx_start) {
- IWL_ERR(priv, "MPDU frame without a PHY data\n");
+ if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
+ !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
+ IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
+ le32_to_cpu(rx_pkt_status));
return;
}
- if (include_phy) {
- header = (struct ieee80211_hdr *)((u8 *) &rx_start[1]
- + rx_start->cfg_phy_cnt);
-
- len = le16_to_cpu(rx_start->byte_count);
- rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt +
- sizeof(struct iwl_rx_phy_res) + len);
- } else {
- struct iwl4965_rx_mpdu_res_start *amsdu =
- (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
+ /* This will be used in several places later */
+ rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
- header = (void *)(pkt->u.raw +
- sizeof(struct iwl4965_rx_mpdu_res_start));
- len = le16_to_cpu(amsdu->byte_count);
- rx_end = (__le32 *) (pkt->u.raw +
- sizeof(struct iwl4965_rx_mpdu_res_start) + len);
- }
+ /* rx_status carries information about the packet to mac80211 */
+ rx_status.mactime = le64_to_cpu(phy_res->timestamp);
+ rx_status.freq =
+ ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel));
+ rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+ IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+ rx_status.rate_idx =
+ iwl_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
+ rx_status.flag = 0;
- if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) ||
- !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
- IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
- le32_to_cpu(*rx_end));
- return;
- }
+ /* TSF isn't reliable. In order to allow smooth user experience,
+ * this W/A doesn't propagate it to the mac80211 */
+ /*rx_status.flag |= RX_FLAG_TSFT;*/
- priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp);
+ priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
/* Find max signal strength (dBm) among 3 antenna/receiver chains */
- rx_status.signal = iwl_calc_rssi(priv, rx_start);
+ rx_status.signal = iwl_calc_rssi(priv, phy_res);
/* Meaningful noise values are available only from beacon statistics,
* which are gathered only when associated, and indicate noise
@@ -1058,13 +1002,14 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
if (!iwl_is_associated(priv))
priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
- /* Set "1" to report good data frames in groups of 100 */
#ifdef CONFIG_IWLWIFI_DEBUG
- if (unlikely(priv->debug_level & IWL_DL_RX))
- iwl_dbg_report_frame(priv, rx_start, len, header, 1);
+ /* Set "1" to report good data frames in groups of 100 */
+ if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX))
+ iwl_dbg_report_frame(priv, phy_res, len, header, 1);
#endif
+ iwl_dbg_log_rx_data_frame(priv, len, header);
IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n",
- rx_status.signal, rx_status.noise, rx_status.signal,
+ rx_status.signal, rx_status.noise, rx_status.qual,
(unsigned long long)rx_status.mactime);
/*
@@ -1080,18 +1025,26 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
* new 802.11n radiotap field "RX chains" that is defined
* as a bitmask.
*/
- rx_status.antenna = le16_to_cpu(rx_start->phy_flags &
- RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+ rx_status.antenna =
+ le16_to_cpu(phy_res->phy_flags & RX_RES_PHY_FLAGS_ANTENNA_MSK)
+ >> RX_RES_PHY_FLAGS_ANTENNA_POS;
/* set the preamble flag if appropriate */
- if (rx_start->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+ if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
rx_status.flag |= RX_FLAG_SHORTPRE;
- network_packet = iwl_is_network_packet(priv, header);
- if (network_packet) {
+ /* Set up the HT phy flags */
+ if (rate_n_flags & RATE_MCS_HT_MSK)
+ rx_status.flag |= RX_FLAG_HT;
+ if (rate_n_flags & RATE_MCS_HT40_MSK)
+ rx_status.flag |= RX_FLAG_40MHZ;
+ if (rate_n_flags & RATE_MCS_SGI_MSK)
+ rx_status.flag |= RX_FLAG_SHORT_GI;
+
+ if (iwl_is_network_packet(priv, header)) {
priv->last_rx_rssi = rx_status.signal;
priv->last_beacon_time = priv->ucode_beacon_time;
- priv->last_tsf = le64_to_cpu(rx_start->timestamp);
+ priv->last_tsf = le64_to_cpu(phy_res->timestamp);
}
fc = le16_to_cpu(header->frame_control);
@@ -1103,8 +1056,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
header->addr2);
/* fall through */
default:
- iwl_pass_packet_to_mac80211(priv, include_phy, rxb,
- &rx_status);
+ iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
+ rxb, &rx_status);
break;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index e26875dbe859..4f3a108fa990 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -109,13 +109,13 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
}
EXPORT_SYMBOL(iwl_scan_cancel_timeout);
-int iwl_send_scan_abort(struct iwl_priv *priv)
+static int iwl_send_scan_abort(struct iwl_priv *priv)
{
int ret = 0;
struct iwl_rx_packet *res;
struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_ABORT_CMD,
- .meta.flags = CMD_WANT_SKB,
+ .flags = CMD_WANT_SKB,
};
/* If there isn't a scan actively going on in the hardware
@@ -132,7 +132,7 @@ int iwl_send_scan_abort(struct iwl_priv *priv)
return ret;
}
- res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->u.status != CAN_ABORT_STATUS) {
/* The scan abort will return 1 for success or
* 2 for "failure". A failure condition can be
@@ -146,11 +146,10 @@ int iwl_send_scan_abort(struct iwl_priv *priv)
}
priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.meta.u.skb);
+ dev_kfree_skb_any(cmd.reply_skb);
return ret;
}
-EXPORT_SYMBOL(iwl_send_scan_abort);
/* Service response to REPLY_SCAN_CMD (0x80) */
static void iwl_rx_reply_scan(struct iwl_priv *priv,
@@ -322,7 +321,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
u8 is_active, u8 n_probes,
struct iwl_scan_channel *scan_ch)
{
- const struct ieee80211_channel *channels = NULL;
+ struct ieee80211_channel *chan;
const struct ieee80211_supported_band *sband;
const struct iwl_channel_info *ch_info;
u16 passive_dwell = 0;
@@ -334,20 +333,19 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
if (!sband)
return 0;
- channels = sband->channels;
-
active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
passive_dwell = iwl_get_passive_dwell_time(priv, band);
if (passive_dwell <= active_dwell)
passive_dwell = active_dwell + 1;
- for (i = 0, added = 0; i < sband->n_channels; i++) {
- if (channels[i].flags & IEEE80211_CHAN_DISABLED)
+ for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+ chan = priv->scan_request->channels[i];
+
+ if (chan->band != band)
continue;
- channel =
- ieee80211_frequency_to_channel(channels[i].center_freq);
+ channel = ieee80211_frequency_to_channel(chan->center_freq);
scan_ch->channel = cpu_to_le16(channel);
ch_info = iwl_get_channel_info(priv, band, channel);
@@ -358,7 +356,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
}
if (!is_active || is_channel_passive(ch_info) ||
- (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
+ (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
else
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
@@ -405,7 +403,7 @@ void iwl_init_scan_params(struct iwl_priv *priv)
priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
}
-int iwl_scan_initiate(struct iwl_priv *priv)
+static int iwl_scan_initiate(struct iwl_priv *priv)
{
if (!iwl_is_ready_rf(priv)) {
IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n");
@@ -423,10 +421,6 @@ int iwl_scan_initiate(struct iwl_priv *priv)
}
IWL_DEBUG_INFO(priv, "Starting scan...\n");
- if (priv->cfg->sku & IWL_SKU_G)
- priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
- if (priv->cfg->sku & IWL_SKU_A)
- priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
set_bit(STATUS_SCANNING, &priv->status);
priv->scan_start = jiffies;
priv->scan_pass_start = priv->scan_start;
@@ -435,7 +429,6 @@ int iwl_scan_initiate(struct iwl_priv *priv)
return 0;
}
-EXPORT_SYMBOL(iwl_scan_initiate);
#define IWL_DELAY_NEXT_SCAN (HZ*2)
@@ -444,7 +437,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
{
unsigned long flags;
struct iwl_priv *priv = hw->priv;
- int ret;
+ int ret, i;
IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -478,6 +471,10 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
goto out_unlock;
}
+ priv->scan_bands = 0;
+ for (i = 0; i < req->n_channels; i++)
+ priv->scan_bands |= BIT(req->channels[i]->band);
+
priv->scan_request = req;
ret = iwl_scan_initiate(priv);
@@ -570,7 +567,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_CMD,
.len = sizeof(struct iwl_scan_cmd),
- .meta.flags = CMD_SIZE_HUGE,
+ .flags = CMD_SIZE_HUGE,
};
struct iwl_scan_cmd *scan;
struct ieee80211_conf *conf = NULL;
@@ -799,7 +796,8 @@ void iwl_bg_abort_scan(struct work_struct *work)
{
struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
- if (!iwl_is_ready(priv))
+ if (!test_bit(STATUS_READY, &priv->status) ||
+ !test_bit(STATUS_GEO_CONFIGURED, &priv->status))
return;
mutex_lock(&priv->mutex);
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index ffd5c61a7553..a2b9ec82b965 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -97,8 +97,9 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
spin_unlock_irqrestore(&priv->sta_lock, flags);
}
-static int iwl_add_sta_callback(struct iwl_priv *priv,
- struct iwl_cmd *cmd, struct sk_buff *skb)
+static void iwl_add_sta_callback(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb)
{
struct iwl_rx_packet *res = NULL;
struct iwl_addsta_cmd *addsta =
@@ -107,14 +108,14 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
if (!skb) {
IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n");
- return 1;
+ return;
}
res = (struct iwl_rx_packet *)skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
res->hdr.flags);
- return 1;
+ return;
}
switch (res->u.add_sta.status) {
@@ -126,9 +127,6 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
res->u.add_sta.status);
break;
}
-
- /* We didn't cache the SKB; let the caller free it */
- return 1;
}
int iwl_send_add_sta(struct iwl_priv *priv,
@@ -139,14 +137,14 @@ int iwl_send_add_sta(struct iwl_priv *priv,
u8 data[sizeof(*sta)];
struct iwl_host_cmd cmd = {
.id = REPLY_ADD_STA,
- .meta.flags = flags,
+ .flags = flags,
.data = data,
};
if (flags & CMD_ASYNC)
- cmd.meta.u.callback = iwl_add_sta_callback;
+ cmd.callback = iwl_add_sta_callback;
else
- cmd.meta.flags |= CMD_WANT_SKB;
+ cmd.flags |= CMD_WANT_SKB;
cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
ret = iwl_send_cmd(priv, &cmd);
@@ -154,7 +152,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
if (ret || (flags & CMD_ASYNC))
return ret;
- res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
res->hdr.flags);
@@ -175,7 +173,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
}
priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.meta.u.skb);
+ dev_kfree_skb_any(cmd.reply_skb);
return ret;
}
@@ -216,10 +214,10 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
sta_flags |= cpu_to_le32(
(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
- if (iwl_is_fat_tx_allowed(priv, sta_ht_inf))
- sta_flags |= STA_FLG_FAT_EN_MSK;
+ if (iwl_is_ht40_tx_allowed(priv, sta_ht_inf))
+ sta_flags |= STA_FLG_HT40_EN_MSK;
else
- sta_flags &= ~STA_FLG_FAT_EN_MSK;
+ sta_flags &= ~STA_FLG_HT40_EN_MSK;
priv->stations[index].sta.station_flags = sta_flags;
done:
@@ -324,8 +322,9 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
spin_unlock_irqrestore(&priv->sta_lock, flags);
}
-static int iwl_remove_sta_callback(struct iwl_priv *priv,
- struct iwl_cmd *cmd, struct sk_buff *skb)
+static void iwl_remove_sta_callback(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb)
{
struct iwl_rx_packet *res = NULL;
struct iwl_rem_sta_cmd *rm_sta =
@@ -334,14 +333,14 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv,
if (!skb) {
IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n");
- return 1;
+ return;
}
res = (struct iwl_rx_packet *)skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
res->hdr.flags);
- return 1;
+ return;
}
switch (res->u.rem_sta.status) {
@@ -352,9 +351,6 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv,
IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
break;
}
-
- /* We didn't cache the SKB; let the caller free it */
- return 1;
}
static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
@@ -368,7 +364,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
struct iwl_host_cmd cmd = {
.id = REPLY_REMOVE_STA,
.len = sizeof(struct iwl_rem_sta_cmd),
- .meta.flags = flags,
+ .flags = flags,
.data = &rm_sta_cmd,
};
@@ -377,15 +373,15 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN);
if (flags & CMD_ASYNC)
- cmd.meta.u.callback = iwl_remove_sta_callback;
+ cmd.callback = iwl_remove_sta_callback;
else
- cmd.meta.flags |= CMD_WANT_SKB;
+ cmd.flags |= CMD_WANT_SKB;
ret = iwl_send_cmd(priv, &cmd);
if (ret || (flags & CMD_ASYNC))
return ret;
- res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
res->hdr.flags);
@@ -406,7 +402,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
}
priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.meta.u.skb);
+ dev_kfree_skb_any(cmd.reply_skb);
return ret;
}
@@ -468,7 +464,6 @@ out:
spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret;
}
-EXPORT_SYMBOL(iwl_remove_station);
/**
* iwl_clear_stations_table - Clear the driver's station table
@@ -525,7 +520,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
struct iwl_host_cmd cmd = {
.id = REPLY_WEPKEY,
.data = wep_cmd,
- .meta.flags = CMD_ASYNC,
+ .flags = CMD_SYNC,
};
memset(wep_cmd, 0, cmd_size +
@@ -930,7 +925,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
struct iwl_host_cmd cmd = {
.id = REPLY_TX_LINK_QUALITY_CMD,
.len = sizeof(struct iwl_link_quality_cmd),
- .meta.flags = flags,
+ .flags = flags,
.data = lq,
};
@@ -1056,11 +1051,10 @@ EXPORT_SYMBOL(iwl_rxon_add_station);
int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
{
int sta_id;
- u16 fc = le16_to_cpu(hdr->frame_control);
+ __le16 fc = hdr->frame_control;
/* If this frame is broadcast or management, use broadcast station id */
- if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
- is_multicast_ether_addr(hdr->addr1))
+ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
return priv->hw_params.bcast_sta_id;
switch (priv->iw_mode) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 2e89040e63be..a7422e52d883 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -141,7 +141,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
priv->cfg->ops->lib->txq_free_tfd(priv, txq);
- len = sizeof(struct iwl_cmd) * q->n_window;
+ len = sizeof(struct iwl_device_cmd) * q->n_window;
/* De-alloc array of command/tx buffers */
for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
@@ -156,6 +156,12 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
kfree(txq->txb);
txq->txb = NULL;
+ /* deallocate arrays */
+ kfree(txq->cmd);
+ kfree(txq->meta);
+ txq->cmd = NULL;
+ txq->meta = NULL;
+
/* 0-fill queue descriptor structure */
memset(txq, 0, sizeof(*txq));
}
@@ -179,7 +185,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
if (q->n_bd == 0)
return;
- len = sizeof(struct iwl_cmd) * q->n_window;
+ len = sizeof(struct iwl_device_cmd) * q->n_window;
len += IWL_MAX_SCAN_SIZE;
/* De-alloc array of command/tx buffers */
@@ -318,6 +324,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
{
int i, len;
int ret;
+ int actual_slots = slots_num;
/*
* Alloc buffer array for commands (Tx or other types of commands).
@@ -327,14 +334,22 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
* For normal Tx queues (all other queues), no super-size command
* space is needed.
*/
- len = sizeof(struct iwl_cmd);
- for (i = 0; i <= slots_num; i++) {
- if (i == slots_num) {
- if (txq_id == IWL_CMD_QUEUE_NUM)
- len += IWL_MAX_SCAN_SIZE;
- else
- continue;
- }
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ actual_slots++;
+
+ txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots,
+ GFP_KERNEL);
+ txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * actual_slots,
+ GFP_KERNEL);
+
+ if (!txq->meta || !txq->cmd)
+ goto out_free_arrays;
+
+ len = sizeof(struct iwl_device_cmd);
+ for (i = 0; i < actual_slots; i++) {
+ /* only happens for cmd queue */
+ if (i == slots_num)
+ len += IWL_MAX_SCAN_SIZE;
txq->cmd[i] = kmalloc(len, GFP_KERNEL);
if (!txq->cmd[i])
@@ -348,6 +363,10 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
txq->need_update = 0;
+ /* aggregation TX queues will get their ID when aggregation begins */
+ if (txq_id <= IWL_TX_FIFO_AC3)
+ txq->swq_id = txq_id;
+
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
* iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
@@ -360,15 +379,12 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
return 0;
err:
- for (i = 0; i < slots_num; i++) {
+ for (i = 0; i < actual_slots; i++)
kfree(txq->cmd[i]);
- txq->cmd[i] = NULL;
- }
+out_free_arrays:
+ kfree(txq->meta);
+ kfree(txq->cmd);
- if (txq_id == IWL_CMD_QUEUE_NUM) {
- kfree(txq->cmd[slots_num]);
- txq->cmd[slots_num] = NULL;
- }
return -ENOMEM;
}
EXPORT_SYMBOL(iwl_tx_queue_init);
@@ -550,62 +566,81 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
static void iwl_tx_cmd_build_rate(struct iwl_priv *priv,
struct iwl_tx_cmd *tx_cmd,
struct ieee80211_tx_info *info,
- __le16 fc, int sta_id,
- int is_hcca)
+ __le16 fc, int is_hcca)
{
- u32 rate_flags = 0;
+ u32 rate_flags;
int rate_idx;
- u8 rts_retry_limit = 0;
- u8 data_retry_limit = 0;
+ u8 rts_retry_limit;
+ u8 data_retry_limit;
u8 rate_plcp;
- rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff,
- IWL_RATE_COUNT - 1);
-
- rate_plcp = iwl_rates[rate_idx].plcp;
-
- rts_retry_limit = (is_hcca) ?
- RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT;
-
- if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
- rate_flags |= RATE_MCS_CCK_MSK;
-
-
- if (ieee80211_is_probe_resp(fc)) {
- data_retry_limit = 3;
- if (data_retry_limit < rts_retry_limit)
- rts_retry_limit = data_retry_limit;
- } else
- data_retry_limit = IWL_DEFAULT_TX_RETRY;
-
+ /* Set retry limit on DATA packets and Probe Responses*/
if (priv->data_retry_limit != -1)
data_retry_limit = priv->data_retry_limit;
+ else if (ieee80211_is_probe_resp(fc))
+ data_retry_limit = 3;
+ else
+ data_retry_limit = IWL_DEFAULT_TX_RETRY;
+ tx_cmd->data_retry_limit = data_retry_limit;
+ /* Set retry limit on RTS packets */
+ rts_retry_limit = (is_hcca) ? RTS_HCCA_RETRY_LIMIT :
+ RTS_DFAULT_RETRY_LIMIT;
+ if (data_retry_limit < rts_retry_limit)
+ rts_retry_limit = data_retry_limit;
+ tx_cmd->rts_retry_limit = rts_retry_limit;
+ /* DATA packets will use the uCode station table for rate/antenna
+ * selection */
if (ieee80211_is_data(fc)) {
tx_cmd->initial_rate_index = 0;
tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
- } else {
- switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
- case cpu_to_le16(IEEE80211_STYPE_AUTH):
- case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
- case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
- case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
- if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) {
- tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
- tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK;
- }
- break;
- default:
- break;
- }
+ return;
+ }
- priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
- rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
+ /**
+ * If the current TX rate stored in mac80211 has the MCS bit set, it's
+ * not really a TX rate. Thus, we use the lowest supported rate for
+ * this band. Also use the lowest supported rate if the stored rate
+ * index is invalid.
+ */
+ rate_idx = info->control.rates[0].idx;
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS ||
+ (rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY))
+ rate_idx = rate_lowest_index(&priv->bands[info->band],
+ info->control.sta);
+ /* For 5 GHZ band, remap mac80211 rate indices into driver indices */
+ if (info->band == IEEE80211_BAND_5GHZ)
+ rate_idx += IWL_FIRST_OFDM_RATE;
+ /* Get PLCP rate for tx_cmd->rate_n_flags */
+ rate_plcp = iwl_rates[rate_idx].plcp;
+ /* Zero out flags for this packet */
+ rate_flags = 0;
+
+ /* Set CCK flag as needed */
+ if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
+ rate_flags |= RATE_MCS_CCK_MSK;
+
+ /* Set up RTS and CTS flags for certain packets */
+ switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+ case cpu_to_le16(IEEE80211_STYPE_AUTH):
+ case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+ case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
+ case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
+ if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) {
+ tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+ break;
+ default:
+ break;
}
- tx_cmd->rts_retry_limit = rts_retry_limit;
- tx_cmd->data_retry_limit = data_retry_limit;
+ /* Set up antennas */
+ priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+ rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
+
+ /* Set the rate in the TX cmd */
tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags);
}
@@ -652,14 +687,6 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
}
}
-static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len)
-{
- /* 0 - mgmt, 1 - cnt, 2 - data */
- int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2;
- priv->tx_stats[idx].cnt++;
- priv->tx_stats[idx].bytes += len;
-}
-
/*
* start REPLY_TX command process
*/
@@ -669,7 +696,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_tx_queue *txq;
struct iwl_queue *q;
- struct iwl_cmd *out_cmd;
+ struct iwl_device_cmd *out_cmd;
+ struct iwl_cmd_meta *out_meta;
struct iwl_tx_cmd *tx_cmd;
int swq_id, txq_id;
dma_addr_t phys_addr;
@@ -692,12 +720,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
goto drop_unlock;
}
- if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) ==
- IWL_INVALID_RATE) {
- IWL_ERR(priv, "ERROR: No TX rate available.\n");
- goto drop_unlock;
- }
-
fc = hdr->frame_control;
#ifdef CONFIG_IWLWIFI_DEBUG
@@ -709,10 +731,9 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
#endif
- /* drop all data frame if we are not associated */
+ /* drop all non-injected data frame if we are not associated */
if (ieee80211_is_data(fc) &&
- (!iwl_is_monitor_mode(priv) ||
- !(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */
+ !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
(!iwl_is_associated(priv) ||
((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id) ||
!priv->assoc_station_added)) {
@@ -723,7 +744,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr_len = ieee80211_hdrlen(fc);
/* Find (or create) index into station table for destination station */
- sta_id = iwl_get_sta_id(priv, hdr);
+ if (info->flags & IEEE80211_TX_CTL_INJECTED)
+ sta_id = priv->hw_params.bcast_sta_id;
+ else
+ sta_id = iwl_get_sta_id(priv, hdr);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
@@ -732,11 +756,12 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
- swq_id = skb_get_queue_mapping(skb);
- txq_id = swq_id;
+ txq_id = skb_get_queue_mapping(skb);
if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+ if (unlikely(tid >= MAX_TID_COUNT))
+ goto drop_unlock;
seq_number = priv->stations[sta_id].tid[tid].seq_number;
seq_number &= IEEE80211_SCTL_SEQ;
hdr->seq_ctrl = hdr->seq_ctrl &
@@ -744,15 +769,13 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr->seq_ctrl |= cpu_to_le16(seq_number);
seq_number += 0x10;
/* aggregation is on for this <sta,tid> */
- if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
- swq_id = iwl_virtual_agg_queue_num(swq_id, txq_id);
- }
}
txq = &priv->txq[txq_id];
+ swq_id = txq->swq_id;
q = &txq->q;
- txq->swq_id = swq_id;
if (unlikely(iwl_queue_space(q) < q->high_mark))
goto drop_unlock;
@@ -766,6 +789,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Set up first empty entry in queue's array of Tx/cmd buffers */
out_cmd = txq->cmd[q->write_ptr];
+ out_meta = &txq->meta[q->write_ptr];
tx_cmd = &out_cmd->cmd.tx;
memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
@@ -793,12 +817,12 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* TODO need this for burst mode later on */
iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
+ iwl_dbg_log_tx_data_frame(priv, len, hdr);
/* set is_hcca to 0; it probably will never be implemented */
- iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0);
-
- iwl_update_tx_stats(priv, le16_to_cpu(fc), len);
+ iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, 0);
+ iwl_update_stats(priv, true, fc, len);
/*
* Use the first empty entry in this queue's command buffer array
* to contain the Tx command and MAC header concatenated together
@@ -828,8 +852,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
txcmd_phys = pci_map_single(priv->pci_dev,
&out_cmd->hdr, len,
PCI_DMA_BIDIRECTIONAL);
- pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
- pci_unmap_len_set(&out_cmd->meta, len, len);
+ pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
+ pci_unmap_len_set(out_meta, len, len);
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
@@ -922,7 +946,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{
struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
struct iwl_queue *q = &txq->q;
- struct iwl_cmd *out_cmd;
+ struct iwl_device_cmd *out_cmd;
+ struct iwl_cmd_meta *out_meta;
dma_addr_t phys_addr;
unsigned long flags;
int len, ret;
@@ -936,25 +961,32 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
* the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
* we will need to increase the size of the TFD entries */
BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
- !(cmd->meta.flags & CMD_SIZE_HUGE));
+ !(cmd->flags & CMD_SIZE_HUGE));
if (iwl_is_rfkill(priv)) {
- IWL_DEBUG_INFO(priv, "Not sending command - RF KILL");
+ IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n");
return -EIO;
}
- if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+ if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
IWL_ERR(priv, "No space for Tx\n");
return -ENOSPC;
}
spin_lock_irqsave(&priv->hcmd_lock, flags);
- idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
+ idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
out_cmd = txq->cmd[idx];
+ out_meta = &txq->meta[idx];
+
+ memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */
+ out_meta->flags = cmd->flags;
+ if (cmd->flags & CMD_WANT_SKB)
+ out_meta->source = cmd;
+ if (cmd->flags & CMD_ASYNC)
+ out_meta->callback = cmd->callback;
out_cmd->hdr.cmd = cmd->id;
- memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
/* At this point, the out_cmd now has all of the incoming cmd
@@ -963,9 +995,9 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
out_cmd->hdr.flags = 0;
out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
INDEX_TO_SEQ(q->write_ptr));
- if (out_cmd->meta.flags & CMD_SIZE_HUGE)
+ if (cmd->flags & CMD_SIZE_HUGE)
out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
- len = sizeof(struct iwl_cmd) - sizeof(struct iwl_cmd_meta);
+ len = sizeof(struct iwl_device_cmd);
len += (idx == TFD_CMD_SLOTS) ? IWL_MAX_SCAN_SIZE : 0;
@@ -997,8 +1029,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
fix_size, PCI_DMA_BIDIRECTIONAL);
- pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr);
- pci_unmap_len_set(&out_cmd->meta, len, fix_size);
+ pci_unmap_addr_set(out_meta, mapping, phys_addr);
+ pci_unmap_len_set(out_meta, len, fix_size);
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
phys_addr, fix_size, 1,
@@ -1067,8 +1099,8 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
}
pci_unmap_single(priv->pci_dev,
- pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping),
- pci_unmap_len(&txq->cmd[cmd_idx]->meta, len),
+ pci_unmap_addr(&txq->meta[cmd_idx], mapping),
+ pci_unmap_len(&txq->meta[cmd_idx], len),
PCI_DMA_BIDIRECTIONAL);
for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx;
@@ -1099,7 +1131,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
int index = SEQ_TO_INDEX(sequence);
int cmd_index;
bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
- struct iwl_cmd *cmd;
+ struct iwl_device_cmd *cmd;
+ struct iwl_cmd_meta *meta;
/* If a Tx command is being handled and it isn't in the actual
* command queue then there a command routing bug has been introduced
@@ -1109,24 +1142,24 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
txq_id, sequence,
priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr,
priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) {
- iwl_print_hex_dump(priv, IWL_DL_INFO , rxb, 32);
+ iwl_print_hex_error(priv, pkt, 32);
return;
}
cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+ meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index];
/* Input error checking is done when commands are added to queue. */
- if (cmd->meta.flags & CMD_WANT_SKB) {
- cmd->meta.source->u.skb = rxb->skb;
- rxb->skb = NULL;
- } else if (cmd->meta.u.callback &&
- !cmd->meta.u.callback(priv, cmd, rxb->skb))
+ if (meta->flags & CMD_WANT_SKB) {
+ meta->source->reply_skb = rxb->skb;
rxb->skb = NULL;
+ } else if (meta->callback)
+ meta->callback(priv, cmd, rxb->skb);
iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
- if (!(cmd->meta.flags & CMD_ASYNC)) {
+ if (!(meta->flags & CMD_ASYNC)) {
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
}
@@ -1189,6 +1222,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
tid_data = &priv->stations[sta_id].tid[tid];
*ssn = SEQ_TO_SN(tid_data->seq_number);
tid_data->agg.txq_id = txq_id;
+ priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(tx_fifo, txq_id);
spin_unlock_irqrestore(&priv->sta_lock, flags);
ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
@@ -1221,6 +1255,9 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
return -EINVAL;
}
+ if (unlikely(tid >= MAX_TID_COUNT))
+ return -EINVAL;
+
if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
tx_fifo_id = default_tid_to_tx_fifo[tid];
else
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 523843369ca2..2238c9f2018c 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -89,7 +89,7 @@ MODULE_LICENSE("GPL");
/* module parameters */
struct iwl_mod_params iwl3945_mod_params = {
- .num_of_queues = IWL39_MAX_NUM_QUEUES,
+ .num_of_queues = IWL39_NUM_QUEUES, /* Not used */
.sw_crypto = 1,
.restart_fw = 1,
/* the rest are 0 by default */
@@ -361,79 +361,9 @@ static void iwl3945_unset_hw_params(struct iwl_priv *priv)
priv->shared_phys);
}
-#define MAX_UCODE_BEACON_INTERVAL 1024
-#define INTEL_CONN_LISTEN_INTERVAL cpu_to_le16(0xA)
-
-static __le16 iwl3945_adjust_beacon_interval(u16 beacon_val)
-{
- u16 new_val = 0;
- u16 beacon_factor = 0;
-
- beacon_factor =
- (beacon_val + MAX_UCODE_BEACON_INTERVAL)
- / MAX_UCODE_BEACON_INTERVAL;
- new_val = beacon_val / beacon_factor;
-
- return cpu_to_le16(new_val);
-}
-
-static void iwl3945_setup_rxon_timing(struct iwl_priv *priv)
-{
- u64 interval_tm_unit;
- u64 tsf, result;
- unsigned long flags;
- struct ieee80211_conf *conf = NULL;
- u16 beacon_int = 0;
-
- conf = ieee80211_get_hw_conf(priv->hw);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
- priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
-
- tsf = priv->timestamp;
-
- beacon_int = priv->beacon_int;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (priv->iw_mode == NL80211_IFTYPE_STATION) {
- if (beacon_int == 0) {
- priv->rxon_timing.beacon_interval = cpu_to_le16(100);
- priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
- } else {
- priv->rxon_timing.beacon_interval =
- cpu_to_le16(beacon_int);
- priv->rxon_timing.beacon_interval =
- iwl3945_adjust_beacon_interval(
- le16_to_cpu(priv->rxon_timing.beacon_interval));
- }
-
- priv->rxon_timing.atim_window = 0;
- } else {
- priv->rxon_timing.beacon_interval =
- iwl3945_adjust_beacon_interval(
- priv->vif->bss_conf.beacon_int);
- /* TODO: we need to get atim_window from upper stack
- * for now we set to 0 */
- priv->rxon_timing.atim_window = 0;
- }
-
- interval_tm_unit =
- (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
- result = do_div(tsf, interval_tm_unit);
- priv->rxon_timing.beacon_init_val =
- cpu_to_le32((u32) ((u64) interval_tm_unit - result));
-
- IWL_DEBUG_ASSOC(priv,
- "beacon interval %d beacon timer %d beacon tim %d\n",
- le16_to_cpu(priv->rxon_timing.beacon_interval),
- le32_to_cpu(priv->rxon_timing.beacon_init_val),
- le16_to_cpu(priv->rxon_timing.atim_window));
-}
-
static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
struct ieee80211_tx_info *info,
- struct iwl_cmd *cmd,
+ struct iwl_device_cmd *cmd,
struct sk_buff *skb_frag,
int sta_id)
{
@@ -473,7 +403,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
* handle build REPLY_TX command notification.
*/
static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
- struct iwl_cmd *cmd,
+ struct iwl_device_cmd *cmd,
struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr, u8 std_id)
{
@@ -546,7 +476,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
struct iwl3945_tx_cmd *tx;
struct iwl_tx_queue *txq = NULL;
struct iwl_queue *q = NULL;
- struct iwl_cmd *out_cmd = NULL;
+ struct iwl_device_cmd *out_cmd;
+ struct iwl_cmd_meta *out_meta;
dma_addr_t phys_addr;
dma_addr_t txcmd_phys;
int txq_id = skb_get_queue_mapping(skb);
@@ -587,9 +518,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
#endif
- /* drop all data frame if we are not associated */
+ /* drop all non-injected data frame if we are not associated */
if (ieee80211_is_data(fc) &&
- (!iwl_is_monitor_mode(priv)) && /* packet injection */
+ !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
(!iwl_is_associated(priv) ||
((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) {
IWL_DEBUG_DROP(priv, "Dropping - !iwl_is_associated\n");
@@ -601,7 +532,10 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr_len = ieee80211_hdrlen(fc);
/* Find (or create) index into station table for destination station */
- sta_id = iwl_get_sta_id(priv, hdr);
+ if (info->flags & IEEE80211_TX_CTL_INJECTED)
+ sta_id = priv->hw_params.bcast_sta_id;
+ else
+ sta_id = iwl_get_sta_id(priv, hdr);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
@@ -613,6 +547,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+ if (unlikely(tid >= MAX_TID_COUNT))
+ goto drop;
seq_number = priv->stations[sta_id].tid[tid].seq_number &
IEEE80211_SCTL_SEQ;
hdr->seq_ctrl = cpu_to_le16(seq_number) |
@@ -635,6 +571,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Init first empty entry in queue's array of Tx/cmd buffers */
out_cmd = txq->cmd[idx];
+ out_meta = &txq->meta[idx];
tx = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload;
memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
memset(tx, 0, sizeof(*tx));
@@ -666,7 +603,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
len = (u16)skb->len;
tx->len = cpu_to_le16(len);
-
+ iwl_dbg_log_tx_data_frame(priv, len, hdr);
+ iwl_update_stats(priv, true, fc, len);
tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
@@ -712,8 +650,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
len, PCI_DMA_TODEVICE);
/* we do not map meta data ... so we can safely access address to
* provide to unmap command*/
- pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
- pci_unmap_len_set(&out_cmd->meta, len, len);
+ pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
+ pci_unmap_len_set(out_meta, len, len);
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
@@ -823,7 +761,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
struct iwl_host_cmd cmd = {
.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
.data = (void *)&spectrum,
- .meta.flags = CMD_WANT_SKB,
+ .flags = CMD_WANT_SKB,
};
u32 add_time = le64_to_cpu(params->start_time);
int rc;
@@ -864,7 +802,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
if (rc)
return rc;
- res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n");
rc = -EIO;
@@ -887,7 +825,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
break;
}
- dev_kfree_skb_any(cmd.meta.u.skb);
+ dev_kfree_skb_any(cmd.reply_skb);
return rc;
}
@@ -996,7 +934,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status;
- IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
+ IWL_WARN(priv, "Card state received: HW:%s SW:%s\n",
(flags & HW_CARD_DISABLED) ? "Kill" : "On",
(flags & SW_CARD_DISABLED) ? "Kill" : "On");
@@ -1435,7 +1373,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
fill_rx = 1;
/* Rx interrupt, but nothing sent from uCode */
if (i == r)
- IWL_DEBUG(priv, IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
+ IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i);
while (i != r) {
rxb = rxq->queue[i];
@@ -1466,15 +1404,13 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
* handle those that need handling via function in
* rx_handlers table. See iwl3945_setup_rx_handlers() */
if (priv->rx_handlers[pkt->hdr.cmd]) {
- IWL_DEBUG(priv, IWL_DL_HCMD | IWL_DL_RX | IWL_DL_ISR,
- "r = %d, i = %d, %s, 0x%02x\n", r, i,
+ IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i,
get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
} else {
/* No handling needed */
- IWL_DEBUG(priv, IWL_DL_HCMD | IWL_DL_RX | IWL_DL_ISR,
- "r %d i %d No handler needed for %s, 0x%02x\n",
+ IWL_DEBUG_RX(priv, "r %d i %d No handler needed for %s, 0x%02x\n",
r, i, get_cmd_string(pkt->hdr.cmd),
pkt->hdr.cmd);
}
@@ -1714,7 +1650,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_ISR) {
+ if (iwl_get_debug_level(priv) & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@@ -1733,7 +1669,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
+ IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
@@ -1749,7 +1685,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1828,7 +1764,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
iwl_enable_interrupts(priv);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
inta = iwl_read32(priv, CSR_INT);
inta_mask = iwl_read32(priv, CSR_INT_MASK);
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@@ -1844,7 +1780,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
u8 is_active, u8 n_probes,
struct iwl3945_scan_channel *scan_ch)
{
- const struct ieee80211_channel *channels = NULL;
+ struct ieee80211_channel *chan;
const struct ieee80211_supported_band *sband;
const struct iwl_channel_info *ch_info;
u16 passive_dwell = 0;
@@ -1855,19 +1791,19 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
if (!sband)
return 0;
- channels = sband->channels;
-
active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
passive_dwell = iwl_get_passive_dwell_time(priv, band);
if (passive_dwell <= active_dwell)
passive_dwell = active_dwell + 1;
- for (i = 0, added = 0; i < sband->n_channels; i++) {
- if (channels[i].flags & IEEE80211_CHAN_DISABLED)
+ for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+ chan = priv->scan_request->channels[i];
+
+ if (chan->band != band)
continue;
- scan_ch->channel = channels[i].hw_value;
+ scan_ch->channel = chan->hw_value;
ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
if (!is_channel_valid(ch_info)) {
@@ -1882,7 +1818,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
* and use long active_dwell time.
*/
if (!is_active || is_channel_passive(ch_info) ||
- (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
+ (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
scan_ch->type = 0; /* passive */
if (IWL_UCODE_API(priv->ucode_ver) == 1)
scan_ch->active_dwell = cpu_to_le16(passive_dwell - 1);
@@ -2111,7 +2047,7 @@ static void iwl3945_nic_start(struct iwl_priv *priv)
*/
static int iwl3945_read_ucode(struct iwl_priv *priv)
{
- struct iwl_ucode *ucode;
+ const struct iwl_ucode_header *ucode;
int ret = -EINVAL, index;
const struct firmware *ucode_raw;
/* firmware file name contains uCode/driver compatibility version */
@@ -2152,22 +2088,24 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
goto error;
/* Make sure that we got at least our header! */
- if (ucode_raw->size < sizeof(*ucode)) {
+ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n");
ret = -EINVAL;
goto err_release;
}
/* Data from ucode file: header followed by uCode images */
- ucode = (void *)ucode_raw->data;
+ ucode = (struct iwl_ucode_header *)ucode_raw->data;
priv->ucode_ver = le32_to_cpu(ucode->ver);
api_ver = IWL_UCODE_API(priv->ucode_ver);
- inst_size = le32_to_cpu(ucode->inst_size);
- data_size = le32_to_cpu(ucode->data_size);
- init_size = le32_to_cpu(ucode->init_size);
- init_data_size = le32_to_cpu(ucode->init_data_size);
- boot_size = le32_to_cpu(ucode->boot_size);
+ inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
+ data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
+ init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
+ init_data_size =
+ priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
+ boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
+ src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
/* api_ver should match the api version forming part of the
* firmware filename ... but we don't check for that and only rely
@@ -2208,12 +2146,13 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
/* Verify size of file vs. image size info in file's header */
- if (ucode_raw->size < sizeof(*ucode) +
+ if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) +
inst_size + data_size + init_size +
init_data_size + boot_size) {
- IWL_DEBUG_INFO(priv, "uCode file size %zd too small\n",
- ucode_raw->size);
+ IWL_DEBUG_INFO(priv,
+ "uCode file size %zd does not match expected size\n",
+ ucode_raw->size);
ret = -EINVAL;
goto err_release;
}
@@ -2296,44 +2235,44 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
- src = &ucode->data[0];
- len = priv->ucode_code.len;
+ len = inst_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) uCode instr len %zd\n", len);
memcpy(priv->ucode_code.v_addr, src, len);
+ src += len;
+
IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
/* Runtime data (2nd block)
* NOTE: Copy into backup buffer will be done in iwl3945_up() */
- src = &ucode->data[inst_size];
- len = priv->ucode_data.len;
+ len = data_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) uCode data len %zd\n", len);
memcpy(priv->ucode_data.v_addr, src, len);
memcpy(priv->ucode_data_backup.v_addr, src, len);
+ src += len;
/* Initialization instructions (3rd block) */
if (init_size) {
- src = &ucode->data[inst_size + data_size];
- len = priv->ucode_init.len;
+ len = init_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) init instr len %zd\n", len);
memcpy(priv->ucode_init.v_addr, src, len);
+ src += len;
}
/* Initialization data (4th block) */
if (init_data_size) {
- src = &ucode->data[inst_size + data_size + init_size];
- len = priv->ucode_init_data.len;
+ len = init_data_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) init data len %zd\n", len);
memcpy(priv->ucode_init_data.v_addr, src, len);
+ src += len;
}
/* Bootstrap instructions (5th block) */
- src = &ucode->data[inst_size + data_size + init_size + init_data_size];
- len = priv->ucode_boot.len;
+ len = boot_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) boot instr len %zd\n", len);
memcpy(priv->ucode_boot.v_addr, src, len);
@@ -2784,7 +2723,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_CMD,
.len = sizeof(struct iwl3945_scan_cmd),
- .meta.flags = CMD_SIZE_HUGE,
+ .flags = CMD_SIZE_HUGE,
};
int rc = 0;
struct iwl3945_scan_cmd *scan;
@@ -3066,7 +3005,7 @@ void iwl3945_post_associate(struct iwl_priv *priv)
iwlcore_commit_rxon(priv);
memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
- iwl3945_setup_rxon_timing(priv);
+ iwl_setup_rxon_timing(priv);
rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
sizeof(priv->rxon_timing), &priv->rxon_timing);
if (rc)
@@ -3261,7 +3200,7 @@ void iwl3945_config_ap(struct iwl_priv *priv)
/* RXON Timing */
memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
- iwl3945_setup_rxon_timing(priv);
+ iwl_setup_rxon_timing(priv);
rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
sizeof(priv->rxon_timing),
&priv->rxon_timing);
@@ -3375,13 +3314,16 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* used for controlling the debug level.
*
* See the level definitions in iwl for details.
+ *
+ * The debug_level being managed using sysfs below is a per device debug
+ * level that is used instead of the global debug level if it (the per
+ * device debug level) is set.
*/
static ssize_t show_debug_level(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwl_priv *priv = dev_get_drvdata(d);
-
- return sprintf(buf, "0x%08X\n", priv->debug_level);
+ return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv));
}
static ssize_t store_debug_level(struct device *d,
struct device_attribute *attr,
@@ -3394,9 +3336,12 @@ static ssize_t store_debug_level(struct device *d,
ret = strict_strtoul(buf, 0, &val);
if (ret)
IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf);
- else
+ else {
priv->debug_level = val;
-
+ if (iwl_alloc_traffic_mem(priv))
+ IWL_ERR(priv,
+ "Not enough memory to generate traffic log\n");
+ }
return strnlen(buf, count);
}
@@ -3612,65 +3557,6 @@ static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate,
store_retry_rate);
-static ssize_t store_power_level(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- int ret;
- unsigned long mode;
-
-
- mutex_lock(&priv->mutex);
-
- ret = strict_strtoul(buf, 10, &mode);
- if (ret)
- goto out;
-
- ret = iwl_power_set_user_mode(priv, mode);
- if (ret) {
- IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n");
- goto out;
- }
- ret = count;
-
- out:
- mutex_unlock(&priv->mutex);
- return ret;
-}
-
-static ssize_t show_power_level(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- int level = priv->power_data.power_mode;
- char *p = buf;
-
- p += sprintf(p, "%d\n", level);
- return p - buf + 1;
-}
-
-static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR,
- show_power_level, store_power_level);
-
-#define MAX_WX_STRING 80
-
-/* Values are in microsecond */
-static const s32 timeout_duration[] = {
- 350000,
- 250000,
- 75000,
- 37000,
- 25000,
-};
-static const s32 period_duration[] = {
- 400000,
- 700000,
- 1000000,
- 1000000,
- 1000000
-};
-
static ssize_t show_channels(struct device *d,
struct device_attribute *attr, char *buf)
{
@@ -3847,7 +3733,6 @@ static struct attribute *iwl3945_sysfs_entries[] = {
#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
&dev_attr_measurement.attr,
#endif
- &dev_attr_power_level.attr,
&dev_attr_retry_rate.attr,
&dev_attr_statistics.attr,
&dev_attr_status.attr,
@@ -3912,8 +3797,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
priv->qos_data.qos_cap.val = 0;
priv->rates_mask = IWL_RATES_MASK;
- /* If power management is turned on, default to CAM mode */
- priv->power_mode = IWL_POWER_MODE_CAM;
priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER;
if (eeprom->version < EEPROM_3945_EEPROM_VERSION) {
@@ -3960,7 +3843,9 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
- IEEE80211_HW_SPECTRUM_MGMT;
+ IEEE80211_HW_SPECTRUM_MGMT |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
@@ -4020,15 +3905,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv = hw->priv;
SET_IEEE80211_DEV(hw, &pdev->dev);
- if ((iwl3945_mod_params.num_of_queues > IWL39_MAX_NUM_QUEUES) ||
- (iwl3945_mod_params.num_of_queues < IWL39_MIN_NUM_QUEUES)) {
- IWL_ERR(priv,
- "invalid queues_num, should be between %d and %d\n",
- IWL39_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES);
- err = -EINVAL;
- goto out_ieee80211_free_hw;
- }
-
/*
* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan.
@@ -4045,9 +3921,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv->inta_mask = CSR_INI_SET_MASK;
#ifdef CONFIG_IWLWIFI_DEBUG
- priv->debug_level = iwl3945_mod_params.debug;
atomic_set(&priv->restrict_refcnt, 0);
#endif
+ if (iwl_alloc_traffic_mem(priv))
+ IWL_ERR(priv, "Not enough memory to generate traffic log\n");
/***************************
* 2. Initializing PCI bus
@@ -4210,6 +4087,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
pci_disable_device(pdev);
out_ieee80211_free_hw:
ieee80211_free_hw(priv->hw);
+ iwl_free_traffic_mem(priv);
out:
return err;
}
@@ -4265,6 +4143,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
* until now... */
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;
+ iwl_free_traffic_mem(priv);
free_irq(pdev->irq, priv);
pci_disable_msi(pdev);
@@ -4341,14 +4220,12 @@ MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto,
"using software crypto (default 1 [software])\n");
-module_param_named(debug, iwl3945_mod_params.debug, uint, 0444);
+#ifdef CONFIG_IWLWIFI_DEBUG
+module_param_named(debug, iwl_debug_level, uint, 0644);
MODULE_PARM_DESC(debug, "debug output mask");
+#endif
module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
-
-module_param_named(queues_num, iwl3945_mod_params.num_of_queues, int, 0444);
-MODULE_PARM_DESC(queues_num, "number of hw queues.");
-
module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444);
MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig
index 030401d367d3..c62da435285a 100644
--- a/drivers/net/wireless/iwmc3200wifi/Kconfig
+++ b/drivers/net/wireless/iwmc3200wifi/Kconfig
@@ -2,7 +2,6 @@ config IWM
tristate "Intel Wireless Multicomm 3200 WiFi driver"
depends on MMC && WLAN_80211 && EXPERIMENTAL
depends on CFG80211
- select WIRELESS_EXT
select FW_LOADER
help
The Intel Wireless Multicomm 3200 hardware is a combo
diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile
index 927f022545c1..d34291b652d3 100644
--- a/drivers/net/wireless/iwmc3200wifi/Makefile
+++ b/drivers/net/wireless/iwmc3200wifi/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_IWM) := iwmc3200wifi.o
iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o
-iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o
+iwmc3200wifi-objs += commands.o cfg80211.o eeprom.o
iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 96f714e6e12b..a56a2b0ac99a 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
@@ -130,6 +131,134 @@ static struct ieee80211_supported_band iwm_band_5ghz = {
.n_bitrates = iwm_a_rates_size,
};
+static int iwm_key_init(struct iwm_key *key, u8 key_index,
+ const u8 *mac_addr, struct key_params *params)
+{
+ key->hdr.key_idx = key_index;
+ if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
+ key->hdr.multicast = 1;
+ memset(key->hdr.mac, 0xff, ETH_ALEN);
+ } else {
+ key->hdr.multicast = 0;
+ memcpy(key->hdr.mac, mac_addr, ETH_ALEN);
+ }
+
+ if (params) {
+ if (params->key_len > WLAN_MAX_KEY_LEN ||
+ params->seq_len > IW_ENCODE_SEQ_MAX_SIZE)
+ return -EINVAL;
+
+ key->cipher = params->cipher;
+ key->key_len = params->key_len;
+ key->seq_len = params->seq_len;
+ memcpy(key->key, params->key, key->key_len);
+ memcpy(key->seq, params->seq, key->seq_len);
+ }
+
+ return 0;
+}
+
+static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, const u8 *mac_addr,
+ struct key_params *params)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+ struct iwm_key *key = &iwm->keys[key_index];
+ int ret;
+
+ IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
+
+ memset(key, 0, sizeof(struct iwm_key));
+ ret = iwm_key_init(key, key_index, mac_addr, params);
+ if (ret < 0) {
+ IWM_ERR(iwm, "Invalid key_params\n");
+ return ret;
+ }
+
+ return iwm_set_key(iwm, 0, key);
+}
+
+static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, const u8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie,
+ struct key_params*))
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+ struct iwm_key *key = &iwm->keys[key_index];
+ struct key_params params;
+
+ IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index);
+
+ memset(&params, 0, sizeof(params));
+
+ params.cipher = key->cipher;
+ params.key_len = key->key_len;
+ params.seq_len = key->seq_len;
+ params.seq = key->seq;
+ params.key = key->key;
+
+ callback(cookie, &params);
+
+ return key->key_len ? 0 : -ENOENT;
+}
+
+
+static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, const u8 *mac_addr)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+ struct iwm_key *key = &iwm->keys[key_index];
+
+ if (!iwm->keys[key_index].key_len) {
+ IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
+ return 0;
+ }
+
+ if (key_index == iwm->default_key)
+ iwm->default_key = -1;
+
+ return iwm_set_key(iwm, 1, key);
+}
+
+static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
+ struct net_device *ndev,
+ u8 key_index)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+
+ IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
+
+ if (!iwm->keys[key_index].key_len) {
+ IWM_ERR(iwm, "Key %d not used\n", key_index);
+ return -EINVAL;
+ }
+
+ iwm->default_key = key_index;
+
+ return iwm_set_tx_key(iwm, key_index);
+}
+
+static int iwm_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *ndev,
+ u8 *mac, struct station_info *sinfo)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+
+ if (memcmp(mac, iwm->bssid, ETH_ALEN))
+ return -ENOENT;
+
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->txrate.legacy = iwm->rate * 10;
+
+ if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = iwm->wstats.qual.level;
+ }
+
+ return 0;
+}
+
+
int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
{
struct wiphy *wiphy = iwm_to_wiphy(iwm);
@@ -167,20 +296,15 @@ int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
return 0;
}
-static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex,
+static int iwm_cfg80211_change_iface(struct wiphy *wiphy,
+ struct net_device *ndev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
- struct net_device *ndev;
struct wireless_dev *wdev;
struct iwm_priv *iwm;
u32 old_mode;
- /* we're under RTNL */
- ndev = __dev_get_by_index(&init_net, ifindex);
- if (!ndev)
- return -ENODEV;
-
wdev = ndev->ieee80211_ptr;
iwm = ndev_to_iwm(ndev);
old_mode = iwm->conf.mode;
@@ -203,11 +327,8 @@ static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex,
iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode);
- if (iwm->umac_profile_active) {
- int ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0)
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- }
+ if (iwm->umac_profile_active)
+ iwm_invalidate_mlme_profile(iwm);
return 0;
}
@@ -329,12 +450,300 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
return 0;
}
+static int iwm_set_auth_type(struct iwm_priv *iwm,
+ enum nl80211_auth_type sme_auth_type)
+{
+ u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+ switch (sme_auth_type) {
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n");
+ *auth_type = UMAC_AUTH_TYPE_OPEN;
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ if (iwm->umac_profile->sec.flags &
+ (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
+ IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n");
+ *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+ } else {
+ IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n");
+ *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+ }
+
+ break;
+ default:
+ IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
+{
+ IWM_DBG_WEXT(iwm, DBG, "wpa_version: %d\n", wpa_version);
+
+ if (!wpa_version) {
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
+ return 0;
+ }
+
+ if (wpa_version & NL80211_WPA_VERSION_2)
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
+
+ if (wpa_version & NL80211_WPA_VERSION_1)
+ iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
+
+ return 0;
+}
+
+static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
+{
+ u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
+ &iwm->umac_profile->sec.mcast_cipher;
+
+ if (!cipher) {
+ *profile_cipher = UMAC_CIPHER_TYPE_NONE;
+ return 0;
+ }
+
+ IWM_DBG_WEXT(iwm, DBG, "%ccast cipher is 0x%x\n", ucast ? 'u' : 'm',
+ cipher);
+
+ switch (cipher) {
+ case IW_AUTH_CIPHER_NONE:
+ *profile_cipher = UMAC_CIPHER_TYPE_NONE;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
+ break;
+ default:
+ IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt)
+{
+ u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+ IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
+
+ if (key_mgt == WLAN_AKM_SUITE_8021X)
+ *auth_type = UMAC_AUTH_TYPE_8021X;
+ else if (key_mgt == WLAN_AKM_SUITE_PSK) {
+ if (iwm->umac_profile->sec.flags &
+ (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
+ *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+ else
+ *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+ } else {
+ IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+ struct ieee80211_channel *chan = sme->channel;
+ struct key_params key_param;
+ int ret;
+
+ if (!test_bit(IWM_STATUS_READY, &iwm->status))
+ return -EIO;
+
+ if (!sme->ssid)
+ return -EINVAL;
+
+ if (iwm->umac_profile_active) {
+ ret = iwm_invalidate_mlme_profile(iwm);
+ if (ret) {
+ IWM_ERR(iwm, "Couldn't invalidate profile\n");
+ return ret;
+ }
+ }
+
+ if (chan)
+ iwm->channel =
+ ieee80211_frequency_to_channel(chan->center_freq);
+
+ iwm->umac_profile->ssid.ssid_len = sme->ssid_len;
+ memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len);
+
+ if (sme->bssid) {
+ IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid);
+ memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN);
+ iwm->umac_profile->bss_num = 1;
+ } else {
+ memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
+ iwm->umac_profile->bss_num = 0;
+ }
+
+ ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
+ if (ret < 0)
+ return ret;
+
+ ret = iwm_set_auth_type(iwm, sme->auth_type);
+ if (ret < 0)
+ return ret;
+
+ if (sme->crypto.n_ciphers_pairwise) {
+ ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0],
+ true);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false);
+ if (ret < 0)
+ return ret;
+
+ if (sme->crypto.n_akm_suites) {
+ ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]);
+ if (ret < 0)
+ return ret;
+ }
+
+ /*
+ * We save the WEP key in case we want to do shared authentication.
+ * We have to do it so because UMAC will assert whenever it gets a
+ * key before a profile.
+ */
+ if (sme->key) {
+ key_param.key = kmemdup(sme->key, sme->key_len, GFP_KERNEL);
+ if (key_param.key == NULL)
+ return -ENOMEM;
+ key_param.key_len = sme->key_len;
+ key_param.seq_len = 0;
+ key_param.cipher = sme->crypto.ciphers_pairwise[0];
+
+ ret = iwm_key_init(&iwm->keys[sme->key_idx], sme->key_idx,
+ NULL, &key_param);
+ kfree(key_param.key);
+ if (ret < 0) {
+ IWM_ERR(iwm, "Invalid key_params\n");
+ return ret;
+ }
+
+ iwm->default_key = sme->key_idx;
+ }
+
+ ret = iwm_send_mlme_profile(iwm);
+
+ if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK ||
+ sme->key == NULL)
+ return ret;
+
+ /*
+ * We want to do shared auth.
+ * We need to actually set the key we previously cached,
+ * and then tell the UMAC it's the default one.
+ * That will trigger the auth+assoc UMAC machinery, and again,
+ * this must be done after setting the profile.
+ */
+ ret = iwm_set_key(iwm, 0, &iwm->keys[sme->key_idx]);
+ if (ret < 0)
+ return ret;
+
+ return iwm_set_tx_key(iwm, iwm->default_key);
+}
+
+static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+ IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
+
+ if (iwm->umac_profile_active)
+ iwm_invalidate_mlme_profile(iwm);
+
+ return 0;
+}
+
+static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
+ enum tx_power_setting type, int dbm)
+{
+ switch (type) {
+ case TX_POWER_AUTOMATIC:
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+ *dbm = iwm->txpower;
+
+ return 0;
+}
+
+static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev,
+ bool enabled, int timeout)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+ u32 power_index;
+
+ if (enabled)
+ power_index = IWM_POWER_INDEX_DEFAULT;
+ else
+ power_index = IWM_POWER_INDEX_MIN;
+
+ if (power_index == iwm->conf.power_index)
+ return 0;
+
+ iwm->conf.power_index = power_index;
+
+ return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+ CFG_POWER_INDEX, iwm->conf.power_index);
+}
+
static struct cfg80211_ops iwm_cfg80211_ops = {
.change_virtual_intf = iwm_cfg80211_change_iface,
+ .add_key = iwm_cfg80211_add_key,
+ .get_key = iwm_cfg80211_get_key,
+ .del_key = iwm_cfg80211_del_key,
+ .set_default_key = iwm_cfg80211_set_default_key,
+ .get_station = iwm_cfg80211_get_station,
.scan = iwm_cfg80211_scan,
.set_wiphy_params = iwm_cfg80211_set_wiphy_params,
+ .connect = iwm_cfg80211_connect,
+ .disconnect = iwm_cfg80211_disconnect,
.join_ibss = iwm_cfg80211_join_ibss,
.leave_ibss = iwm_cfg80211_leave_ibss,
+ .set_tx_power = iwm_cfg80211_set_txpower,
+ .get_tx_power = iwm_cfg80211_get_txpower,
+ .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
+};
+
+static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
};
struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
@@ -379,6 +788,9 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wdev->wiphy->cipher_suites = cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
ret = wiphy_register(wdev->wiphy);
if (ret < 0) {
dev_err(dev, "Couldn't register wiphy device\n");
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index e2334d123599..23b52fa2605f 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -70,14 +70,27 @@ static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm,
int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
bool resp)
{
+ struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload;
struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
struct iwm_umac_cmd umac_cmd;
+ int ret;
+ u8 oid = hdr->oid;
umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER;
umac_cmd.resp = resp;
- return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
- payload, payload_size);
+ ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
+ payload, payload_size);
+
+ if (resp) {
+ ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue,
+ test_and_clear_bit(oid, &iwm->wifi_ntfy[0]),
+ 3 * HZ);
+
+ return ret ? 0 : -EBUSY;
+ }
+
+ return ret;
}
static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
@@ -106,7 +119,7 @@ static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] =
{4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
{3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
{5, 5, 0, COEX_CALIBRATION_FLAGS},
- {4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
+ {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
{5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS},
{4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS},
{4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
@@ -332,8 +345,7 @@ int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key,
return ret;
}
-int iwm_send_umac_config(struct iwm_priv *iwm,
- __le32 reset_flags)
+int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags)
{
int ret;
@@ -361,6 +373,12 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
return ret;
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+ CFG_WIRELESS_MODE,
+ iwm->conf.wireless_mode);
+ if (ret < 0)
+ return ret;
+
+ ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
CFG_COEX_MODE, iwm->conf.coexist_mode);
if (ret < 0)
return ret;
@@ -402,7 +420,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
return ret;
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
- CFG_PM_CTRL_FLAGS, 0x30001);
+ CFG_PM_CTRL_FLAGS, 0x1);
if (ret < 0)
return ret;
@@ -462,8 +480,10 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
target_cmd.eop = 1;
ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
- if (ret < 0)
+ if (ret < 0) {
IWM_ERR(iwm, "Couldn't send READ command\n");
+ return ret;
+ }
/* When succeding, the send_target routine returns the seq number */
seq_num = ret;
@@ -483,7 +503,7 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
kfree(cmd);
- return ret;
+ return 0;
}
int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
@@ -493,7 +513,7 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR),
mac_align, sizeof(mac_align));
- if (ret < 0)
+ if (ret)
return ret;
if (is_valid_ether_addr(mac_align))
@@ -507,22 +527,6 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
return 0;
}
-int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
-{
- struct iwm_umac_tx_key_id tx_key_id;
-
- if (!iwm->default_key || !iwm->default_key->in_use)
- return -EINVAL;
-
- tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
- tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
- sizeof(struct iwm_umac_wifi_if));
-
- tx_key_id.key_idx = key_idx;
-
- return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1);
-}
-
static int iwm_check_profile(struct iwm_priv *iwm)
{
if (!iwm->umac_profile_active)
@@ -556,10 +560,35 @@ static int iwm_check_profile(struct iwm_priv *iwm)
return 0;
}
-int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
- struct iwm_key *key)
+int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
{
+ struct iwm_umac_tx_key_id tx_key_id;
int ret;
+
+ ret = iwm_check_profile(iwm);
+ if (ret < 0)
+ return ret;
+
+ /* UMAC only allows to set default key for WEP and auth type is
+ * NOT 802.1X or RSNA. */
+ if ((iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 &&
+ iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104) ||
+ iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_8021X ||
+ iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_RSNA_PSK)
+ return 0;
+
+ tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
+ tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
+ sizeof(struct iwm_umac_wifi_if));
+
+ tx_key_id.key_idx = key_idx;
+
+ return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1);
+}
+
+int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
+{
+ int ret = 0;
u8 cmd[64], *sta_addr, *key_data, key_len;
s8 key_idx;
u16 cmd_size = 0;
@@ -569,15 +598,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd;
struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd;
- if (set_tx_key)
- iwm->default_key = key;
-
- /*
- * We check if our current profile is valid.
- * If not, we dont push the key, we just cache them,
- * so that with the next siwsessid call, the keys
- * will be actually pushed.
- */
if (!remove) {
ret = iwm_check_profile(iwm);
if (ret < 0)
@@ -590,8 +610,9 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
key_idx = key->hdr.key_idx;
if (!remove) {
- IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n",
- key_idx, set_tx_key);
+ u8 auth_type = iwm->umac_profile->sec.auth_type;
+
+ IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx);
IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len);
IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n",
key_hdr->mac, key_hdr->key_idx, key_hdr->multicast);
@@ -603,8 +624,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
iwm->umac_profile->sec.auth_type,
iwm->umac_profile->sec.flags);
- switch (key->alg) {
- case UMAC_CIPHER_TYPE_WEP_40:
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY;
wep40->hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_wep40) -
@@ -613,12 +634,14 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
memcpy(&wep40->key_hdr, key_hdr,
sizeof(struct iwm_umac_key_hdr));
memcpy(wep40->key, key_data, key_len);
- wep40->static_key = 1;
+ wep40->static_key =
+ !!((auth_type != UMAC_AUTH_TYPE_8021X) &&
+ (auth_type != UMAC_AUTH_TYPE_RSNA_PSK));
cmd_size = sizeof(struct iwm_umac_key_wep40);
break;
- case UMAC_CIPHER_TYPE_WEP_104:
+ case WLAN_CIPHER_SUITE_WEP104:
wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY;
wep104->hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_wep104) -
@@ -627,12 +650,14 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
memcpy(&wep104->key_hdr, key_hdr,
sizeof(struct iwm_umac_key_hdr));
memcpy(wep104->key, key_data, key_len);
- wep104->static_key = 1;
+ wep104->static_key =
+ !!((auth_type != UMAC_AUTH_TYPE_8021X) &&
+ (auth_type != UMAC_AUTH_TYPE_RSNA_PSK));
cmd_size = sizeof(struct iwm_umac_key_wep104);
break;
- case UMAC_CIPHER_TYPE_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
key_hdr->key_idx++;
ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY;
ccmp->hdr.buf_size =
@@ -644,13 +669,13 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
memcpy(ccmp->key, key_data, key_len);
- if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
- memcpy(ccmp->iv_count, key->rx_seq, 6);
+ if (key->seq_len)
+ memcpy(ccmp->iv_count, key->seq, key->seq_len);
cmd_size = sizeof(struct iwm_umac_key_ccmp);
break;
- case UMAC_CIPHER_TYPE_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
key_hdr->key_idx++;
tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY;
tkip->hdr.buf_size =
@@ -667,8 +692,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE,
IWM_TKIP_MIC_SIZE);
- if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
- memcpy(ccmp->iv_count, key->rx_seq, 6);
+ if (key->seq_len)
+ memcpy(ccmp->iv_count, key->seq, key->seq_len);
cmd_size = sizeof(struct iwm_umac_key_tkip);
break;
@@ -677,8 +702,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
return -ENOTSUPP;
}
- if ((key->alg == UMAC_CIPHER_TYPE_CCMP) ||
- (key->alg == UMAC_CIPHER_TYPE_TKIP))
+ if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) ||
+ (key->cipher == WLAN_CIPHER_SUITE_CCMP))
/*
* UGLY_UGLY_UGLY
* Copied HACK from the MWG driver.
@@ -689,23 +714,11 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
schedule_timeout_interruptible(usecs_to_jiffies(300));
ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1);
- if (ret < 0)
- goto err;
-
- /*
- * We need a default key only if it is set and
- * if we're doing WEP.
- */
- if (iwm->default_key == key &&
- ((key->alg == UMAC_CIPHER_TYPE_WEP_40) ||
- (key->alg == UMAC_CIPHER_TYPE_WEP_104))) {
- ret = iwm_set_tx_key(iwm, key_idx);
- if (ret < 0)
- goto err;
- }
} else {
struct iwm_umac_key_remove key_remove;
+ IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx);
+
key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY;
key_remove.hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_remove) -
@@ -716,23 +729,19 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
ret = iwm_send_wifi_if_cmd(iwm, &key_remove,
sizeof(struct iwm_umac_key_remove),
1);
- if (ret < 0)
+ if (ret)
return ret;
- iwm->keys[key_idx].in_use = 0;
+ iwm->keys[key_idx].key_len = 0;
}
- return 0;
-
- err:
- kfree(key);
return ret;
}
int iwm_send_mlme_profile(struct iwm_priv *iwm)
{
- int ret, i;
+ int ret;
struct iwm_umac_profile profile;
memcpy(&profile, iwm->umac_profile, sizeof(profile));
@@ -742,45 +751,19 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
sizeof(struct iwm_umac_wifi_if));
ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1);
- if (ret < 0) {
+ if (ret) {
IWM_ERR(iwm, "Send profile command failed\n");
return ret;
}
- /* Wait for the profile to be active */
- ret = wait_event_interruptible_timeout(iwm->mlme_queue,
- iwm->umac_profile_active == 1,
- 3 * HZ);
- if (!ret)
- return -EBUSY;
-
-
- for (i = 0; i < IWM_NUM_KEYS; i++)
- if (iwm->keys[i].in_use) {
- int default_key = 0;
- struct iwm_key *key = &iwm->keys[i];
-
- if (key == iwm->default_key)
- default_key = 1;
-
- /* Wait for the profile before sending the keys */
- wait_event_interruptible_timeout(iwm->mlme_queue,
- (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) ||
- test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)),
- 3 * HZ);
-
- ret = iwm_set_key(iwm, 0, default_key, key);
- if (ret < 0)
- return ret;
- }
-
+ set_bit(IWM_STATUS_SME_CONNECTING, &iwm->status);
return 0;
}
int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
{
- int ret;
struct iwm_umac_invalidate_profile invalid;
+ int ret;
invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE;
invalid.hdr.buf_size =
@@ -790,16 +773,13 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
invalid.reason = WLAN_REASON_UNSPECIFIED;
ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1);
- if (ret < 0)
+ if (ret)
return ret;
ret = wait_event_interruptible_timeout(iwm->mlme_queue,
- (iwm->umac_profile_active == 0),
- 2 * HZ);
- if (!ret)
- return -EBUSY;
+ (iwm->umac_profile_active == 0), 2 * HZ);
- return 0;
+ return ret ? 0 : -EBUSY;
}
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags)
@@ -882,7 +862,7 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
}
ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0);
- if (ret < 0) {
+ if (ret) {
IWM_ERR(iwm, "Couldn't send scan request\n");
return ret;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index 36b13a130595..e24d5b633997 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -106,8 +106,7 @@ enum {
CFG_TLC_SPATIAL_STREAM_SUPPORTED,
CFG_TLC_RETRY_PER_RATE,
CFG_TLC_RETRY_PER_HT_RATE,
- CFG_TLC_FIXED_RATE,
- CFG_TLC_FIXED_RATE_FLAGS,
+ CFG_TLC_FIXED_MCS,
CFG_TLC_CONTROL_FLAGS,
CFG_TLC_SR_MIN_FAIL,
CFG_TLC_SR_MIN_PASS,
@@ -232,6 +231,7 @@ struct iwm_umac_cmd_get_channel_list {
/* Wireless mode */
#define WIRELESS_MODE_11A 0x1
#define WIRELESS_MODE_11G 0x2
+#define WIRELESS_MODE_11N 0x4
#define UMAC_PROFILE_EX_IE_REQUIRED 0x1
#define UMAC_PROFILE_QOS_ALLOWED 0x2
@@ -406,8 +406,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm);
int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
-int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
- struct iwm_key *key);
+int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key);
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
int iwm_send_umac_channel_list(struct iwm_priv *iwm);
int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
diff --git a/drivers/net/wireless/iwmc3200wifi/debug.h b/drivers/net/wireless/iwmc3200wifi/debug.h
index 8fbb42d9c21f..e35c9b693d1f 100644
--- a/drivers/net/wireless/iwmc3200wifi/debug.h
+++ b/drivers/net/wireless/iwmc3200wifi/debug.h
@@ -108,6 +108,8 @@ struct iwm_debugfs {
struct dentry *txq_dentry;
struct dentry *tx_credit_dentry;
struct dentry *rx_ticket_dentry;
+
+ struct dentry *fw_err_dentry;
};
#ifdef CONFIG_IWM_DEBUG
diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c
index 0fa7b9150d58..1465379f900a 100644
--- a/drivers/net/wireless/iwmc3200wifi/debugfs.c
+++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c
@@ -98,7 +98,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules,
iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write,
"%llu\n");
-static int iwm_txrx_open(struct inode *inode, struct file *filp)
+static int iwm_generic_open(struct inode *inode, struct file *filp)
{
filp->private_data = inode->i_private;
return 0;
@@ -289,25 +289,111 @@ static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp,
return ret;
}
+static ssize_t iwm_debugfs_fw_err_read(struct file *filp,
+ char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+
+ struct iwm_priv *iwm = filp->private_data;
+ char buf[512];
+ int buf_len = 512;
+ size_t len = 0;
+
+ if (*ppos != 0)
+ return 0;
+ if (count < sizeof(buf))
+ return -ENOSPC;
+
+ if (!iwm->last_fw_err)
+ return -ENOMEM;
+
+ if (iwm->last_fw_err->line_num == 0)
+ goto out;
+
+ len += snprintf(buf + len, buf_len - len, "%cMAC FW ERROR:\n",
+ (le32_to_cpu(iwm->last_fw_err->category) == UMAC_SYS_ERR_CAT_LMAC)
+ ? 'L' : 'U');
+ len += snprintf(buf + len, buf_len - len,
+ "\tCategory: %d\n",
+ le32_to_cpu(iwm->last_fw_err->category));
+
+ len += snprintf(buf + len, buf_len - len,
+ "\tStatus: 0x%x\n",
+ le32_to_cpu(iwm->last_fw_err->status));
+
+ len += snprintf(buf + len, buf_len - len,
+ "\tPC: 0x%x\n",
+ le32_to_cpu(iwm->last_fw_err->pc));
+
+ len += snprintf(buf + len, buf_len - len,
+ "\tblink1: %d\n",
+ le32_to_cpu(iwm->last_fw_err->blink1));
+
+ len += snprintf(buf + len, buf_len - len,
+ "\tblink2: %d\n",
+ le32_to_cpu(iwm->last_fw_err->blink2));
+
+ len += snprintf(buf + len, buf_len - len,
+ "\tilink1: %d\n",
+ le32_to_cpu(iwm->last_fw_err->ilink1));
+
+ len += snprintf(buf + len, buf_len - len,
+ "\tilink2: %d\n",
+ le32_to_cpu(iwm->last_fw_err->ilink2));
+
+ len += snprintf(buf + len, buf_len - len,
+ "\tData1: 0x%x\n",
+ le32_to_cpu(iwm->last_fw_err->data1));
+
+ len += snprintf(buf + len, buf_len - len,
+ "\tData2: 0x%x\n",
+ le32_to_cpu(iwm->last_fw_err->data2));
+
+ len += snprintf(buf + len, buf_len - len,
+ "\tLine number: %d\n",
+ le32_to_cpu(iwm->last_fw_err->line_num));
+
+ len += snprintf(buf + len, buf_len - len,
+ "\tUMAC status: 0x%x\n",
+ le32_to_cpu(iwm->last_fw_err->umac_status));
+
+ len += snprintf(buf + len, buf_len - len,
+ "\tLMAC status: 0x%x\n",
+ le32_to_cpu(iwm->last_fw_err->lmac_status));
+
+ len += snprintf(buf + len, buf_len - len,
+ "\tSDIO status: 0x%x\n",
+ le32_to_cpu(iwm->last_fw_err->sdio_status));
+
+out:
+
+ return simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
+}
static const struct file_operations iwm_debugfs_txq_fops = {
.owner = THIS_MODULE,
- .open = iwm_txrx_open,
+ .open = iwm_generic_open,
.read = iwm_debugfs_txq_read,
};
static const struct file_operations iwm_debugfs_tx_credit_fops = {
.owner = THIS_MODULE,
- .open = iwm_txrx_open,
+ .open = iwm_generic_open,
.read = iwm_debugfs_tx_credit_read,
};
static const struct file_operations iwm_debugfs_rx_ticket_fops = {
.owner = THIS_MODULE,
- .open = iwm_txrx_open,
+ .open = iwm_generic_open,
.read = iwm_debugfs_rx_ticket_read,
};
+static const struct file_operations iwm_debugfs_fw_err_fops = {
+ .owner = THIS_MODULE,
+ .open = iwm_generic_open,
+ .read = iwm_debugfs_fw_err_read,
+};
+
int iwm_debugfs_init(struct iwm_priv *iwm)
{
int i, result;
@@ -423,6 +509,16 @@ int iwm_debugfs_init(struct iwm_priv *iwm)
goto error;
}
+ iwm->dbg.fw_err_dentry = debugfs_create_file("last_fw_err", 0200,
+ iwm->dbg.dbgdir, iwm,
+ &iwm_debugfs_fw_err_fops);
+ result = PTR_ERR(iwm->dbg.fw_err_dentry);
+ if (IS_ERR(iwm->dbg.fw_err_dentry) && (result != -ENODEV)) {
+ IWM_ERR(iwm, "Couldn't create last FW err: %d\n", result);
+ goto error;
+ }
+
+
return 0;
error:
@@ -441,6 +537,7 @@ void iwm_debugfs_exit(struct iwm_priv *iwm)
debugfs_remove(iwm->dbg.txq_dentry);
debugfs_remove(iwm->dbg.tx_credit_dentry);
debugfs_remove(iwm->dbg.rx_ticket_dentry);
+ debugfs_remove(iwm->dbg.fw_err_dentry);
if (iwm->bus_ops->debugfs_exit)
iwm->bus_ops->debugfs_exit(iwm);
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c
index 0f34b84fd2eb..365910fbe01e 100644
--- a/drivers/net/wireless/iwmc3200wifi/eeprom.c
+++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c
@@ -156,10 +156,6 @@ int iwm_eeprom_init(struct iwm_priv *iwm)
return -ENOMEM;
for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) {
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (iwm->conf.hw_b0 && (i >= IWM_EEPROM_INDIRECT_OFFSET))
- break;
-#endif
ret = iwm_eeprom_read(iwm, i);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n",
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c
index ec1a15a5a0e4..6b0bcad758ca 100644
--- a/drivers/net/wireless/iwmc3200wifi/fw.c
+++ b/drivers/net/wireless/iwmc3200wifi/fw.c
@@ -261,6 +261,33 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name)
cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_CLK_EN), 0);
}
+static int iwm_init_calib(struct iwm_priv *iwm, unsigned long cfg_bitmap,
+ unsigned long expected_bitmap, u8 rx_iq_cmd)
+{
+ /* Read RX IQ calibration result from EEPROM */
+ if (test_bit(rx_iq_cmd, &cfg_bitmap)) {
+ iwm_store_rxiq_calib_result(iwm);
+ set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map);
+ }
+
+ iwm_send_prio_table(iwm);
+ iwm_send_init_calib_cfg(iwm, cfg_bitmap);
+
+ while (iwm->calib_done_map != expected_bitmap) {
+ if (iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION,
+ IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT)) {
+ IWM_DBG_FW(iwm, DBG, "Initial calibration timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: "
+ "0x%lx, expected calibrations: 0x%lx\n",
+ iwm->calib_done_map, expected_bitmap);
+ }
+
+ return 0;
+}
+
/*
* We currently have to load 3 FWs:
* 1) The UMAC (Upper MAC).
@@ -275,6 +302,8 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name)
*/
int iwm_load_fw(struct iwm_priv *iwm)
{
+ unsigned long init_calib_map, periodic_calib_map;
+ unsigned long expected_calib_map;
int ret;
/* We first start downloading the UMAC */
@@ -315,32 +344,22 @@ int iwm_load_fw(struct iwm_priv *iwm)
return ret;
}
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (iwm->conf.hw_b0) {
- clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map);
- clear_bit(PHY_CALIBRATE_RX_IQ_CMD,
- &iwm->conf.periodic_calib_map);
- }
-#endif
- /* Read RX IQ calibration result from EEPROM */
- if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map)) {
- iwm_store_rxiq_calib_result(iwm);
- set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map);
- }
-
- iwm_send_prio_table(iwm);
- iwm_send_init_calib_cfg(iwm, iwm->conf.init_calib_map);
+ init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK;
+ expected_calib_map = iwm->conf.expected_calib_map &
+ IWM_CALIB_MAP_INIT_MSK;
+ periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map);
- while (iwm->calib_done_map != iwm->conf.init_calib_map) {
- ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION,
- IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT);
- if (ret) {
- IWM_ERR(iwm, "Wait for calibration result timeout\n");
+ ret = iwm_init_calib(iwm, init_calib_map, expected_calib_map,
+ CALIB_CFG_RX_IQ_IDX);
+ if (ret < 0) {
+ /* Let's try the old way */
+ ret = iwm_init_calib(iwm, expected_calib_map,
+ expected_calib_map,
+ PHY_CALIBRATE_RX_IQ_CMD);
+ if (ret < 0) {
+ IWM_ERR(iwm, "Calibration result timeout\n");
goto out;
}
- IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: "
- "0x%lx, requested calibrations: 0x%lx\n",
- iwm->calib_done_map, iwm->conf.init_calib_map);
}
/* Handle LMAC CALIBRATION_COMPLETE notification */
@@ -378,7 +397,7 @@ int iwm_load_fw(struct iwm_priv *iwm)
iwm_send_prio_table(iwm);
iwm_send_calib_results(iwm);
- iwm_send_periodic_calib_cfg(iwm, iwm->conf.periodic_calib_map);
+ iwm_send_periodic_calib_cfg(iwm, periodic_calib_map);
return 0;
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c
index ee127fe4f43f..c430418248b4 100644
--- a/drivers/net/wireless/iwmc3200wifi/hal.c
+++ b/drivers/net/wireless/iwmc3200wifi/hal.c
@@ -105,9 +105,9 @@
#include "umac.h"
#include "debug.h"
-static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
- struct iwm_nonwifi_cmd *cmd,
- struct iwm_udma_nonwifi_cmd *udma_cmd)
+static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
+ struct iwm_nonwifi_cmd *cmd,
+ struct iwm_udma_nonwifi_cmd *udma_cmd)
{
INIT_LIST_HEAD(&cmd->pending);
@@ -118,7 +118,7 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
cmd->seq_num = iwm->nonwifi_seq_num;
udma_cmd->seq_num = cpu_to_le16(cmd->seq_num);
- cmd->seq_num = iwm->nonwifi_seq_num++;
+ iwm->nonwifi_seq_num++;
iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX;
if (udma_cmd->resp)
@@ -130,6 +130,8 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
cmd->buf.len = 0;
memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
+
+ return cmd->seq_num;
}
u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm)
@@ -369,7 +371,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
const void *payload)
{
struct iwm_nonwifi_cmd *cmd;
- int ret;
+ int ret, seq_num;
cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL);
if (!cmd) {
@@ -377,7 +379,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
return -ENOMEM;
}
- iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
+ seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE ||
cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) {
@@ -393,7 +395,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
if (ret < 0)
return ret;
- return cmd->seq_num;
+ return seq_num;
}
static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr,
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 77c339f8516c..1b02a4e2a1ac 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -52,8 +52,6 @@
#define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation"
#define IWM_AUTHOR "<ilw@linux.intel.com>"
-#define CONFIG_IWM_B0_HW_SUPPORT 1
-
#define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX
#define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA
#define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW
@@ -65,8 +63,8 @@
struct iwm_conf {
u32 sdio_ior_timeout;
- unsigned long init_calib_map;
- unsigned long periodic_calib_map;
+ unsigned long calib_map;
+ unsigned long expected_calib_map;
bool reset_on_fatal_err;
bool auto_connect;
bool wimax_not_present;
@@ -87,9 +85,6 @@ struct iwm_conf {
u8 ibss_channel;
u8 mac_addr[ETH_ALEN];
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- bool hw_b0;
-#endif
};
enum {
@@ -162,13 +157,11 @@ struct iwm_umac_key_hdr {
struct iwm_key {
struct iwm_umac_key_hdr hdr;
- u8 in_use;
- u8 alg;
- u32 flags;
- u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE];
- u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE];
- u8 key_len;
- u8 key[32];
+ u32 cipher;
+ u8 key[WLAN_MAX_KEY_LEN];
+ u8 seq[IW_ENCODE_SEQ_MAX_SIZE];
+ int key_len;
+ int seq_len;
};
#define IWM_RX_ID_HASH 0xff
@@ -183,12 +176,9 @@ struct iwm_key {
#define IWM_STATUS_READY 0
#define IWM_STATUS_SCANNING 1
#define IWM_STATUS_SCAN_ABORTING 2
-#define IWM_STATUS_ASSOCIATING 3
+#define IWM_STATUS_SME_CONNECTING 3
#define IWM_STATUS_ASSOCIATED 4
-
-#define IWM_RADIO_RFKILL_OFF 0
-#define IWM_RADIO_RFKILL_HW 1
-#define IWM_RADIO_RFKILL_SW 2
+#define IWM_STATUS_RESETTING 5
struct iwm_tx_queue {
int id;
@@ -223,7 +213,6 @@ struct iwm_priv {
struct iwm_conf conf;
unsigned long status;
- unsigned long radio;
struct list_head pending_notif;
wait_queue_head_t notif_queue;
@@ -242,6 +231,7 @@ struct iwm_priv {
u8 bssid[ETH_ALEN];
u8 channel;
u16 rate;
+ u32 txpower;
struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM];
struct list_head bss_list;
@@ -276,12 +266,16 @@ struct iwm_priv {
struct iwm_tx_queue txq[IWM_TX_QUEUES];
struct iwm_key keys[IWM_NUM_KEYS];
- struct iwm_key *default_key;
+ s8 default_key;
+
+ DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX);
+ wait_queue_head_t wifi_ntfy_queue;
wait_queue_head_t mlme_queue;
struct iw_statistics wstats;
struct delayed_work stats_request;
+ struct delayed_work disconnect;
struct iwm_debugfs dbg;
@@ -289,7 +283,13 @@ struct iwm_priv {
struct timer_list watchdog;
struct work_struct reset_worker;
struct mutex mutex;
- struct rfkill *rfkill;
+
+ u8 *req_ie;
+ int req_ie_len;
+ u8 *resp_ie;
+ int resp_ie_len;
+
+ struct iwm_fw_error_hdr *last_fw_err;
char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
@@ -311,8 +311,6 @@ static inline void *iwm_private(struct iwm_priv *iwm)
#define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb))
#define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb)
-extern const struct iw_handler_def iwm_iw_handler_def;
-
void *iwm_if_alloc(int sizeof_bus, struct device *dev,
struct iwm_if_ops *if_ops);
void iwm_if_free(struct iwm_priv *iwm);
@@ -322,6 +320,7 @@ int iwm_mode_to_nl80211_iftype(int mode);
int iwm_priv_init(struct iwm_priv *iwm);
void iwm_priv_deinit(struct iwm_priv *iwm);
void iwm_reset(struct iwm_priv *iwm);
+void iwm_resetting(struct iwm_priv *iwm);
void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
struct iwm_umac_notif_alive *alive);
int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb);
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
index db2e5eea1895..6c1a14c4480f 100644
--- a/drivers/net/wireless/iwmc3200wifi/lmac.h
+++ b/drivers/net/wireless/iwmc3200wifi/lmac.h
@@ -396,6 +396,25 @@ enum {
CALIBRATION_CMD_NUM,
};
+enum {
+ CALIB_CFG_RX_BB_IDX = 0,
+ CALIB_CFG_DC_IDX = 1,
+ CALIB_CFG_LO_IDX = 2,
+ CALIB_CFG_TX_IQ_IDX = 3,
+ CALIB_CFG_RX_IQ_IDX = 4,
+ CALIB_CFG_NOISE_IDX = 5,
+ CALIB_CFG_CRYSTAL_IDX = 6,
+ CALIB_CFG_TEMPERATURE_IDX = 7,
+ CALIB_CFG_PAPD_IDX = 8,
+ CALIB_CFG_LAST_IDX = CALIB_CFG_PAPD_IDX,
+ CALIB_CFG_MODULE_NUM,
+};
+
+#define IWM_CALIB_MAP_INIT_MSK 0xFFFF
+#define IWM_CALIB_MAP_PER_LMAC(m) ((m & 0xFF0000) >> 16)
+#define IWM_CALIB_MAP_PER_UMAC(m) ((m & 0xFF000000) >> 24)
+#define IWM_CALIB_OPCODE_TO_INDEX(op) (op - PHY_CALIBRATE_OPCODES_NUM)
+
struct iwm_lmac_calib_hdr {
u8 opcode;
u8 first_grp;
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index 8be206d58222..d668e4756324 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -53,11 +53,12 @@
static struct iwm_conf def_iwm_conf = {
.sdio_ior_timeout = 5000,
- .init_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
- BIT(PHY_CALIBRATE_LO_CMD) |
- BIT(PHY_CALIBRATE_TX_IQ_CMD) |
- BIT(PHY_CALIBRATE_RX_IQ_CMD),
- .periodic_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
+ .calib_map = BIT(CALIB_CFG_DC_IDX) |
+ BIT(CALIB_CFG_LO_IDX) |
+ BIT(CALIB_CFG_TX_IQ_IDX) |
+ BIT(CALIB_CFG_RX_IQ_IDX) |
+ BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD),
+ .expected_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
BIT(PHY_CALIBRATE_LO_CMD) |
BIT(PHY_CALIBRATE_TX_IQ_CMD) |
BIT(PHY_CALIBRATE_RX_IQ_CMD) |
@@ -112,8 +113,28 @@ static void iwm_statistics_request(struct work_struct *work)
iwm_send_umac_stats_req(iwm, 0);
}
-int __iwm_up(struct iwm_priv *iwm);
-int __iwm_down(struct iwm_priv *iwm);
+static void iwm_disconnect_work(struct work_struct *work)
+{
+ struct iwm_priv *iwm =
+ container_of(work, struct iwm_priv, disconnect.work);
+
+ if (iwm->umac_profile_active)
+ iwm_invalidate_mlme_profile(iwm);
+
+ clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
+ iwm->umac_profile_active = 0;
+ memset(iwm->bssid, 0, ETH_ALEN);
+ iwm->channel = 0;
+
+ iwm_link_off(iwm);
+
+ wake_up_interruptible(&iwm->mlme_queue);
+
+ cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL);
+}
+
+static int __iwm_up(struct iwm_priv *iwm);
+static int __iwm_down(struct iwm_priv *iwm);
static void iwm_reset_worker(struct work_struct *work)
{
@@ -166,7 +187,8 @@ static void iwm_reset_worker(struct work_struct *work)
memcpy(iwm->umac_profile, profile, sizeof(*profile));
iwm_send_mlme_profile(iwm);
kfree(profile);
- }
+ } else
+ clear_bit(IWM_STATUS_RESETTING, &iwm->status);
out:
mutex_unlock(&iwm->mutex);
@@ -179,7 +201,7 @@ static void iwm_watchdog(unsigned long data)
IWM_WARN(iwm, "Watchdog expired: UMAC stalls!\n");
if (modparam_reset)
- schedule_work(&iwm->reset_worker);
+ iwm_resetting(iwm);
}
int iwm_priv_init(struct iwm_priv *iwm)
@@ -191,6 +213,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
INIT_LIST_HEAD(&iwm->pending_notif);
init_waitqueue_head(&iwm->notif_queue);
init_waitqueue_head(&iwm->nonwifi_queue);
+ init_waitqueue_head(&iwm->wifi_ntfy_queue);
init_waitqueue_head(&iwm->mlme_queue);
memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf));
spin_lock_init(&iwm->tx_credit.lock);
@@ -201,6 +224,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
spin_lock_init(&iwm->cmd_lock);
iwm->scan_id = 1;
INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request);
+ INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work);
INIT_WORK(&iwm->reset_worker, iwm_reset_worker);
INIT_LIST_HEAD(&iwm->bss_list);
@@ -229,13 +253,18 @@ int iwm_priv_init(struct iwm_priv *iwm)
for (i = 0; i < IWM_NUM_KEYS; i++)
memset(&iwm->keys[i], 0, sizeof(struct iwm_key));
- iwm->default_key = NULL;
+ iwm->default_key = -1;
init_timer(&iwm->watchdog);
iwm->watchdog.function = iwm_watchdog;
iwm->watchdog.data = (unsigned long)iwm;
mutex_init(&iwm->mutex);
+ iwm->last_fw_err = kzalloc(sizeof(struct iwm_fw_error_hdr),
+ GFP_KERNEL);
+ if (iwm->last_fw_err == NULL)
+ return -ENOMEM;
+
return 0;
}
@@ -247,6 +276,7 @@ void iwm_priv_deinit(struct iwm_priv *iwm)
destroy_workqueue(iwm->txq[i].wq);
destroy_workqueue(iwm->rx_wq);
+ kfree(iwm->last_fw_err);
}
/*
@@ -261,7 +291,11 @@ void iwm_reset(struct iwm_priv *iwm)
if (test_bit(IWM_STATUS_READY, &iwm->status))
iwm_target_reset(iwm);
- iwm->status = 0;
+ if (test_bit(IWM_STATUS_RESETTING, &iwm->status)) {
+ iwm->status = 0;
+ set_bit(IWM_STATUS_RESETTING, &iwm->status);
+ } else
+ iwm->status = 0;
iwm->scan_id = 1;
list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) {
@@ -277,6 +311,13 @@ void iwm_reset(struct iwm_priv *iwm)
iwm_link_off(iwm);
}
+void iwm_resetting(struct iwm_priv *iwm)
+{
+ set_bit(IWM_STATUS_RESETTING, &iwm->status);
+
+ schedule_work(&iwm->reset_worker);
+}
+
/*
* Notification code:
*
@@ -500,6 +541,13 @@ void iwm_link_off(struct iwm_priv *iwm)
memset(wstats, 0, sizeof(struct iw_statistics));
wstats->qual.updated = IW_QUAL_ALL_INVALID;
+ kfree(iwm->req_ie);
+ iwm->req_ie = NULL;
+ iwm->req_ie_len = 0;
+ kfree(iwm->resp_ie);
+ iwm->resp_ie = NULL;
+ iwm->resp_ie_len = 0;
+
del_timer_sync(&iwm->watchdog);
}
@@ -518,13 +566,6 @@ static int iwm_channels_init(struct iwm_priv *iwm)
{
int ret;
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (iwm->conf.hw_b0) {
- IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n");
- return 0;
- }
-#endif
-
ret = iwm_send_umac_channel_list(iwm);
if (ret) {
IWM_ERR(iwm, "Send channel list failed\n");
@@ -541,7 +582,7 @@ static int iwm_channels_init(struct iwm_priv *iwm)
return 0;
}
-int __iwm_up(struct iwm_priv *iwm)
+static int __iwm_up(struct iwm_priv *iwm)
{
int ret;
struct iwm_notif *notif_reboot, *notif_ack = NULL;
@@ -642,19 +683,10 @@ int __iwm_up(struct iwm_priv *iwm)
}
}
- iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
- GFP_KERNEL);
- if (!iwm->umac_profile) {
- IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
- goto err_fw;
- }
-
- iwm_init_default_profile(iwm, iwm->umac_profile);
-
ret = iwm_channels_init(iwm);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't init channels\n");
- goto err_profile;
+ goto err_fw;
}
/* Set the READY bit to indicate interface is brought up successfully */
@@ -662,10 +694,6 @@ int __iwm_up(struct iwm_priv *iwm)
return 0;
- err_profile:
- kfree(iwm->umac_profile);
- iwm->umac_profile = NULL;
-
err_fw:
iwm_eeprom_exit(iwm);
@@ -688,7 +716,7 @@ int iwm_up(struct iwm_priv *iwm)
return ret;
}
-int __iwm_down(struct iwm_priv *iwm)
+static int __iwm_down(struct iwm_priv *iwm)
{
int ret;
@@ -704,11 +732,10 @@ int __iwm_down(struct iwm_priv *iwm)
clear_bit(IWM_STATUS_READY, &iwm->status);
iwm_eeprom_exit(iwm);
- kfree(iwm->umac_profile);
- iwm->umac_profile = NULL;
iwm_bss_list_clean(iwm);
-
- iwm->default_key = NULL;
+ iwm_init_default_profile(iwm, iwm->umac_profile);
+ iwm->umac_profile_active = false;
+ iwm->default_key = -1;
iwm->core_enabled = 0;
ret = iwm_bus_disable(iwm);
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
index bf294e41753b..35ec006c2d2c 100644
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -48,29 +48,22 @@
#include <linux/netdevice.h>
#include "iwm.h"
+#include "commands.h"
#include "cfg80211.h"
#include "debug.h"
static int iwm_open(struct net_device *ndev)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
- int ret = 0;
-
- if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
- ret = iwm_up(iwm);
- return ret;
+ return iwm_up(iwm);
}
static int iwm_stop(struct net_device *ndev)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
- int ret = 0;
-
- if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
- ret = iwm_down(iwm);
- return ret;
+ return iwm_down(iwm);
}
/*
@@ -128,13 +121,24 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
}
ndev->netdev_ops = &iwm_netdev_ops;
- ndev->wireless_handlers = &iwm_iw_handler_def;
ndev->ieee80211_ptr = wdev;
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev;
+ iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
+ GFP_KERNEL);
+ if (!iwm->umac_profile) {
+ dev_err(dev, "Couldn't alloc memory for profile\n");
+ goto out_profile;
+ }
+
+ iwm_init_default_profile(iwm, iwm->umac_profile);
+
return iwm;
+ out_profile:
+ free_netdev(ndev);
+
out_priv:
iwm_priv_deinit(iwm);
@@ -150,6 +154,8 @@ void iwm_if_free(struct iwm_priv *iwm)
free_netdev(iwm_to_ndev(iwm));
iwm_priv_deinit(iwm);
+ kfree(iwm->umac_profile);
+ iwm->umac_profile = NULL;
iwm_wdev_free(iwm);
}
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index d73cf96c6dc6..40dbcbc16593 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -102,6 +102,7 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
error = (struct iwm_umac_notif_error *)buf;
fw_err = &error->err;
+ memcpy(iwm->last_fw_err, fw_err, sizeof(struct iwm_fw_error_hdr));
IWM_ERR(iwm, "%cMAC FW ERROR:\n",
(le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U');
@@ -119,6 +120,8 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status));
IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status));
+ iwm_resetting(iwm);
+
return 0;
}
@@ -143,17 +146,18 @@ static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
{
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
struct iwm_umac_notif_init_complete *init_complete =
(struct iwm_umac_notif_init_complete *)(buf);
u16 status = le16_to_cpu(init_complete->status);
+ bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR);
- if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) {
+ if (blocked)
IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n");
- set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
- } else {
+ else
IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n");
- clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
- }
+
+ wiphy_rfkill_set_hw_state(wiphy, blocked);
return 0;
}
@@ -218,17 +222,17 @@ static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf,
(buf + sizeof(struct iwm_umac_wifi_in_hdr));
hdr = (struct iwm_umac_wifi_in_hdr *)buf;
- IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
+ IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
- IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n",
- le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
- IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
- IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n",
- le16_to_cpu(tx_resp->retry_cnt));
- IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
- IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n",
- le16_to_cpu(tx_resp->byte_cnt));
- IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
+ IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n",
+ le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
+ IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
+ IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n",
+ le16_to_cpu(tx_resp->retry_cnt));
+ IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
+ IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n",
+ le16_to_cpu(tx_resp->byte_cnt));
+ IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
return 0;
}
@@ -418,8 +422,8 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
if (IS_ERR(ticket_node))
return PTR_ERR(ticket_node);
- IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n",
- ticket->id);
+ IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n",
+ ticket->id);
list_add_tail(&ticket_node->node, &iwm->rx_tickets);
/*
@@ -454,15 +458,15 @@ static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf,
u16 id, buf_offset;
u32 packet_size;
- IWM_DBG_NTF(iwm, DBG, "\n");
+ IWM_DBG_RX(iwm, DBG, "\n");
wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num);
buf_offset = sizeof(struct iwm_umac_wifi_in_hdr);
packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr);
- IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
- wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
+ IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
+ wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id);
IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size);
@@ -487,8 +491,6 @@ static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf,
start = (struct iwm_umac_notif_assoc_start *)buf;
- set_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
-
IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n",
start->bssid, le32_to_cpu(start->roam_reason));
@@ -503,43 +505,84 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
{
struct iwm_umac_notif_assoc_complete *complete =
(struct iwm_umac_notif_assoc_complete *)buf;
- union iwreq_data wrqu;
IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n",
complete->bssid, complete->status);
- memset(&wrqu, 0, sizeof(wrqu));
-
- clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
-
switch (le32_to_cpu(complete->status)) {
case UMAC_ASSOC_COMPLETE_SUCCESS:
set_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
memcpy(iwm->bssid, complete->bssid, ETH_ALEN);
iwm->channel = complete->channel;
+ /* Internal roaming state, avoid notifying SME. */
+ if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
+ && iwm->conf.mode == UMAC_MODE_BSS) {
+ cancel_delayed_work(&iwm->disconnect);
+ cfg80211_roamed(iwm_to_ndev(iwm),
+ complete->bssid,
+ iwm->req_ie, iwm->req_ie_len,
+ iwm->resp_ie, iwm->resp_ie_len,
+ GFP_KERNEL);
+ break;
+ }
+
iwm_link_on(iwm);
- memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN);
+ if (iwm->conf.mode == UMAC_MODE_IBSS)
+ goto ibss;
+
+ if (!test_bit(IWM_STATUS_RESETTING, &iwm->status))
+ cfg80211_connect_result(iwm_to_ndev(iwm),
+ complete->bssid,
+ iwm->req_ie, iwm->req_ie_len,
+ iwm->resp_ie, iwm->resp_ie_len,
+ WLAN_STATUS_SUCCESS,
+ GFP_KERNEL);
+ else
+ cfg80211_roamed(iwm_to_ndev(iwm),
+ complete->bssid,
+ iwm->req_ie, iwm->req_ie_len,
+ iwm->resp_ie, iwm->resp_ie_len,
+ GFP_KERNEL);
break;
case UMAC_ASSOC_COMPLETE_FAILURE:
clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
memset(iwm->bssid, 0, ETH_ALEN);
iwm->channel = 0;
+ /* Internal roaming state, avoid notifying SME. */
+ if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
+ && iwm->conf.mode == UMAC_MODE_BSS) {
+ cancel_delayed_work(&iwm->disconnect);
+ break;
+ }
+
iwm_link_off(iwm);
+
+ if (iwm->conf.mode == UMAC_MODE_IBSS)
+ goto ibss;
+
+ if (!test_bit(IWM_STATUS_RESETTING, &iwm->status))
+ cfg80211_connect_result(iwm_to_ndev(iwm),
+ complete->bssid,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
+ else
+ cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0,
+ GFP_KERNEL);
+ break;
default:
break;
}
- if (iwm->conf.mode == UMAC_MODE_IBSS) {
- cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
- return 0;
- }
-
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL);
+ clear_bit(IWM_STATUS_RESETTING, &iwm->status);
+ return 0;
+ ibss:
+ cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
+ clear_bit(IWM_STATUS_RESETTING, &iwm->status);
return 0;
}
@@ -548,13 +591,20 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf,
struct iwm_wifi_cmd *cmd)
{
struct iwm_umac_notif_profile_invalidate *invalid;
+ u32 reason;
invalid = (struct iwm_umac_notif_profile_invalidate *)buf;
+ reason = le32_to_cpu(invalid->reason);
+
+ IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", reason);
- IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n",
- le32_to_cpu(invalid->reason));
+ if (reason != UMAC_PROFILE_INVALID_REQUEST &&
+ test_bit(IWM_STATUS_SME_CONNECTING, &iwm->status))
+ cfg80211_connect_result(iwm_to_ndev(iwm), NULL, NULL, 0, NULL,
+ 0, WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
- clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
+ clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status);
clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
iwm->umac_profile_active = 0;
@@ -568,6 +618,19 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf,
return 0;
}
+#define IWM_DISCONNECT_INTERVAL (5 * HZ)
+
+static int iwm_mlme_connection_terminated(struct iwm_priv *iwm, u8 *buf,
+ unsigned long buf_size,
+ struct iwm_wifi_cmd *cmd)
+{
+ IWM_DBG_MLME(iwm, DBG, "Connection terminated\n");
+
+ schedule_delayed_work(&iwm->disconnect, IWM_DISCONNECT_INTERVAL);
+
+ return 0;
+}
+
static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
@@ -769,37 +832,47 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, struct iwm_wifi_cmd *cmd)
{
struct iwm_umac_notif_mgt_frame *mgt_frame =
- (struct iwm_umac_notif_mgt_frame *)buf;
+ (struct iwm_umac_notif_mgt_frame *)buf;
struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
u8 *ie;
- unsigned int event;
- union iwreq_data wrqu;
IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
le16_to_cpu(mgt_frame->len));
if (ieee80211_is_assoc_req(mgt->frame_control)) {
ie = mgt->u.assoc_req.variable;;
- event = IWEVASSOCREQIE;
+ iwm->req_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->req_ie);
+ iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
+ iwm->req_ie_len, GFP_KERNEL);
} else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
ie = mgt->u.reassoc_req.variable;;
- event = IWEVASSOCREQIE;
+ iwm->req_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->req_ie);
+ iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
+ iwm->req_ie_len, GFP_KERNEL);
} else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
ie = mgt->u.assoc_resp.variable;;
- event = IWEVASSOCRESPIE;
+ iwm->resp_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->resp_ie);
+ iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
+ iwm->resp_ie_len, GFP_KERNEL);
} else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
ie = mgt->u.reassoc_resp.variable;;
- event = IWEVASSOCRESPIE;
+ iwm->resp_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->resp_ie);
+ iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
+ iwm->resp_ie_len, GFP_KERNEL);
} else {
- IWM_ERR(iwm, "Unsupported management frame");
+ IWM_ERR(iwm, "Unsupported management frame: 0x%x",
+ le16_to_cpu(mgt->frame_control));
return 0;
}
- wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
-
- IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length);
- wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie);
-
return 0;
}
@@ -817,8 +890,7 @@ static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf,
case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE:
return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd);
case WIFI_IF_NTFY_CONNECTION_TERMINATED:
- IWM_DBG_MLME(iwm, DBG, "Connection terminated\n");
- break;
+ return iwm_mlme_connection_terminated(iwm, buf, buf_size, cmd);
case WIFI_IF_NTFY_SCAN_COMPLETE:
return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd);
case WIFI_IF_NTFY_STA_TABLE_CHANGE:
@@ -875,6 +947,7 @@ static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf,
/* UMAC passes rate info multiplies by 2 */
iwm->rate = max_rate >> 1;
}
+ iwm->txpower = le32_to_cpu(stats->tx_power);
wstats->status = 0;
@@ -922,13 +995,6 @@ static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf,
if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN)
return -EINVAL;
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (hdr_offset == IWM_EEPROM_SKU_CAP_OFF) {
- if (eeprom_proxy->buf[0] == 0xff)
- iwm->conf.hw_b0 = 1;
- }
-#endif
-
switch (hdr_type) {
case IWM_UMAC_CMD_EEPROM_TYPE_READ:
memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len);
@@ -993,12 +1059,17 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
(struct iwm_umac_wifi_if *)cmd->buf.payload;
IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
- "oid is %d\n", hdr->oid);
+ "oid is 0x%x\n", hdr->oid);
+
+ if (hdr->oid <= WIFI_IF_NTFY_MAX) {
+ set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
+ wake_up_interruptible(&iwm->wifi_ntfy_queue);
+ } else
+ return -EINVAL;
switch (hdr->oid) {
case UMAC_WIFI_IF_CMD_SET_PROFILE:
iwm->umac_profile_active = 1;
- wake_up_interruptible(&iwm->mlme_queue);
break;
default:
break;
@@ -1010,6 +1081,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, struct iwm_wifi_cmd *cmd)
{
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *)
(buf + sizeof(struct iwm_umac_wifi_in_hdr));
u32 flags = le32_to_cpu(state->flags);
@@ -1018,10 +1090,7 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
- if (flags & IWM_CARD_STATE_HW_DISABLED)
- set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
- else
- clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
+ wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED);
return 0;
}
@@ -1362,13 +1431,13 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
skb->dev = iwm_to_ndev(iwm);
skb->protocol = eth_type_trans(skb, ndev);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->ip_summed = CHECKSUM_NONE;
memset(skb->cb, 0, sizeof(skb->cb));
ndev->stats.rx_packets++;
ndev->stats.rx_bytes += skb->len;
- if (netif_rx(skb) == NET_RX_DROP) {
+ if (netif_rx_ni(skb) == NET_RX_DROP) {
IWM_ERR(iwm, "Packet dropped\n");
ndev->stats.rx_dropped++;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c
index 916681837fd2..8b1de84003ca 100644
--- a/drivers/net/wireless/iwmc3200wifi/sdio.c
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.c
@@ -65,6 +65,7 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/debugfs.h>
+#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
@@ -492,7 +493,8 @@ static void iwm_sdio_remove(struct sdio_func *func)
}
static const struct sdio_device_id iwm_sdio_ids[] = {
- { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, SDIO_DEVICE_ID_IWM) },
+ { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL,
+ SDIO_DEVICE_ID_INTEL_IWMC3200WIFI) },
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids);
@@ -506,11 +508,7 @@ static struct sdio_driver iwm_sdio_driver = {
static int __init iwm_sdio_init_module(void)
{
- int ret;
-
- ret = sdio_register_driver(&iwm_sdio_driver);
-
- return ret;
+ return sdio_register_driver(&iwm_sdio_driver);
}
static void __exit iwm_sdio_exit_module(void)
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h
index b3c156b08dda..aab6b6892e45 100644
--- a/drivers/net/wireless/iwmc3200wifi/sdio.h
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.h
@@ -39,9 +39,6 @@
#ifndef __IWM_SDIO_H__
#define __IWM_SDIO_H__
-#define SDIO_VENDOR_ID_INTEL 0x89
-#define SDIO_DEVICE_ID_IWM 0x1403
-
#define IWM_SDIO_DATA_ADDR 0x0
#define IWM_SDIO_INTR_ENABLE_ADDR 0x14
#define IWM_SDIO_INTR_STATUS_ADDR 0x13
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
index 4a95cce1f0a6..c5a14ae3160a 100644
--- a/drivers/net/wireless/iwmc3200wifi/umac.h
+++ b/drivers/net/wireless/iwmc3200wifi/umac.h
@@ -495,6 +495,8 @@ struct iwm_fw_alive_hdr {
#define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8
#define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9
+#define WIFI_IF_NTFY_MAX 0xff
+
/* Notification structures */
struct iwm_umac_notif_wifi_if {
struct iwm_umac_wifi_in_hdr hdr;
@@ -613,6 +615,7 @@ struct iwm_umac_notif_alive {
} __attribute__ ((packed));
struct iwm_umac_notif_init_complete {
+ struct iwm_umac_wifi_in_hdr hdr;
__le16 status;
__le16 reserved;
} __attribute__ ((packed));
@@ -641,6 +644,11 @@ struct iwm_fw_error_hdr {
__le32 umac_status;
__le32 lmac_status;
__le32 sdio_status;
+ __le32 dbm_sample_ctrl;
+ __le32 dbm_buf_base;
+ __le32 dbm_buf_end;
+ __le32 dbm_buf_write_ptr;
+ __le32 dbm_buf_cycle_cnt;
} __attribute__ ((packed));
struct iwm_umac_notif_error {
diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c
deleted file mode 100644
index 584c94d0f399..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/wext.c
+++ /dev/null
@@ -1,723 +0,0 @@
-/*
- * Intel Wireless Multicomm 3200 WiFi driver
- *
- * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
- * Samuel Ortiz <samuel.ortiz@intel.com>
- * Zhu Yi <yi.zhu@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/wireless.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <net/cfg80211.h>
-#include <net/iw_handler.h>
-
-#include "iwm.h"
-#include "umac.h"
-#include "commands.h"
-#include "debug.h"
-
-static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- struct iw_statistics *wstats = &iwm->wstats;
-
- if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
- memset(wstats, 0, sizeof(struct iw_statistics));
- wstats->qual.updated = IW_QUAL_ALL_INVALID;
- }
-
- return wstats;
-}
-
-static int iwm_wext_siwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- if (freq->flags == IW_FREQ_AUTO)
- return 0;
-
- /* frequency/channel can only be set in IBSS mode */
- if (iwm->conf.mode != UMAC_MODE_IBSS)
- return -EOPNOTSUPP;
-
- return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
-}
-
-static int iwm_wext_giwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- if (iwm->conf.mode == UMAC_MODE_IBSS)
- return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
-
- freq->e = 0;
- freq->m = iwm->channel;
-
- return 0;
-}
-
-static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- if (iwm->conf.mode == UMAC_MODE_IBSS)
- return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- if (is_zero_ether_addr(ap_addr->sa_data) ||
- is_broadcast_ether_addr(ap_addr->sa_data)) {
- IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
- iwm->umac_profile->bssid[0]);
- memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
- iwm->umac_profile->bss_num = 0;
- } else {
- IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
- ap_addr->sa_data);
- memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
- ETH_ALEN);
- iwm->umac_profile->bss_num = 1;
- }
-
- if (iwm->umac_profile_active) {
- if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
- return 0;
-
- iwm_invalidate_mlme_profile(iwm);
- }
-
- if (iwm->umac_profile->ssid.ssid_len)
- return iwm_send_mlme_profile(iwm);
-
- return 0;
-}
-
-static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- switch (iwm->conf.mode) {
- case UMAC_MODE_IBSS:
- return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
- case UMAC_MODE_BSS:
- if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
- ap_addr->sa_family = ARPHRD_ETHER;
- memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
- } else
- memset(&ap_addr->sa_data, 0, ETH_ALEN);
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_wext_siwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *ssid)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- size_t len = data->length;
- int ret;
-
- if (iwm->conf.mode == UMAC_MODE_IBSS)
- return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- if (len > 0 && ssid[len - 1] == '\0')
- len--;
-
- if (iwm->umac_profile_active) {
- if (iwm->umac_profile->ssid.ssid_len == len &&
- !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
- return 0;
-
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
- }
-
- iwm->umac_profile->ssid.ssid_len = len;
- memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
-
- return iwm_send_mlme_profile(iwm);
-}
-
-static int iwm_wext_giwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *ssid)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- if (iwm->conf.mode == UMAC_MODE_IBSS)
- return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- data->length = iwm->umac_profile->ssid.ssid_len;
- if (data->length) {
- memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
- data->flags = 1;
- } else
- data->flags = 0;
-
- return 0;
-}
-
-static struct iwm_key *
-iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use,
- struct iw_encode_ext *ext, u8 alg)
-{
- struct iwm_key *key = &iwm->keys[key_idx];
-
- memset(key, 0, sizeof(struct iwm_key));
- memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN);
- key->hdr.key_idx = key_idx;
- if (is_broadcast_ether_addr(ext->addr.sa_data))
- key->hdr.multicast = 1;
-
- key->in_use = in_use;
- key->flags = ext->ext_flags;
- key->alg = alg;
- key->key_len = ext->key_len;
- memcpy(key->key, ext->key, ext->key_len);
-
- return key;
-}
-
-static int iwm_wext_giwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rate, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- rate->value = iwm->rate * 1000000;
-
- return 0;
-}
-
-static int iwm_wext_siwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *key_buf)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- struct iwm_key *uninitialized_var(key);
- int idx, i, uninitialized_var(alg), remove = 0, ret;
-
- IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length);
- IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
-
- if (!iwm->umac_profile) {
- IWM_ERR(iwm, "UMAC profile not allocated yet\n");
- return -ENODEV;
- }
-
- if (erq->length == WLAN_KEY_LEN_WEP40) {
- alg = UMAC_CIPHER_TYPE_WEP_40;
- iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40;
- iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
- } else if (erq->length == WLAN_KEY_LEN_WEP104) {
- alg = UMAC_CIPHER_TYPE_WEP_104;
- iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104;
- iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104;
- }
-
- if (erq->flags & IW_ENCODE_RESTRICTED)
- iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- else
- iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;
-
- idx = erq->flags & IW_ENCODE_INDEX;
- if (idx == 0) {
- if (iwm->default_key)
- for (i = 0; i < IWM_NUM_KEYS; i++) {
- if (iwm->default_key == &iwm->keys[i]) {
- idx = i;
- break;
- }
- }
- else
- iwm->default_key = &iwm->keys[idx];
- } else if (idx < 1 || idx > 4) {
- return -EINVAL;
- } else
- idx--;
-
- if (erq->flags & IW_ENCODE_DISABLED)
- remove = 1;
- else if (erq->length == 0) {
- if (!iwm->keys[idx].in_use)
- return -EINVAL;
- iwm->default_key = &iwm->keys[idx];
- }
-
- if (erq->length) {
- key = &iwm->keys[idx];
- memset(key, 0, sizeof(struct iwm_key));
- memset(key->hdr.mac, 0xff, ETH_ALEN);
- key->hdr.key_idx = idx;
- key->hdr.multicast = 1;
- key->in_use = !remove;
- key->alg = alg;
- key->key_len = erq->length;
- memcpy(key->key, key_buf, erq->length);
-
- IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n",
- idx, !!iwm->default_key);
- }
-
- if (remove) {
- if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) {
- int j;
- for (j = 0; j < IWM_NUM_KEYS; j++)
- if (iwm->keys[j].in_use) {
- struct iwm_key *k = &iwm->keys[j];
-
- k->in_use = 0;
- ret = iwm_set_key(iwm, remove, 0, k);
- if (ret < 0)
- return ret;
- }
-
- iwm->umac_profile->sec.ucast_cipher =
- UMAC_CIPHER_TYPE_NONE;
- iwm->umac_profile->sec.mcast_cipher =
- UMAC_CIPHER_TYPE_NONE;
- iwm->umac_profile->sec.auth_type =
- UMAC_AUTH_TYPE_OPEN;
-
- return 0;
- } else {
- key->in_use = 0;
- return iwm_set_key(iwm, remove, 0, key);
- }
- }
-
- /*
- * If we havent set a profile yet, we cant set keys.
- * Keys will be pushed after we're associated.
- */
- if (!iwm->umac_profile_active)
- return 0;
-
- /*
- * If there is a current active profile, but no
- * default key, it's not worth trying to associate again.
- */
- if (!iwm->default_key)
- return 0;
-
- /*
- * Here we have an active profile, but a key setting changed.
- * We thus have to invalidate the current profile, and push the
- * new one. Keys will be pushed when association takes place.
- */
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
-
- return iwm_send_mlme_profile(iwm);
-}
-
-static int iwm_wext_giwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *key)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- int idx, i;
-
- idx = erq->flags & IW_ENCODE_INDEX;
- if (idx < 1 || idx > 4) {
- idx = -1;
- if (!iwm->default_key) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_NOKEY;
- return 0;
- } else
- for (i = 0; i < IWM_NUM_KEYS; i++) {
- if (iwm->default_key == &iwm->keys[i]) {
- idx = i;
- break;
- }
- }
- if (idx < 0)
- return -EINVAL;
- } else
- idx--;
-
- erq->flags = idx + 1;
-
- if (!iwm->keys[idx].in_use) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_DISABLED;
- return 0;
- }
-
- memcpy(key, iwm->keys[idx].key,
- min_t(int, erq->length, iwm->keys[idx].key_len));
- erq->length = iwm->keys[idx].key_len;
- erq->flags |= IW_ENCODE_ENABLED;
-
- if (iwm->umac_profile->mode == UMAC_MODE_BSS) {
- switch (iwm->umac_profile->sec.auth_type) {
- case UMAC_AUTH_TYPE_OPEN:
- erq->flags |= IW_ENCODE_OPEN;
- break;
- default:
- erq->flags |= IW_ENCODE_RESTRICTED;
- break;
- }
- }
-
- return 0;
-}
-
-static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
-{
- if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
- else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
- else
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
-
- return 0;
-}
-
-static int iwm_wext_siwpower(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- u32 power_index;
-
- if (wrq->disabled) {
- power_index = IWM_POWER_INDEX_MIN;
- goto set;
- } else
- power_index = IWM_POWER_INDEX_DEFAULT;
-
- switch (wrq->flags & IW_POWER_MODE) {
- case IW_POWER_ON:
- case IW_POWER_MODE:
- case IW_POWER_ALL_R:
- break;
- default:
- return -EINVAL;
- }
-
- set:
- if (power_index == iwm->conf.power_index)
- return 0;
-
- iwm->conf.power_index = power_index;
-
- return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
- CFG_POWER_INDEX, iwm->conf.power_index);
-}
-
-static int iwm_wext_giwpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN);
-
- return 0;
-}
-
-static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
-{
- u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
- if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
- *auth_type = UMAC_AUTH_TYPE_8021X;
- else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
- if (iwm->umac_profile->sec.flags &
- (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
- *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
- else
- *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- } else {
- IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
-{
- u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
- &iwm->umac_profile->sec.mcast_cipher;
-
- switch (cipher) {
- case IW_AUTH_CIPHER_NONE:
- *profile_cipher = UMAC_CIPHER_TYPE_NONE;
- break;
- case IW_AUTH_CIPHER_WEP40:
- *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
- break;
- case IW_AUTH_CIPHER_TKIP:
- *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
- break;
- case IW_AUTH_CIPHER_CCMP:
- *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
- break;
- case IW_AUTH_CIPHER_WEP104:
- *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
- break;
- default:
- IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
-{
- u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
- switch (auth_alg) {
- case IW_AUTH_ALG_OPEN_SYSTEM:
- *auth_type = UMAC_AUTH_TYPE_OPEN;
- break;
- case IW_AUTH_ALG_SHARED_KEY:
- if (iwm->umac_profile->sec.flags &
- (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
- if (*auth_type == UMAC_AUTH_TYPE_8021X)
- return -EINVAL;
- *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
- } else {
- *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- }
- break;
- case IW_AUTH_ALG_LEAP:
- default:
- IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_wext_siwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- int ret;
-
- if ((data->flags) &
- (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
- IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
- /* We need to invalidate the current profile */
- if (iwm->umac_profile_active) {
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
- }
- }
-
- switch (data->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- return iwm_set_wpa_version(iwm, data->value);
- break;
- case IW_AUTH_CIPHER_PAIRWISE:
- return iwm_set_cipher(iwm, data->value, 1);
- break;
- case IW_AUTH_CIPHER_GROUP:
- return iwm_set_cipher(iwm, data->value, 0);
- break;
- case IW_AUTH_KEY_MGMT:
- return iwm_set_key_mgt(iwm, data->value);
- break;
- case IW_AUTH_80211_AUTH_ALG:
- return iwm_set_auth_alg(iwm, data->value);
- break;
- default:
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_wext_giwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
-{
- return 0;
-}
-
-static int iwm_wext_siwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- struct iwm_key *key;
- struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
- int uninitialized_var(alg), idx, i, remove = 0;
-
- IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg);
- IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len);
- IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags);
- IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
- IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length);
-
- switch (ext->alg) {
- case IW_ENCODE_ALG_NONE:
- remove = 1;
- break;
- case IW_ENCODE_ALG_WEP:
- if (ext->key_len == WLAN_KEY_LEN_WEP40)
- alg = UMAC_CIPHER_TYPE_WEP_40;
- else if (ext->key_len == WLAN_KEY_LEN_WEP104)
- alg = UMAC_CIPHER_TYPE_WEP_104;
- else {
- IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len);
- return -EINVAL;
- }
-
- break;
- case IW_ENCODE_ALG_TKIP:
- alg = UMAC_CIPHER_TYPE_TKIP;
- break;
- case IW_ENCODE_ALG_CCMP:
- alg = UMAC_CIPHER_TYPE_CCMP;
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- idx = erq->flags & IW_ENCODE_INDEX;
-
- if (idx == 0) {
- if (iwm->default_key)
- for (i = 0; i < IWM_NUM_KEYS; i++) {
- if (iwm->default_key == &iwm->keys[i]) {
- idx = i;
- break;
- }
- }
- } else if (idx < 1 || idx > 4) {
- return -EINVAL;
- } else
- idx--;
-
- if (erq->flags & IW_ENCODE_DISABLED)
- remove = 1;
- else if ((erq->length == 0) ||
- (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
- iwm->default_key = &iwm->keys[idx];
- if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP)
- return iwm_set_tx_key(iwm, idx);
- }
-
- key = iwm_key_init(iwm, idx, !remove, ext, alg);
-
- return iwm_set_key(iwm, remove, !iwm->default_key, key);
-}
-
-static const iw_handler iwm_handlers[] =
-{
- (iw_handler) NULL, /* SIOCSIWCOMMIT */
- (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */
- (iw_handler) NULL, /* SIOCSIWNWID */
- (iw_handler) NULL, /* SIOCGIWNWID */
- (iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */
- (iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */
- (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */
- (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */
- (iw_handler) NULL, /* SIOCSIWSENS */
- (iw_handler) NULL, /* SIOCGIWSENS */
- (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
- (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */
- (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
- (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
- (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
- (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
- (iw_handler) NULL, /* SIOCSIWSPY */
- (iw_handler) NULL, /* SIOCGIWSPY */
- (iw_handler) NULL, /* SIOCSIWTHRSPY */
- (iw_handler) NULL, /* SIOCGIWTHRSPY */
- (iw_handler) iwm_wext_siwap, /* SIOCSIWAP */
- (iw_handler) iwm_wext_giwap, /* SIOCGIWAP */
- (iw_handler) NULL, /* SIOCSIWMLME */
- (iw_handler) NULL, /* SIOCGIWAPLIST */
- (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
- (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
- (iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */
- (iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */
- (iw_handler) NULL, /* SIOCSIWNICKN */
- (iw_handler) NULL, /* SIOCGIWNICKN */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* SIOCSIWRATE */
- (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */
- (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
- (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
- (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
- (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
- (iw_handler) NULL, /* SIOCSIWTXPOW */
- (iw_handler) NULL, /* SIOCGIWTXPOW */
- (iw_handler) NULL, /* SIOCSIWRETRY */
- (iw_handler) NULL, /* SIOCGIWRETRY */
- (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */
- (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */
- (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */
- (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* SIOCSIWGENIE */
- (iw_handler) NULL, /* SIOCGIWGENIE */
- (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */
- (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */
- (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */
- (iw_handler) NULL, /* SIOCGIWENCODEEXT */
- (iw_handler) NULL, /* SIOCSIWPMKSA */
- (iw_handler) NULL, /* -- hole -- */
-};
-
-const struct iw_handler_def iwm_iw_handler_def = {
- .num_standard = ARRAY_SIZE(iwm_handlers),
- .standard = (iw_handler *) iwm_handlers,
- .get_wireless_stats = iwm_get_wireless_stats,
-};
-
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index b9b374119033..dd8732611ba9 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -34,7 +34,8 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
*
* @param priv A pointer to struct lbs_private structure
* @param rates the buffer which keeps input and output
- * @param rates_size the size of rate1 buffer; new size of buffer on return
+ * @param rates_size the size of rates buffer; new size of buffer on return,
+ * which will be less than or equal to original rates_size
*
* @return 0 on success, or -1 on error
*/
@@ -42,42 +43,42 @@ static int get_common_rates(struct lbs_private *priv,
u8 *rates,
u16 *rates_size)
{
- u8 *card_rates = lbs_bg_rates;
- size_t num_card_rates = sizeof(lbs_bg_rates);
- int ret = 0, i, j;
- u8 tmp[30];
- size_t tmp_size = 0;
-
- /* For each rate in card_rates that exists in rate1, copy to tmp */
- for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
- for (j = 0; rates[j] && (j < *rates_size); j++) {
- if (rates[j] == card_rates[i])
- tmp[tmp_size++] = card_rates[i];
+ int i, j;
+ u8 intersection[MAX_RATES];
+ u16 intersection_size;
+ u16 num_rates = 0;
+
+ intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection));
+
+ /* Allow each rate from 'rates' that is supported by the hardware */
+ for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) {
+ for (j = 0; j < intersection_size && rates[j]; j++) {
+ if (rates[j] == lbs_bg_rates[i])
+ intersection[num_rates++] = rates[j];
}
}
lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
- lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
- lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
+ lbs_deb_hex(LBS_DEB_JOIN, "card rates ", lbs_bg_rates,
+ ARRAY_SIZE(lbs_bg_rates));
+ lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates);
lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
if (!priv->enablehwauto) {
- for (i = 0; i < tmp_size; i++) {
- if (tmp[i] == priv->cur_rate)
+ for (i = 0; i < num_rates; i++) {
+ if (intersection[i] == priv->cur_rate)
goto done;
}
lbs_pr_alert("Previously set fixed data rate %#x isn't "
"compatible with the network.\n", priv->cur_rate);
- ret = -1;
- goto done;
+ return -1;
}
- ret = 0;
done:
memset(rates, 0, *rates_size);
- *rates_size = min_t(int, tmp_size, *rates_size);
- memcpy(rates, tmp, *rates_size);
- return ret;
+ *rates_size = num_rates;
+ memcpy(rates, intersection, num_rates);
+ return 0;
}
@@ -129,7 +130,6 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
{
struct cmd_ds_802_11_authenticate cmd;
int ret = -1;
- DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
@@ -138,8 +138,7 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
cmd.authtype = iw_auth_to_ieee_auth(auth);
- lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
- print_mac(mac, bssid), cmd.authtype);
+ lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype);
ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
@@ -321,8 +320,8 @@ static int lbs_associate(struct lbs_private *priv,
rates = (struct mrvl_ie_rates_param_set *) pos;
rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
- memcpy(&rates->rates, &bss->rates, MAX_RATES);
- tmplen = MAX_RATES;
+ tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES);
+ memcpy(&rates->rates, &bss->rates, tmplen);
if (get_common_rates(priv, rates->rates, &tmplen)) {
ret = -1;
goto done;
@@ -342,8 +341,6 @@ static int lbs_associate(struct lbs_private *priv,
/* Firmware v9+ indicate authentication suites as a TLV */
if (priv->fwrelease >= 0x09000000) {
- DECLARE_MAC_BUF(mac);
-
auth = (struct mrvl_ie_auth_type *) pos;
auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
auth->header.len = cpu_to_le16(2);
@@ -351,8 +348,8 @@ static int lbs_associate(struct lbs_private *priv,
auth->auth = cpu_to_le16(tmpauth);
pos += sizeof(auth->header) + 2;
- lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
- print_mac(mac, bss->bssid), priv->secinfo.auth_mode);
+ lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
+ bss->bssid, priv->secinfo.auth_mode);
}
/* WPA/WPA2 IEs */
@@ -598,7 +595,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
/* Copy Data rates from the rates recorded in scan response */
memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
- ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES);
+ ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates));
memcpy(cmd.bss.rates, bss->rates, ratesize);
if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
@@ -1368,11 +1365,17 @@ static int assoc_helper_wpa_keys(struct lbs_private *priv,
if (ret)
goto out;
+ memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key,
+ sizeof(struct enc_key));
+
if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
assoc_req->flags = flags;
+
+ memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key,
+ sizeof(struct enc_key));
}
out:
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 811ffc3ef414..893a55ca344a 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -45,6 +45,8 @@ static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
ssize_t res;
+ if (!buf)
+ return -ENOMEM;
pos += snprintf(buf+pos, len-pos, "state = %s\n",
szStates[priv->connect_status]);
@@ -68,6 +70,8 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
char *buf = (char *)addr;
DECLARE_SSID_BUF(ssid);
struct bss_descriptor * iter_bss;
+ if (!buf)
+ return -ENOMEM;
pos += snprintf(buf+pos, len-pos,
"# | ch | rssi | bssid | cap | Qual | SSID \n");
@@ -110,6 +114,8 @@ static ssize_t lbs_sleepparams_write(struct file *file,
int p1, p2, p3, p4, p5, p6;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, user_buf, buf_size)) {
@@ -148,6 +154,8 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
struct sleep_params sp;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
if (ret)
@@ -433,6 +441,8 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
int ret;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
offval.offset = priv->mac_offset;
offval.value = 0;
@@ -457,6 +467,8 @@ static ssize_t lbs_rdmac_write(struct file *file,
ssize_t res, buf_size;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
@@ -481,6 +493,8 @@ static ssize_t lbs_wrmac_write(struct file *file,
struct lbs_offset_value offval;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
@@ -515,6 +529,8 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
int ret;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
offval.offset = priv->bbp_offset;
offval.value = 0;
@@ -540,6 +556,8 @@ static ssize_t lbs_rdbbp_write(struct file *file,
ssize_t res, buf_size;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
@@ -564,6 +582,8 @@ static ssize_t lbs_wrbbp_write(struct file *file,
struct lbs_offset_value offval;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
@@ -598,6 +618,8 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
int ret;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
offval.offset = priv->rf_offset;
offval.value = 0;
@@ -623,6 +645,8 @@ static ssize_t lbs_rdrf_write(struct file *file,
ssize_t res, buf_size;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
@@ -647,6 +671,8 @@ static ssize_t lbs_wrrf_write(struct file *file,
struct lbs_offset_value offval;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
@@ -853,6 +879,8 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
struct debug_data *d;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
p = buf;
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 0b84bdca0726..8b15380ae6e1 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -6,7 +6,7 @@
#ifndef _LBS_DECL_H_
#define _LBS_DECL_H_
-#include <linux/device.h>
+#include <linux/netdevice.h>
#include "defs.h"
@@ -41,7 +41,8 @@ u8 lbs_data_rate_to_fw_index(u32 rate);
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
int result);
-int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
+netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *dev);
int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *);
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index f9ec69e04734..d3b69a4b4b5e 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -14,7 +14,7 @@
#include "defs.h"
#include "hostcmd.h"
-extern struct ethtool_ops lbs_ethtool_ops;
+extern const struct ethtool_ops lbs_ethtool_ops;
#define MAX_BSSID_PER_CHANNEL 16
@@ -260,7 +260,6 @@ struct lbs_private {
u16 psmode; /* Wlan802_11PowermodeCAM=disable
Wlan802_11PowermodeMAX_PSP=enable */
u32 psstate;
- char ps_supported;
u8 needtowakeup;
struct assoc_request * pending_assoc_req;
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index b118a35ec605..039b555e4d76 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -183,7 +183,7 @@ static int lbs_ethtool_set_wol(struct net_device *dev,
return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL);
}
-struct ethtool_ops lbs_ethtool_ops = {
+const struct ethtool_ops lbs_ethtool_ops = {
.get_drvinfo = lbs_ethtool_get_drvinfo,
.get_eeprom = lbs_ethtool_get_eeprom,
.get_eeprom_len = lbs_ethtool_get_eeprom_len,
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 2a5b083bf9bd..62381768f2d5 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -59,6 +59,7 @@ struct if_cs_card {
struct pcmcia_device *p_dev;
struct lbs_private *priv;
void __iomem *iobase;
+ bool align_regs;
};
@@ -274,16 +275,25 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
#define IF_CS_PRODUCT_ID 0x0000001C
#define IF_CS_CF8385_B1_REV 0x12
#define IF_CS_CF8381_B3_REV 0x04
+#define IF_CS_CF8305_B1_REV 0x03
/*
* Used to detect other cards than CF8385 since their revisions of silicon
* doesn't match those from CF8385, eg. CF8381 B3 works with this driver.
*/
+#define CF8305_MANFID 0x02db
+#define CF8305_CARDID 0x8103
#define CF8381_MANFID 0x02db
#define CF8381_CARDID 0x6064
#define CF8385_MANFID 0x02df
#define CF8385_CARDID 0x8103
+static inline int if_cs_hw_is_cf8305(struct pcmcia_device *p_dev)
+{
+ return (p_dev->manf_id == CF8305_MANFID &&
+ p_dev->card_id == CF8305_CARDID);
+}
+
static inline int if_cs_hw_is_cf8381(struct pcmcia_device *p_dev)
{
return (p_dev->manf_id == CF8381_MANFID &&
@@ -556,7 +566,15 @@ static int if_cs_prog_helper(struct if_cs_card *card)
lbs_deb_enter(LBS_DEB_CS);
- scratch = if_cs_read8(card, IF_CS_SCRATCH);
+ /*
+ * This is the only place where an unaligned register access happens on
+ * the CF8305 card, therefore for the sake of speed of the driver, we do
+ * the alignment correction here.
+ */
+ if (card->align_regs)
+ scratch = if_cs_read16(card, IF_CS_SCRATCH) >> 8;
+ else
+ scratch = if_cs_read8(card, IF_CS_SCRATCH);
/* "If the value is 0x5a, the firmware is already
* downloaded successfully"
@@ -880,8 +898,24 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
p_dev->irq.AssignedIRQ, p_dev->io.BasePort1,
p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1);
+ /*
+ * Most of the libertas cards can do unaligned register access, but some
+ * weird ones can not. That's especially true for the CF8305 card.
+ */
+ card->align_regs = 0;
+
/* Check if we have a current silicon */
prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
+ if (if_cs_hw_is_cf8305(p_dev)) {
+ card->align_regs = 1;
+ if (prod_id < IF_CS_CF8305_B1_REV) {
+ lbs_pr_err("old chips like 8305 rev B3 "
+ "aren't supported\n");
+ ret = -ENODEV;
+ goto out2;
+ }
+ }
+
if (if_cs_hw_is_cf8381(p_dev) && prod_id < IF_CS_CF8381_B3_REV) {
lbs_pr_err("old chips like 8381 rev B3 aren't supported\n");
ret = -ENODEV;
@@ -896,7 +930,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
/* Load the firmware early, before calling into libertas.ko */
ret = if_cs_prog_helper(card);
- if (ret == 0)
+ if (ret == 0 && !if_cs_hw_is_cf8305(p_dev))
ret = if_cs_prog_real(card);
if (ret)
goto out2;
@@ -933,9 +967,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
goto out3;
}
- /* The firmware for the CF card supports powersave */
- priv->ps_supported = 1;
-
ret = 0;
goto out;
@@ -979,6 +1010,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev)
/********************************************************************/
static struct pcmcia_device_id if_cs_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
PCMCIA_DEVICE_NULL,
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 8cdb88c6ca28..485a8d406525 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -1039,9 +1039,6 @@ static int if_sdio_probe(struct sdio_func *func,
if (ret)
goto err_activate_card;
- if (priv->fwcapinfo & FW_CAPINFO_PS)
- priv->ps_supported = 1;
-
out:
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -1096,11 +1093,11 @@ static void if_sdio_remove(struct sdio_func *func)
lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
}
- card->priv->surpriseremoved = 1;
lbs_deb_sdio("call remove card\n");
lbs_stop_card(card->priv);
lbs_remove_card(card->priv);
+ card->priv->surpriseremoved = 1;
flush_workqueue(card->workqueue);
destroy_workqueue(card->workqueue);
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 6564282ce476..446e327180f8 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -376,7 +376,7 @@ static int spu_set_bus_mode(struct if_spi_card *card, u16 mode)
err = spu_read_u16(card, IF_SPI_SPU_BUS_MODE_REG, &rval);
if (err)
return err;
- if (rval != mode) {
+ if ((rval & 0xF) != mode) {
lbs_pr_err("Can't read bus mode register.\n");
return -EIO;
}
@@ -737,7 +737,7 @@ static int if_spi_c2h_data(struct if_spi_card *card)
goto out;
} else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
lbs_pr_err("%s: error: card has %d bytes of data, but "
- "our maximum skb size is %lu\n",
+ "our maximum skb size is %zu\n",
__func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
err = -EINVAL;
goto out;
@@ -1118,7 +1118,6 @@ static int __devinit if_spi_probe(struct spi_device *spi)
priv->card = card;
priv->hw_host_to_card = if_spi_host_to_card;
priv->fw_ready = 1;
- priv->ps_supported = 1;
/* Initialize interrupt handling stuff. */
card->run_thread = 1;
@@ -1171,12 +1170,13 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
lbs_deb_spi("libertas_spi_remove\n");
lbs_deb_enter(LBS_DEB_SPI);
- priv->surpriseremoved = 1;
lbs_stop_card(priv);
+ lbs_remove_card(priv); /* will call free_netdev */
+
+ priv->surpriseremoved = 1;
free_irq(spi->irq, card);
if_spi_terminate_spi_thread(card);
- lbs_remove_card(priv); /* will call free_netdev */
if (card->pdata->teardown)
card->pdata->teardown(spi);
free_if_spi_card(card);
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 1844c5adf6e9..92bc8c5f1ca2 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -181,13 +181,14 @@ static void if_usb_setup_firmware(struct lbs_private *priv)
wake_method.action = cpu_to_le16(CMD_ACT_GET);
if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
lbs_pr_info("Firmware does not seem to support PS mode\n");
+ priv->fwcapinfo &= ~FW_CAPINFO_PS;
} else {
if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
lbs_deb_usb("Firmware seems to support PS with wake-via-command\n");
- priv->ps_supported = 1;
} else {
/* The versions which boot up this way don't seem to
work even if we set it to the command interrupt */
+ priv->fwcapinfo &= ~FW_CAPINFO_PS;
lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
}
}
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 89575e448015..87b4e497faa2 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)
/* Allocate an Ethernet device and register it */
dev = alloc_etherdev(sizeof(struct lbs_private));
if (!dev) {
- lbs_pr_err("init ethX device failed\n");
+ lbs_pr_err("init wlanX device failed\n");
goto done;
}
priv = netdev_priv(dev);
@@ -1204,6 +1204,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
SET_NETDEV_DEV(dev, dmdev);
priv->rtap_net_dev = NULL;
+ strcpy(dev->name, "wlan%d");
lbs_deb_thread("Starting main thread...\n");
init_waitqueue_head(&priv->waitq);
@@ -1646,7 +1647,8 @@ static int lbs_rtap_stop(struct net_device *dev)
return 0;
}
-static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t lbs_rtap_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
netif_stop_queue(dev);
return NETDEV_TX_BUSY;
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index 160cfd8311c0..4c018f7a0a8d 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -57,19 +57,17 @@ static u32 convert_radiotap_rate_to_mv(u8 rate)
* @param skb A pointer to skb which includes TX packet
* @return 0 or -1
*/
-int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned long flags;
struct lbs_private *priv = dev->ml_priv;
struct txpd *txpd;
char *p802x_hdr;
uint16_t pkt_len;
- int ret;
+ netdev_tx_t ret = NETDEV_TX_OK;
lbs_deb_enter(LBS_DEB_TX);
- ret = NETDEV_TX_OK;
-
/* We need to protect against the queues being restarted before
we get round to stopping them */
spin_lock_irqsave(&priv->driver_lock, flags);
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 8bc1907458b1..be837a0d2517 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -712,7 +712,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
- if (!priv->ps_supported) {
+ if (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
if (vwrq->disabled)
return 0;
else
@@ -1728,6 +1728,8 @@ static int lbs_set_auth(struct net_device *dev,
}
switch (dwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_PRIVACY_INVOKED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
case IW_AUTH_TKIP_COUNTERMEASURES:
case IW_AUTH_CIPHER_PAIRWISE:
case IW_AUTH_CIPHER_GROUP:
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 10a99e26d392..019431d2f8a9 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -366,15 +366,35 @@ static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed)
return 0;
}
+static u64 lbtf_op_prepare_multicast(struct ieee80211_hw *hw,
+ int mc_count, struct dev_addr_list *mclist)
+{
+ struct lbtf_private *priv = hw->priv;
+ int i;
+
+ if (!mc_count || mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE)
+ return mc_count;
+
+ priv->nr_of_multicastmacaddr = mc_count;
+ for (i = 0; i < mc_count; i++) {
+ if (!mclist)
+ break;
+ memcpy(&priv->multicastlist[i], mclist->da_addr,
+ ETH_ALEN);
+ mclist = mclist->next;
+ }
+
+ return mc_count;
+}
+
#define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)
static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *new_flags,
- int mc_count, struct dev_mc_list *mclist)
+ u64 multicast)
{
struct lbtf_private *priv = hw->priv;
int old_mac_control = priv->mac_control;
- int i;
changed_flags &= SUPPORTED_FIF_FLAGS;
*new_flags &= SUPPORTED_FIF_FLAGS;
@@ -386,20 +406,12 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
else
priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
if (*new_flags & (FIF_ALLMULTI) ||
- mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) {
+ multicast > MRVDRV_MAX_MULTICAST_LIST_SIZE) {
priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
- } else if (mc_count) {
+ } else if (multicast) {
priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
- priv->nr_of_multicastmacaddr = mc_count;
- for (i = 0; i < mc_count; i++) {
- if (!mclist)
- break;
- memcpy(&priv->multicastlist[i], mclist->da_addr,
- ETH_ALEN);
- mclist = mclist->next;
- }
lbtf_cmd_set_mac_multicast_addr(priv);
} else {
priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE |
@@ -461,6 +473,7 @@ static const struct ieee80211_ops lbtf_ops = {
.add_interface = lbtf_op_add_interface,
.remove_interface = lbtf_op_remove_interface,
.config = lbtf_op_config,
+ .prepare_multicast = lbtf_op_prepare_multicast,
.configure_filter = lbtf_op_configure_filter,
.bss_info_changed = lbtf_op_bss_info_changed,
};
@@ -503,7 +516,8 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
skb_reserve(skb, 2);
}
- ieee80211_rx_irqsafe(priv->hw, skb, &stats);
+ memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
+ ieee80211_rx_irqsafe(priv->hw, skb);
return 0;
}
EXPORT_SYMBOL_GPL(lbtf_rx);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 7916ca3f84c8..896f532182f0 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -15,6 +15,8 @@
#include <linux/list.h>
#include <linux/spinlock.h>
+#include <net/dst.h>
+#include <net/xfrm.h>
#include <net/mac80211.h>
#include <net/ieee80211_radiotap.h>
#include <linux/if_arp.h>
@@ -310,11 +312,12 @@ struct hwsim_radiotap_hdr {
} __attribute__ ((packed));
-static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
/* TODO: allow packet injection */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -404,11 +407,19 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
rx_status.freq = data->channel->center_freq;
rx_status.band = data->channel->band;
rx_status.rate_idx = info->control.rates[0].idx;
- /* TODO: simulate signal strength (and optional packet drop) */
+ /* TODO: simulate real signal strength (and optional packet loss) */
+ rx_status.signal = -50;
if (data->ps != PS_DISABLED)
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+ /* release the skb's source info */
+ skb_orphan(skb);
+ skb_dst_drop(skb);
+ skb->mark = 0;
+ secpath_reset(skb);
+ nf_reset(skb);
+
/* Copy skb to all enabled radios that are on the current frequency */
spin_lock(&hwsim_radio_lock);
list_for_each_entry(data2, &hwsim_radios, list) {
@@ -430,7 +441,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr,
ETH_ALEN) == 0)
ack = true;
- ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(data2->hw, nskb);
}
spin_unlock(&hwsim_radio_lock);
@@ -571,9 +583,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
- unsigned int *total_flags,
- int mc_count,
- struct dev_addr_list *mc_list)
+ unsigned int *total_flags,u64 multicast)
{
struct mac80211_hwsim_data *data = hw->priv;
@@ -690,6 +700,74 @@ static int mac80211_hwsim_conf_tx(
return 0;
}
+#ifdef CONFIG_NL80211_TESTMODE
+/*
+ * This section contains example code for using netlink
+ * attributes with the testmode command in nl80211.
+ */
+
+/* These enums need to be kept in sync with userspace */
+enum hwsim_testmode_attr {
+ __HWSIM_TM_ATTR_INVALID = 0,
+ HWSIM_TM_ATTR_CMD = 1,
+ HWSIM_TM_ATTR_PS = 2,
+
+ /* keep last */
+ __HWSIM_TM_ATTR_AFTER_LAST,
+ HWSIM_TM_ATTR_MAX = __HWSIM_TM_ATTR_AFTER_LAST - 1
+};
+
+enum hwsim_testmode_cmd {
+ HWSIM_TM_CMD_SET_PS = 0,
+ HWSIM_TM_CMD_GET_PS = 1,
+};
+
+static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = {
+ [HWSIM_TM_ATTR_CMD] = { .type = NLA_U32 },
+ [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 },
+};
+
+static int hwsim_fops_ps_write(void *dat, u64 val);
+
+static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
+ void *data, int len)
+{
+ struct mac80211_hwsim_data *hwsim = hw->priv;
+ struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1];
+ struct sk_buff *skb;
+ int err, ps;
+
+ err = nla_parse(tb, HWSIM_TM_ATTR_MAX, data, len,
+ hwsim_testmode_policy);
+ if (err)
+ return err;
+
+ if (!tb[HWSIM_TM_ATTR_CMD])
+ return -EINVAL;
+
+ switch (nla_get_u32(tb[HWSIM_TM_ATTR_CMD])) {
+ case HWSIM_TM_CMD_SET_PS:
+ if (!tb[HWSIM_TM_ATTR_PS])
+ return -EINVAL;
+ ps = nla_get_u32(tb[HWSIM_TM_ATTR_PS]);
+ return hwsim_fops_ps_write(hwsim, ps);
+ case HWSIM_TM_CMD_GET_PS:
+ skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+ nla_total_size(sizeof(u32)));
+ if (!skb)
+ return -ENOMEM;
+ NLA_PUT_U32(skb, HWSIM_TM_ATTR_PS, hwsim->ps);
+ return cfg80211_testmode_reply(skb);
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ nla_put_failure:
+ kfree_skb(skb);
+ return -ENOBUFS;
+}
+#endif
+
static const struct ieee80211_ops mac80211_hwsim_ops =
{
.tx = mac80211_hwsim_tx,
@@ -703,6 +781,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
.sta_notify = mac80211_hwsim_sta_notify,
.set_tim = mac80211_hwsim_set_tim,
.conf_tx = mac80211_hwsim_conf_tx,
+ CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
};
@@ -757,7 +836,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
{
struct mac80211_hwsim_data *data = dat;
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
- DECLARE_MAC_BUF(buf);
struct sk_buff *skb;
struct ieee80211_pspoll *pspoll;
@@ -787,7 +865,6 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
struct ieee80211_vif *vif, int ps)
{
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
- DECLARE_MAC_BUF(buf);
struct sk_buff *skb;
struct ieee80211_hdr *hdr;
@@ -945,7 +1022,8 @@ static int __init init_mac80211_hwsim(void)
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT);
- hw->flags = IEEE80211_HW_MFP_CAPABLE;
+ hw->flags = IEEE80211_HW_MFP_CAPABLE |
+ IEEE80211_HW_SIGNAL_DBM;
/* ask mac80211 to reserve space for magic */
hw->vif_data_size = sizeof(struct hwsim_vif_priv);
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 83967afe0821..746532ebe5a8 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1,7 +1,8 @@
/*
- * drivers/net/wireless/mwl8k.c driver for Marvell TOPDOG 802.11 Wireless cards
+ * drivers/net/wireless/mwl8k.c
+ * Driver for Marvell TOPDOG 802.11 Wireless cards
*
- * Copyright (C) 2008 Marvell Semiconductor Inc.
+ * Copyright (C) 2008-2009 Marvell Semiconductor Inc.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -24,7 +25,7 @@
#define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver"
#define MWL8K_NAME KBUILD_MODNAME
-#define MWL8K_VERSION "0.9.1"
+#define MWL8K_VERSION "0.10"
MODULE_DESCRIPTION(MWL8K_DESC);
MODULE_VERSION(MWL8K_VERSION);
@@ -38,16 +39,14 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_table) = {
};
MODULE_DEVICE_TABLE(pci, mwl8k_table);
-#define IEEE80211_ADDR_LEN ETH_ALEN
-
/* Register definitions */
#define MWL8K_HIU_GEN_PTR 0x00000c10
-#define MWL8K_MODE_STA 0x0000005a
-#define MWL8K_MODE_AP 0x000000a5
+#define MWL8K_MODE_STA 0x0000005a
+#define MWL8K_MODE_AP 0x000000a5
#define MWL8K_HIU_INT_CODE 0x00000c14
-#define MWL8K_FWSTA_READY 0xf0f1f2f4
-#define MWL8K_FWAP_READY 0xf1f2f4a5
-#define MWL8K_INT_CODE_CMD_FINISHED 0x00000005
+#define MWL8K_FWSTA_READY 0xf0f1f2f4
+#define MWL8K_FWAP_READY 0xf1f2f4a5
+#define MWL8K_INT_CODE_CMD_FINISHED 0x00000005
#define MWL8K_HIU_SCRATCH 0x00000c40
/* Host->device communications */
@@ -56,11 +55,10 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table);
#define MWL8K_HIU_H2A_INTERRUPT_MASK 0x00000c20
#define MWL8K_HIU_H2A_INTERRUPT_CLEAR_SEL 0x00000c24
#define MWL8K_HIU_H2A_INTERRUPT_STATUS_MASK 0x00000c28
-#define MWL8K_H2A_INT_DUMMY (1 << 20)
-#define MWL8K_H2A_INT_RESET (1 << 15)
-#define MWL8K_H2A_INT_PS (1 << 2)
-#define MWL8K_H2A_INT_DOORBELL (1 << 1)
-#define MWL8K_H2A_INT_PPA_READY (1 << 0)
+#define MWL8K_H2A_INT_DUMMY (1 << 20)
+#define MWL8K_H2A_INT_RESET (1 << 15)
+#define MWL8K_H2A_INT_DOORBELL (1 << 1)
+#define MWL8K_H2A_INT_PPA_READY (1 << 0)
/* Device->host communications */
#define MWL8K_HIU_A2H_INTERRUPT_EVENTS 0x00000c2c
@@ -68,16 +66,16 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table);
#define MWL8K_HIU_A2H_INTERRUPT_MASK 0x00000c34
#define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38
#define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c
-#define MWL8K_A2H_INT_DUMMY (1 << 20)
-#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11)
-#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10)
-#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7)
-#define MWL8K_A2H_INT_RADIO_ON (1 << 6)
-#define MWL8K_A2H_INT_RADIO_OFF (1 << 5)
-#define MWL8K_A2H_INT_MAC_EVENT (1 << 3)
-#define MWL8K_A2H_INT_OPC_DONE (1 << 2)
-#define MWL8K_A2H_INT_RX_READY (1 << 1)
-#define MWL8K_A2H_INT_TX_DONE (1 << 0)
+#define MWL8K_A2H_INT_DUMMY (1 << 20)
+#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11)
+#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10)
+#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7)
+#define MWL8K_A2H_INT_RADIO_ON (1 << 6)
+#define MWL8K_A2H_INT_RADIO_OFF (1 << 5)
+#define MWL8K_A2H_INT_MAC_EVENT (1 << 3)
+#define MWL8K_A2H_INT_OPC_DONE (1 << 2)
+#define MWL8K_A2H_INT_RX_READY (1 << 1)
+#define MWL8K_A2H_INT_TX_DONE (1 << 0)
#define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \
MWL8K_A2H_INT_CHNL_SWITCHED | \
@@ -113,17 +111,6 @@ struct mwl8k_rx_queue {
struct sk_buff **rx_skb;
};
-struct mwl8k_skb {
- /*
- * The DMA engine requires a modification to the payload.
- * If the skbuff is shared/cloned, it needs to be unshared.
- * This method is used to ensure the stack always gets back
- * the skbuff it sent for transmission.
- */
- struct sk_buff *clone;
- struct sk_buff *skb;
-};
-
struct mwl8k_tx_queue {
/* hw transmits here */
int tx_head;
@@ -134,7 +121,7 @@ struct mwl8k_tx_queue {
struct ieee80211_tx_queue_stats tx_stats;
struct mwl8k_tx_desc *tx_desc_area;
dma_addr_t tx_desc_dma;
- struct mwl8k_skb *tx_skb;
+ struct sk_buff **tx_skb;
};
/* Pointers to the firmware data and meta information about it. */
@@ -152,19 +139,22 @@ struct mwl8k_priv {
struct pci_dev *pdev;
u8 name[16];
- /* firmware access lock */
- spinlock_t fw_lock;
/* firmware files and meta data */
struct mwl8k_firmware fw;
u32 part_num;
+ /* firmware access */
+ struct mutex fw_mutex;
+ struct task_struct *fw_mutex_owner;
+ int fw_mutex_depth;
+ struct completion *tx_wait;
+ struct completion *hostcmd_wait;
+
/* lock held over TX and TX reap */
spinlock_t tx_lock;
- u32 int_mask;
struct ieee80211_vif *vif;
- struct list_head vif_list;
struct ieee80211_channel *current_channel;
@@ -173,10 +163,8 @@ struct mwl8k_priv {
dma_addr_t cookie_dma;
u16 num_mcaddrs;
- u16 region_code;
u8 hw_rev;
- __le32 fw_rev;
- u32 wep_enabled;
+ u32 fw_rev;
/*
* Running count of TX packets in flight, to avoid
@@ -192,19 +180,13 @@ struct mwl8k_priv {
struct ieee80211_channel channels[14];
struct ieee80211_rate rates[12];
- /* RF preamble: Short, Long or Auto */
- u8 radio_preamble;
- u8 radio_state;
-
- /* WMM MODE 1 for enabled; 0 for disabled */
- bool wmm_mode;
-
- /* Set if PHY config is in progress */
- bool inconfig;
+ bool radio_on;
+ bool radio_short_preamble;
+ bool wmm_enabled;
/* XXX need to convert this to handle multiple interfaces */
bool capture_beacon;
- u8 capture_bssid[IEEE80211_ADDR_LEN];
+ u8 capture_bssid[ETH_ALEN];
struct sk_buff *beacon_skb;
/*
@@ -220,14 +202,10 @@ struct mwl8k_priv {
/* Work thread to serialize configuration requests */
struct workqueue_struct *config_wq;
- struct completion *hostcmd_wait;
- struct completion *tx_wait;
};
/* Per interface specific private data */
struct mwl8k_vif {
- struct list_head node;
-
/* backpointer to parent config block */
struct mwl8k_priv *priv;
@@ -235,8 +213,8 @@ struct mwl8k_vif {
struct ieee80211_bss_conf bss_info;
/* BSSID of AP or IBSS */
- u8 bssid[IEEE80211_ADDR_LEN];
- u8 mac_addr[IEEE80211_ADDR_LEN];
+ u8 bssid[ETH_ALEN];
+ u8 mac_addr[ETH_ALEN];
/*
* Subset of supported legacy rates.
@@ -247,18 +225,11 @@ struct mwl8k_vif {
/* number of supported legacy rates */
u8 legacy_nrates;
- /* Number of supported MCS rates. Work in progress */
- u8 mcs_nrates;
-
/* Index into station database.Returned by update_sta_db call */
u8 peer_id;
/* Non AMPDU sequence number assigned by driver */
u16 seqno;
-
- /* Note:There is no channel info,
- * refer to the master channel info in priv
- */
};
#define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv))
@@ -292,28 +263,6 @@ static const struct ieee80211_rate mwl8k_rates[] = {
{ .bitrate = 540, .hw_value = 108, },
};
-/* Radio settings */
-#define MWL8K_RADIO_FORCE 0x2
-#define MWL8K_RADIO_ENABLE 0x1
-#define MWL8K_RADIO_DISABLE 0x0
-#define MWL8K_RADIO_AUTO_PREAMBLE 0x0005
-#define MWL8K_RADIO_SHORT_PREAMBLE 0x0003
-#define MWL8K_RADIO_LONG_PREAMBLE 0x0001
-
-/* WMM */
-#define MWL8K_WMM_ENABLE 1
-#define MWL8K_WMM_DISABLE 0
-
-#define MWL8K_RADIO_DEFAULT_PREAMBLE MWL8K_RADIO_LONG_PREAMBLE
-
-/* Slot time */
-
-/* Short Slot: 9us slot time */
-#define MWL8K_SHORT_SLOTTIME 1
-
-/* Long slot: 20us slot time */
-#define MWL8K_LONG_SLOTTIME 0
-
/* Set or get info from Firmware */
#define MWL8K_CMD_SET 0x0001
#define MWL8K_CMD_GET 0x0000
@@ -323,25 +272,23 @@ static const struct ieee80211_rate mwl8k_rates[] = {
#define MWL8K_CMD_GET_HW_SPEC 0x0003
#define MWL8K_CMD_MAC_MULTICAST_ADR 0x0010
#define MWL8K_CMD_GET_STAT 0x0014
-#define MWL8K_CMD_RADIO_CONTROL 0x001C
-#define MWL8K_CMD_RF_TX_POWER 0x001E
+#define MWL8K_CMD_RADIO_CONTROL 0x001c
+#define MWL8K_CMD_RF_TX_POWER 0x001e
#define MWL8K_CMD_SET_PRE_SCAN 0x0107
#define MWL8K_CMD_SET_POST_SCAN 0x0108
-#define MWL8K_CMD_SET_RF_CHANNEL 0x010A
+#define MWL8K_CMD_SET_RF_CHANNEL 0x010a
+#define MWL8K_CMD_SET_AID 0x010d
+#define MWL8K_CMD_SET_RATE 0x0110
+#define MWL8K_CMD_SET_FINALIZE_JOIN 0x0111
+#define MWL8K_CMD_RTS_THRESHOLD 0x0113
#define MWL8K_CMD_SET_SLOT 0x0114
+#define MWL8K_CMD_SET_EDCA_PARAMS 0x0115
+#define MWL8K_CMD_SET_WMM_MODE 0x0123
#define MWL8K_CMD_MIMO_CONFIG 0x0125
+#define MWL8K_CMD_USE_FIXED_RATE 0x0126
#define MWL8K_CMD_ENABLE_SNIFFER 0x0150
-#define MWL8K_CMD_SET_WMM_MODE 0x0123
-#define MWL8K_CMD_SET_EDCA_PARAMS 0x0115
-#define MWL8K_CMD_SET_FINALIZE_JOIN 0x0111
-#define MWL8K_CMD_UPDATE_STADB 0x1123
#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203
-#define MWL8K_CMD_SET_LINKADAPT_MODE 0x0129
-#define MWL8K_CMD_SET_AID 0x010d
-#define MWL8K_CMD_SET_RATE 0x0110
-#define MWL8K_CMD_USE_FIXED_RATE 0x0126
-#define MWL8K_CMD_RTS_THRESHOLD 0x0113
-#define MWL8K_CMD_ENCRYPTION 0x1122
+#define MWL8K_CMD_UPDATE_STADB 0x1123
static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
{
@@ -349,7 +296,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
snprintf(buf, bufsize, "%s", #x);\
return buf;\
} while (0)
- switch (cmd & (~0x8000)) {
+ switch (cmd & ~0x8000) {
MWL8K_CMDNAME(CODE_DNLD);
MWL8K_CMDNAME(GET_HW_SPEC);
MWL8K_CMDNAME(MAC_MULTICAST_ADR);
@@ -359,20 +306,18 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
MWL8K_CMDNAME(SET_PRE_SCAN);
MWL8K_CMDNAME(SET_POST_SCAN);
MWL8K_CMDNAME(SET_RF_CHANNEL);
+ MWL8K_CMDNAME(SET_AID);
+ MWL8K_CMDNAME(SET_RATE);
+ MWL8K_CMDNAME(SET_FINALIZE_JOIN);
+ MWL8K_CMDNAME(RTS_THRESHOLD);
MWL8K_CMDNAME(SET_SLOT);
+ MWL8K_CMDNAME(SET_EDCA_PARAMS);
+ MWL8K_CMDNAME(SET_WMM_MODE);
MWL8K_CMDNAME(MIMO_CONFIG);
+ MWL8K_CMDNAME(USE_FIXED_RATE);
MWL8K_CMDNAME(ENABLE_SNIFFER);
- MWL8K_CMDNAME(SET_WMM_MODE);
- MWL8K_CMDNAME(SET_EDCA_PARAMS);
- MWL8K_CMDNAME(SET_FINALIZE_JOIN);
- MWL8K_CMDNAME(UPDATE_STADB);
MWL8K_CMDNAME(SET_RATEADAPT_MODE);
- MWL8K_CMDNAME(SET_LINKADAPT_MODE);
- MWL8K_CMDNAME(SET_AID);
- MWL8K_CMDNAME(SET_RATE);
- MWL8K_CMDNAME(USE_FIXED_RATE);
- MWL8K_CMDNAME(RTS_THRESHOLD);
- MWL8K_CMDNAME(ENCRYPTION);
+ MWL8K_CMDNAME(UPDATE_STADB);
default:
snprintf(buf, bufsize, "0x%x", cmd);
}
@@ -466,7 +411,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
{
void __iomem *regs = priv->regs;
dma_addr_t dma_addr;
- int rc;
int loops;
dma_addr = pci_map_single(priv->pdev, data, length, PCI_DMA_TODEVICE);
@@ -480,7 +424,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
iowrite32(MWL8K_H2A_INT_DUMMY,
regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
- rc = -ETIMEDOUT;
loops = 1000;
do {
u32 int_code;
@@ -488,7 +431,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
int_code = ioread32(regs + MWL8K_HIU_INT_CODE);
if (int_code == MWL8K_INT_CODE_CMD_FINISHED) {
iowrite32(0, regs + MWL8K_HIU_INT_CODE);
- rc = 0;
break;
}
@@ -497,26 +439,7 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
pci_unmap_single(priv->pdev, dma_addr, length, PCI_DMA_TODEVICE);
- /*
- * Clear 'command done' interrupt bit.
- */
- loops = 1000;
- do {
- u32 status;
-
- status = ioread32(priv->regs +
- MWL8K_HIU_A2H_INTERRUPT_STATUS);
- if (status & MWL8K_A2H_INT_OPC_DONE) {
- iowrite32(~MWL8K_A2H_INT_OPC_DONE,
- priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
- ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
- break;
- }
-
- udelay(1);
- } while (--loops);
-
- return rc;
+ return loops ? 0 : -ETIMEDOUT;
}
static int mwl8k_load_fw_image(struct mwl8k_priv *priv,
@@ -681,11 +604,9 @@ struct ewc_ht_info {
/* Peer Entry flags - used to define the type of the peer node */
#define MWL8K_PEER_TYPE_ACCESSPOINT 2
-#define MWL8K_PEER_TYPE_ADHOC_STATION 4
#define MWL8K_IEEE_LEGACY_DATA_RATES 12
#define MWL8K_MCS_BITMAP_SIZE 16
-#define pad_size 16
struct peer_capability_info {
/* Peer type - AP vs. STA. */
@@ -707,7 +628,7 @@ struct peer_capability_info {
/* HT rate table. Intersection of our rates and peer rates. */
__u8 ht_rates[MWL8K_MCS_BITMAP_SIZE];
- __u8 pad[pad_size];
+ __u8 pad[16];
/* If set, interoperability mode, no proprietary extensions. */
__u8 interop;
@@ -717,15 +638,6 @@ struct peer_capability_info {
} __attribute__((packed));
/* Inline functions to manipulate QoS field in data descriptor. */
-static inline u16 mwl8k_qos_setbit_tid(u16 qos, u8 tid)
-{
- u16 val_mask = 0x000f;
- u16 qos_mask = ~val_mask;
-
- /* TID bits 0-3 */
- return (qos & qos_mask) | (tid & val_mask);
-}
-
static inline u16 mwl8k_qos_setbit_eosp(u16 qos)
{
u16 val_mask = 1 << 4;
@@ -769,12 +681,11 @@ struct mwl8k_dma_data {
} __attribute__((packed));
/* Routines to add/remove DMA header from skb. */
-static inline int mwl8k_remove_dma_header(struct sk_buff *skb)
+static inline void mwl8k_remove_dma_header(struct sk_buff *skb)
{
- struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)(skb->data);
+ struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)skb->data;
void *dst, *src = &tr->wh;
- __le16 fc = tr->wh.frame_control;
- int hdrlen = ieee80211_hdrlen(fc);
+ int hdrlen = ieee80211_hdrlen(tr->wh.frame_control);
u16 space = sizeof(struct mwl8k_dma_data) - hdrlen;
dst = (void *)tr + space;
@@ -782,11 +693,9 @@ static inline int mwl8k_remove_dma_header(struct sk_buff *skb)
memmove(dst, src, hdrlen);
skb_pull(skb, space);
}
-
- return 0;
}
-static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb)
+static inline void mwl8k_add_dma_header(struct sk_buff *skb)
{
struct ieee80211_hdr *wh;
u32 hdrlen, pktlen;
@@ -810,7 +719,7 @@ static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb)
memmove(&tr->wh, wh, hdrlen);
/* Clear addr4 */
- memset(tr->wh.addr4, 0, IEEE80211_ADDR_LEN);
+ memset(tr->wh.addr4, 0, ETH_ALEN);
/*
* Firmware length is the length of the fully formed "802.11
@@ -818,17 +727,13 @@ static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb)
* This includes all crypto material including the MIC.
*/
tr->fwlen = cpu_to_le16(pktlen - hdrlen);
-
- return skb;
}
/*
* Packet reception.
*/
-#define MWL8K_RX_CTRL_KEY_INDEX_MASK 0x30
#define MWL8K_RX_CTRL_OWNED_BY_HOST 0x02
-#define MWL8K_RX_CTRL_AMPDU 0x01
struct mwl8k_rx_desc {
__le16 pkt_len;
@@ -979,7 +884,7 @@ static inline void mwl8k_save_beacon(struct mwl8k_priv *priv,
struct sk_buff *skb)
{
priv->capture_beacon = false;
- memset(priv->capture_bssid, 0, IEEE80211_ADDR_LEN);
+ memset(priv->capture_bssid, 0, ETH_ALEN);
/*
* Use GFP_ATOMIC as rxq_process is called from
@@ -1024,10 +929,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
skb_put(skb, le16_to_cpu(rx_desc->pkt_len));
- if (mwl8k_remove_dma_header(skb)) {
- dev_kfree_skb(skb);
- continue;
- }
+ mwl8k_remove_dma_header(skb);
wh = (struct ieee80211_hdr *)skb->data;
@@ -1049,7 +951,8 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
status.flag = 0;
status.band = IEEE80211_BAND_2GHZ;
status.freq = ieee80211_channel_to_frequency(rx_desc->channel);
- ieee80211_rx_irqsafe(hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(hw, skb);
processed++;
}
@@ -1072,8 +975,6 @@ enum {
/* Transmit packet ACK policy */
#define MWL8K_TXD_ACK_POLICY_NORMAL 0
-#define MWL8K_TXD_ACK_POLICY_NONE 1
-#define MWL8K_TXD_ACK_POLICY_NO_EXPLICIT 2
#define MWL8K_TXD_ACK_POLICY_BLOCKACK 3
#define GET_TXQ(_ac) (\
@@ -1082,20 +983,11 @@ enum {
((_ac) == WME_AC_BK) ? MWL8K_WME_AC_BK : \
MWL8K_WME_AC_BE)
-#define MWL8K_TXD_STATUS_IDLE 0x00000000
-#define MWL8K_TXD_STATUS_USED 0x00000001
#define MWL8K_TXD_STATUS_OK 0x00000001
#define MWL8K_TXD_STATUS_OK_RETRY 0x00000002
#define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004
#define MWL8K_TXD_STATUS_MULTICAST_TX 0x00000008
-#define MWL8K_TXD_STATUS_BROADCAST_TX 0x00000010
-#define MWL8K_TXD_STATUS_FAILED_LINK_ERROR 0x00000020
-#define MWL8K_TXD_STATUS_FAILED_EXCEED_LIMIT 0x00000040
-#define MWL8K_TXD_STATUS_FAILED_AGING 0x00000080
-#define MWL8K_TXD_STATUS_HOST_CMD 0x40000000
#define MWL8K_TXD_STATUS_FW_OWNED 0x80000000
-#define MWL8K_TXD_SOFTSTALE 0x80
-#define MWL8K_TXD_SOFTSTALE_MGMT_RETRY 0x01
struct mwl8k_tx_desc {
__le32 status;
@@ -1104,7 +996,7 @@ struct mwl8k_tx_desc {
__le16 qos_control;
__le32 pkt_phys_addr;
__le16 pkt_len;
- __u8 dest_MAC_addr[IEEE80211_ADDR_LEN];
+ __u8 dest_MAC_addr[ETH_ALEN];
__le32 next_tx_desc_phys_addr;
__le32 reserved;
__le16 rate_info;
@@ -1121,8 +1013,7 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index)
int size;
int i;
- memset(&txq->tx_stats, 0,
- sizeof(struct ieee80211_tx_queue_stats));
+ memset(&txq->tx_stats, 0, sizeof(struct ieee80211_tx_queue_stats));
txq->tx_stats.limit = MWL8K_TX_DESCS;
txq->tx_head = 0;
txq->tx_tail = 0;
@@ -1189,17 +1080,17 @@ struct mwl8k_txq_info {
};
static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
- struct mwl8k_txq_info txinfo[],
- u32 num_queues)
+ struct mwl8k_txq_info *txinfo)
{
int count, desc, status;
struct mwl8k_tx_queue *txq;
struct mwl8k_tx_desc *tx_desc;
int ndescs = 0;
- memset(txinfo, 0, num_queues * sizeof(struct mwl8k_txq_info));
+ memset(txinfo, 0, MWL8K_TX_QUEUES * sizeof(struct mwl8k_txq_info));
+
spin_lock_bh(&priv->tx_lock);
- for (count = 0; count < num_queues; count++) {
+ for (count = 0; count < MWL8K_TX_QUEUES; count++) {
txq = priv->txq + count;
txinfo[count].len = txq->tx_stats.len;
txinfo[count].head = txq->tx_head;
@@ -1222,34 +1113,34 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
return ndescs;
}
-static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms)
+/*
+ * Must be called with hw->fw_mutex held and tx queues stopped.
+ */
+static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
{
- u32 count = 0;
- unsigned long timeout = 0;
struct mwl8k_priv *priv = hw->priv;
DECLARE_COMPLETION_ONSTACK(cmd_wait);
+ u32 count;
+ unsigned long timeout;
might_sleep();
- if (priv->tx_wait != NULL)
- printk(KERN_ERR "WARNING Previous TXWaitEmpty instance\n");
-
spin_lock_bh(&priv->tx_lock);
count = mwl8k_txq_busy(priv);
if (count) {
priv->tx_wait = &cmd_wait;
- if (priv->radio_state)
+ if (priv->radio_on)
mwl8k_tx_start(priv);
}
spin_unlock_bh(&priv->tx_lock);
if (count) {
- struct mwl8k_txq_info txinfo[4];
+ struct mwl8k_txq_info txinfo[MWL8K_TX_QUEUES];
int index;
int newcount;
timeout = wait_for_completion_timeout(&cmd_wait,
- msecs_to_jiffies(delay_ms));
+ msecs_to_jiffies(5000));
if (timeout)
return 0;
@@ -1258,11 +1149,11 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms)
newcount = mwl8k_txq_busy(priv);
spin_unlock_bh(&priv->tx_lock);
- printk(KERN_ERR "%s(%u) TIMEDOUT:%ums Pend:%u-->%u\n",
- __func__, __LINE__, delay_ms, count, newcount);
+ printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n",
+ __func__, __LINE__, count, newcount);
- mwl8k_scan_tx_ring(priv, txinfo, 4);
- for (index = 0 ; index < 4; index++)
+ mwl8k_scan_tx_ring(priv, txinfo);
+ for (index = 0; index < MWL8K_TX_QUEUES; index++)
printk(KERN_ERR
"TXQ:%u L:%u H:%u T:%u FW:%u DRV:%u U:%u\n",
index,
@@ -1272,18 +1163,17 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms)
txinfo[index].fw_owned,
txinfo[index].drv_owned,
txinfo[index].unused);
+
return -ETIMEDOUT;
}
return 0;
}
-#define MWL8K_TXD_OK (MWL8K_TXD_STATUS_OK | \
- MWL8K_TXD_STATUS_OK_RETRY | \
- MWL8K_TXD_STATUS_OK_MORE_RETRY)
-#define MWL8K_TXD_SUCCESS(stat) ((stat) & MWL8K_TXD_OK)
-#define MWL8K_TXD_FAIL_RETRY(stat) \
- ((stat) & (MWL8K_TXD_STATUS_FAILED_EXCEED_LIMIT))
+#define MWL8K_TXD_SUCCESS(status) \
+ ((status) & (MWL8K_TXD_STATUS_OK | \
+ MWL8K_TXD_STATUS_OK_RETRY | \
+ MWL8K_TXD_STATUS_OK_MORE_RETRY))
static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
{
@@ -1293,15 +1183,13 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
while (txq->tx_stats.len > 0) {
int tx;
- int rc;
struct mwl8k_tx_desc *tx_desc;
unsigned long addr;
- size_t size;
+ int size;
struct sk_buff *skb;
struct ieee80211_tx_info *info;
u32 status;
- rc = 0;
tx = txq->tx_head;
tx_desc = txq->tx_desc_area + tx;
@@ -1320,56 +1208,30 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
priv->pending_tx_pkts--;
addr = le32_to_cpu(tx_desc->pkt_phys_addr);
- size = (u32)(le16_to_cpu(tx_desc->pkt_len));
- skb = txq->tx_skb[tx].skb;
- txq->tx_skb[tx].skb = NULL;
+ size = le16_to_cpu(tx_desc->pkt_len);
+ skb = txq->tx_skb[tx];
+ txq->tx_skb[tx] = NULL;
BUG_ON(skb == NULL);
pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE);
- rc = mwl8k_remove_dma_header(skb);
+ mwl8k_remove_dma_header(skb);
/* Mark descriptor as unused */
tx_desc->pkt_phys_addr = 0;
tx_desc->pkt_len = 0;
- if (txq->tx_skb[tx].clone) {
- /* Replace with original skb
- * before returning to stack
- * as buffer has been cloned
- */
- dev_kfree_skb(skb);
- skb = txq->tx_skb[tx].clone;
- txq->tx_skb[tx].clone = NULL;
- }
-
- if (rc) {
- /* Something has gone wrong here.
- * Failed to remove DMA header.
- * Print error message and drop packet.
- */
- printk(KERN_ERR "%s: Error removing DMA header from "
- "tx skb 0x%p.\n", priv->name, skb);
-
- dev_kfree_skb(skb);
- continue;
- }
-
info = IEEE80211_SKB_CB(skb);
ieee80211_tx_info_clear_status(info);
-
- /* Convert firmware status stuff into tx_status */
- if (MWL8K_TXD_SUCCESS(status)) {
- /* Transmit OK */
+ if (MWL8K_TXD_SUCCESS(status))
info->flags |= IEEE80211_TX_STAT_ACK;
- }
ieee80211_tx_status_irqsafe(hw, skb);
- wake = !priv->inconfig && priv->radio_state;
+ wake = 1;
}
- if (wake)
+ if (wake && priv->radio_on && !mutex_is_locked(&priv->fw_mutex))
ieee80211_wake_queue(hw, index);
}
@@ -1395,56 +1257,60 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
{
struct mwl8k_priv *priv = hw->priv;
struct ieee80211_tx_info *tx_info;
+ struct mwl8k_vif *mwl8k_vif;
struct ieee80211_hdr *wh;
struct mwl8k_tx_queue *txq;
struct mwl8k_tx_desc *tx;
- struct mwl8k_dma_data *tr;
- struct mwl8k_vif *mwl8k_vif;
- struct sk_buff *org_skb = skb;
dma_addr_t dma;
- u16 qos = 0;
- bool qosframe = false, ampduframe = false;
- bool mcframe = false, eapolframe = false;
- bool amsduframe = false;
- __le16 fc;
-
- txq = priv->txq + index;
- tx = txq->tx_desc_area + txq->tx_tail;
+ u32 txstatus;
+ u8 txdatarate;
+ u16 qos;
- BUG_ON(txq->tx_skb[txq->tx_tail].skb != NULL);
+ wh = (struct ieee80211_hdr *)skb->data;
+ if (ieee80211_is_data_qos(wh->frame_control))
+ qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh)));
+ else
+ qos = 0;
- /*
- * Append HW DMA header to start of packet. Drop packet if
- * there is not enough space or a failure to unshare/unclone
- * the skb.
- */
- skb = mwl8k_add_dma_header(skb);
-
- if (skb == NULL) {
- printk(KERN_DEBUG "%s: failed to prepend HW DMA "
- "header, dropping TX frame.\n", priv->name);
- dev_kfree_skb(org_skb);
- return NETDEV_TX_OK;
- }
+ mwl8k_add_dma_header(skb);
+ wh = &((struct mwl8k_dma_data *)skb->data)->wh;
tx_info = IEEE80211_SKB_CB(skb);
mwl8k_vif = MWL8K_VIF(tx_info->control.vif);
- tr = (struct mwl8k_dma_data *)skb->data;
- wh = &tr->wh;
- fc = wh->frame_control;
- qosframe = ieee80211_is_data_qos(fc);
- mcframe = is_multicast_ether_addr(wh->addr1);
- ampduframe = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
u16 seqno = mwl8k_vif->seqno;
+
wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
wh->seq_ctrl |= cpu_to_le16(seqno << 4);
mwl8k_vif->seqno = seqno++ % 4096;
}
- if (qosframe)
- qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh)));
+ /* Setup firmware control bit fields for each frame type. */
+ txstatus = 0;
+ txdatarate = 0;
+ if (ieee80211_is_mgmt(wh->frame_control) ||
+ ieee80211_is_ctl(wh->frame_control)) {
+ txdatarate = 0;
+ qos = mwl8k_qos_setbit_eosp(qos);
+ /* Set Queue size to unspecified */
+ qos = mwl8k_qos_setbit_qlen(qos, 0xff);
+ } else if (ieee80211_is_data(wh->frame_control)) {
+ txdatarate = 1;
+ if (is_multicast_ether_addr(wh->addr1))
+ txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX;
+
+ /* Send pkt in an aggregate if AMPDU frame. */
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ qos = mwl8k_qos_setbit_ack(qos,
+ MWL8K_TXD_ACK_POLICY_BLOCKACK);
+ else
+ qos = mwl8k_qos_setbit_ack(qos,
+ MWL8K_TXD_ACK_POLICY_NORMAL);
+
+ if (qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
+ qos = mwl8k_qos_setbit_amsdu(qos);
+ }
dma = pci_map_single(priv->pdev, skb->data,
skb->len, PCI_DMA_TODEVICE);
@@ -1452,99 +1318,40 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
if (pci_dma_mapping_error(priv->pdev, dma)) {
printk(KERN_DEBUG "%s: failed to dma map skb, "
"dropping TX frame.\n", priv->name);
-
- if (org_skb != NULL)
- dev_kfree_skb(org_skb);
- if (skb != NULL)
- dev_kfree_skb(skb);
+ dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
- /* Set desc header, cpu bit order. */
- tx->status = 0;
- tx->data_rate = 0;
- tx->tx_priority = index;
- tx->qos_control = 0;
- tx->rate_info = 0;
- tx->peer_id = mwl8k_vif->peer_id;
-
- amsduframe = !!(qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT);
-
- /* Setup firmware control bit fields for each frame type. */
- if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
- tx->data_rate = 0;
- qos = mwl8k_qos_setbit_eosp(qos);
- /* Set Queue size to unspecified */
- qos = mwl8k_qos_setbit_qlen(qos, 0xff);
- } else if (ieee80211_is_data(fc)) {
- tx->data_rate = 1;
- if (mcframe)
- tx->status |= MWL8K_TXD_STATUS_MULTICAST_TX;
+ spin_lock_bh(&priv->tx_lock);
- /*
- * Tell firmware to not send EAPOL pkts in an
- * aggregate. Verify against mac80211 tx path. If
- * stack turns off AMPDU for an EAPOL frame this
- * check will be removed.
- */
- if (eapolframe) {
- qos = mwl8k_qos_setbit_ack(qos,
- MWL8K_TXD_ACK_POLICY_NORMAL);
- } else {
- /* Send pkt in an aggregate if AMPDU frame. */
- if (ampduframe)
- qos = mwl8k_qos_setbit_ack(qos,
- MWL8K_TXD_ACK_POLICY_BLOCKACK);
- else
- qos = mwl8k_qos_setbit_ack(qos,
- MWL8K_TXD_ACK_POLICY_NORMAL);
+ txq = priv->txq + index;
- if (amsduframe)
- qos = mwl8k_qos_setbit_amsdu(qos);
- }
- }
+ BUG_ON(txq->tx_skb[txq->tx_tail] != NULL);
+ txq->tx_skb[txq->tx_tail] = skb;
- /* Convert to little endian */
+ tx = txq->tx_desc_area + txq->tx_tail;
+ tx->data_rate = txdatarate;
+ tx->tx_priority = index;
tx->qos_control = cpu_to_le16(qos);
- tx->status = cpu_to_le32(tx->status);
tx->pkt_phys_addr = cpu_to_le32(dma);
tx->pkt_len = cpu_to_le16(skb->len);
-
- txq->tx_skb[txq->tx_tail].skb = skb;
- txq->tx_skb[txq->tx_tail].clone =
- skb == org_skb ? NULL : org_skb;
-
- spin_lock_bh(&priv->tx_lock);
-
- tx->status = cpu_to_le32(MWL8K_TXD_STATUS_OK |
- MWL8K_TXD_STATUS_FW_OWNED);
+ tx->rate_info = 0;
+ tx->peer_id = mwl8k_vif->peer_id;
wmb();
+ tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus);
+
+ txq->tx_stats.count++;
txq->tx_stats.len++;
priv->pending_tx_pkts++;
- txq->tx_stats.count++;
- txq->tx_tail++;
+ txq->tx_tail++;
if (txq->tx_tail == MWL8K_TX_DESCS)
txq->tx_tail = 0;
+
if (txq->tx_head == txq->tx_tail)
ieee80211_stop_queue(hw, index);
- if (priv->inconfig) {
- /*
- * Silently queue packet when we are in the middle of
- * a config cycle. Notify firmware only if we are
- * waiting for TXQs to empty. If a packet is sent
- * before .config() is complete, perhaps it is better
- * to drop the packet, as the channel is being changed
- * and the packet will end up on the wrong channel.
- */
- printk(KERN_ERR "%s(): WARNING TX activity while "
- "in config\n", __func__);
-
- if (priv->tx_wait != NULL)
- mwl8k_tx_start(priv);
- } else
- mwl8k_tx_start(priv);
+ mwl8k_tx_start(priv);
spin_unlock_bh(&priv->tx_lock);
@@ -1553,6 +1360,60 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
/*
+ * Firmware access.
+ *
+ * We have the following requirements for issuing firmware commands:
+ * - Some commands require that the packet transmit path is idle when
+ * the command is issued. (For simplicity, we'll just quiesce the
+ * transmit path for every command.)
+ * - There are certain sequences of commands that need to be issued to
+ * the hardware sequentially, with no other intervening commands.
+ *
+ * This leads to an implementation of a "firmware lock" as a mutex that
+ * can be taken recursively, and which is taken by both the low-level
+ * command submission function (mwl8k_post_cmd) as well as any users of
+ * that function that require issuing of an atomic sequence of commands,
+ * and quiesces the transmit path whenever it's taken.
+ */
+static int mwl8k_fw_lock(struct ieee80211_hw *hw)
+{
+ struct mwl8k_priv *priv = hw->priv;
+
+ if (priv->fw_mutex_owner != current) {
+ int rc;
+
+ mutex_lock(&priv->fw_mutex);
+ ieee80211_stop_queues(hw);
+
+ rc = mwl8k_tx_wait_empty(hw);
+ if (rc) {
+ ieee80211_wake_queues(hw);
+ mutex_unlock(&priv->fw_mutex);
+
+ return rc;
+ }
+
+ priv->fw_mutex_owner = current;
+ }
+
+ priv->fw_mutex_depth++;
+
+ return 0;
+}
+
+static void mwl8k_fw_unlock(struct ieee80211_hw *hw)
+{
+ struct mwl8k_priv *priv = hw->priv;
+
+ if (!--priv->fw_mutex_depth) {
+ ieee80211_wake_queues(hw);
+ priv->fw_mutex_owner = NULL;
+ mutex_unlock(&priv->fw_mutex);
+ }
+}
+
+
+/*
* Command processing.
*/
@@ -1567,7 +1428,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
dma_addr_t dma_addr;
unsigned int dma_size;
int rc;
- u16 __iomem *result;
unsigned long timeout = 0;
u8 buf[32];
@@ -1578,41 +1438,43 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
if (pci_dma_mapping_error(priv->pdev, dma_addr))
return -ENOMEM;
- if (priv->hostcmd_wait != NULL)
- printk(KERN_ERR "WARNING host command in progress\n");
+ rc = mwl8k_fw_lock(hw);
+ if (rc) {
+ pci_unmap_single(priv->pdev, dma_addr, dma_size,
+ PCI_DMA_BIDIRECTIONAL);
+ return rc;
+ }
- spin_lock_irq(&priv->fw_lock);
priv->hostcmd_wait = &cmd_wait;
iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR);
iowrite32(MWL8K_H2A_INT_DOORBELL,
regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
iowrite32(MWL8K_H2A_INT_DUMMY,
regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
- spin_unlock_irq(&priv->fw_lock);
timeout = wait_for_completion_timeout(&cmd_wait,
msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS));
+ priv->hostcmd_wait = NULL;
+
+ mwl8k_fw_unlock(hw);
+
pci_unmap_single(priv->pdev, dma_addr, dma_size,
PCI_DMA_BIDIRECTIONAL);
- result = &cmd->result;
if (!timeout) {
- spin_lock_irq(&priv->fw_lock);
- priv->hostcmd_wait = NULL;
- spin_unlock_irq(&priv->fw_lock);
printk(KERN_ERR "%s: Command %s timeout after %u ms\n",
priv->name,
mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
MWL8K_CMD_TIMEOUT_MS);
rc = -ETIMEDOUT;
} else {
- rc = *result ? -EINVAL : 0;
+ rc = cmd->result ? -EINVAL : 0;
if (rc)
printk(KERN_ERR "%s: Command %s error 0x%x\n",
priv->name,
mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
- *result);
+ le16_to_cpu(cmd->result));
}
return rc;
@@ -1626,7 +1488,7 @@ struct mwl8k_cmd_get_hw_spec {
__u8 hw_rev;
__u8 host_interface;
__le16 num_mcaddrs;
- __u8 perm_addr[IEEE80211_ADDR_LEN];
+ __u8 perm_addr[ETH_ALEN];
__le16 region_code;
__le32 fw_rev;
__le32 ps_cookie;
@@ -1670,7 +1532,6 @@ static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw)
priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs);
priv->fw_rev = le32_to_cpu(cmd->fw_rev);
priv->hw_rev = cmd->hw_rev;
- priv->region_code = le16_to_cpu(cmd->region_code);
}
kfree(cmd);
@@ -1684,41 +1545,44 @@ struct mwl8k_cmd_mac_multicast_adr {
struct mwl8k_cmd_pkt header;
__le16 action;
__le16 numaddr;
- __u8 addr[1][IEEE80211_ADDR_LEN];
+ __u8 addr[0][ETH_ALEN];
};
#define MWL8K_ENABLE_RX_MULTICAST 0x000F
-static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
- int mc_count,
- struct dev_addr_list *mclist)
+
+static struct mwl8k_cmd_pkt *
+__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
+ int mc_count, struct dev_addr_list *mclist)
{
+ struct mwl8k_priv *priv = hw->priv;
struct mwl8k_cmd_mac_multicast_adr *cmd;
- int index = 0;
- int rc;
- int size = sizeof(*cmd) + ((mc_count - 1) * IEEE80211_ADDR_LEN);
- cmd = kzalloc(size, GFP_KERNEL);
+ int size;
+ int i;
+
+ if (mc_count > priv->num_mcaddrs)
+ mc_count = priv->num_mcaddrs;
+
+ size = sizeof(*cmd) + mc_count * ETH_ALEN;
+
+ cmd = kzalloc(size, GFP_ATOMIC);
if (cmd == NULL)
- return -ENOMEM;
+ return NULL;
cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR);
cmd->header.length = cpu_to_le16(size);
cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST);
cmd->numaddr = cpu_to_le16(mc_count);
- while ((index < mc_count) && mclist) {
- if (mclist->da_addrlen != IEEE80211_ADDR_LEN) {
- rc = -EINVAL;
- goto mwl8k_cmd_mac_multicast_adr_exit;
+
+ for (i = 0; i < mc_count && mclist; i++) {
+ if (mclist->da_addrlen != ETH_ALEN) {
+ kfree(cmd);
+ return NULL;
}
- memcpy(cmd->addr[index], mclist->da_addr, IEEE80211_ADDR_LEN);
- index++;
+ memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN);
mclist = mclist->next;
}
- rc = mwl8k_post_cmd(hw, &cmd->header);
-
-mwl8k_cmd_mac_multicast_adr_exit:
- kfree(cmd);
- return rc;
+ return &cmd->header;
}
/*
@@ -1775,18 +1639,16 @@ struct mwl8k_cmd_802_11_radio_control {
__le16 radio_on;
} __attribute__((packed));
-static int mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, int enable)
+static int
+mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
{
struct mwl8k_priv *priv = hw->priv;
struct mwl8k_cmd_802_11_radio_control *cmd;
int rc;
- if (((enable & MWL8K_RADIO_ENABLE) == priv->radio_state) &&
- !(enable & MWL8K_RADIO_FORCE))
+ if (enable == priv->radio_on && !force)
return 0;
- enable &= MWL8K_RADIO_ENABLE;
-
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
@@ -1794,18 +1656,28 @@ static int mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, int enable)
cmd->header.code = cpu_to_le16(MWL8K_CMD_RADIO_CONTROL);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
cmd->action = cpu_to_le16(MWL8K_CMD_SET);
- cmd->control = cpu_to_le16(priv->radio_preamble);
+ cmd->control = cpu_to_le16(priv->radio_short_preamble ? 3 : 1);
cmd->radio_on = cpu_to_le16(enable ? 0x0001 : 0x0000);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
if (!rc)
- priv->radio_state = enable;
+ priv->radio_on = enable;
return rc;
}
+static int mwl8k_cmd_802_11_radio_disable(struct ieee80211_hw *hw)
+{
+ return mwl8k_cmd_802_11_radio_control(hw, 0, 0);
+}
+
+static int mwl8k_cmd_802_11_radio_enable(struct ieee80211_hw *hw)
+{
+ return mwl8k_cmd_802_11_radio_control(hw, 1, 0);
+}
+
static int
mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble)
{
@@ -1815,12 +1687,9 @@ mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble)
return -EINVAL;
priv = hw->priv;
- priv->radio_preamble = (short_preamble ?
- MWL8K_RADIO_SHORT_PREAMBLE :
- MWL8K_RADIO_LONG_PREAMBLE);
+ priv->radio_short_preamble = short_preamble;
- return mwl8k_cmd_802_11_radio_control(hw,
- MWL8K_RADIO_ENABLE | MWL8K_RADIO_FORCE);
+ return mwl8k_cmd_802_11_radio_control(hw, 1, 1);
}
/*
@@ -1888,11 +1757,11 @@ static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw)
struct mwl8k_cmd_set_post_scan {
struct mwl8k_cmd_pkt header;
__le32 isibss;
- __u8 bssid[IEEE80211_ADDR_LEN];
+ __u8 bssid[ETH_ALEN];
} __attribute__((packed));
static int
-mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 mac[IEEE80211_ADDR_LEN])
+mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 *mac)
{
struct mwl8k_cmd_set_post_scan *cmd;
int rc;
@@ -1904,7 +1773,7 @@ mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 mac[IEEE80211_ADDR_LEN])
cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_POST_SCAN);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
cmd->isibss = 0;
- memcpy(cmd->bssid, mac, IEEE80211_ADDR_LEN);
+ memcpy(cmd->bssid, mac, ETH_ALEN);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
@@ -1956,7 +1825,7 @@ struct mwl8k_cmd_set_slot {
__u8 short_slot;
} __attribute__((packed));
-static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, int slot_time)
+static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
{
struct mwl8k_cmd_set_slot *cmd;
int rc;
@@ -1968,7 +1837,7 @@ static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, int slot_time)
cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
cmd->action = cpu_to_le16(MWL8K_CMD_SET);
- cmd->short_slot = slot_time == MWL8K_SHORT_SLOTTIME ? 1 : 0;
+ cmd->short_slot = short_slot_time;
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
@@ -2026,7 +1895,7 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable)
cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
- cmd->action = enable ? cpu_to_le32((u32)MWL8K_CMD_SET) : 0;
+ cmd->action = cpu_to_le32(!!enable);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
@@ -2035,7 +1904,7 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable)
}
/*
- * CMD_SET_RATE_ADAPT_MODE.
+ * CMD_SET_RATEADAPT_MODE.
*/
struct mwl8k_cmd_set_rate_adapt_mode {
struct mwl8k_cmd_pkt header;
@@ -2083,13 +1952,13 @@ static int mwl8k_set_wmm(struct ieee80211_hw *hw, bool enable)
cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
- cmd->action = enable ? cpu_to_le16(MWL8K_CMD_SET) : 0;
+ cmd->action = cpu_to_le16(!!enable);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
if (!rc)
- priv->wmm_mode = enable;
+ priv->wmm_enabled = enable;
return rc;
}
@@ -2104,7 +1973,7 @@ struct mwl8k_cmd_rts_threshold {
} __attribute__((packed));
static int mwl8k_rts_threshold(struct ieee80211_hw *hw,
- u16 action, u16 *threshold)
+ u16 action, u16 threshold)
{
struct mwl8k_cmd_rts_threshold *cmd;
int rc;
@@ -2116,7 +1985,7 @@ static int mwl8k_rts_threshold(struct ieee80211_hw *hw,
cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
cmd->action = cpu_to_le16(action);
- cmd->threshold = cpu_to_le16(*threshold);
+ cmd->threshold = cpu_to_le16(threshold);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
@@ -2149,7 +2018,6 @@ struct mwl8k_cmd_set_edca_params {
__u8 txq;
} __attribute__((packed));
-#define MWL8K_GET_EDCA_ALL 0
#define MWL8K_SET_EDCA_CW 0x01
#define MWL8K_SET_EDCA_TXOP 0x02
#define MWL8K_SET_EDCA_AIFS 0x04
@@ -2164,22 +2032,18 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
__u8 aifs, __u16 txop)
{
struct mwl8k_cmd_set_edca_params *cmd;
- u32 log_cw_min, log_cw_max;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
- log_cw_min = ilog2(cw_min+1);
- log_cw_max = ilog2(cw_max+1);
cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
-
cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL);
cmd->txop = cpu_to_le16(txop);
- cmd->log_cw_max = (u8)log_cw_max;
- cmd->log_cw_min = (u8)log_cw_min;
+ cmd->log_cw_max = (u8)ilog2(cw_max + 1);
+ cmd->log_cw_min = (u8)ilog2(cw_min + 1);
cmd->aifs = aifs;
cmd->txq = qnum;
@@ -2220,11 +2084,7 @@ static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame,
cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
-
- if (dtim)
- cmd->sleep_interval = cpu_to_le32(dtim);
- else
- cmd->sleep_interval = cpu_to_le32(1);
+ cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1);
hdrlen = ieee80211_hdrlen(payload->frame_control);
@@ -2236,8 +2096,8 @@ static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame,
"sent to firmware. Sz=%u MAX=%u\n", __func__,
payload_len, MWL8K_FJ_BEACON_MAXLEN);
- payload_len = payload_len > MWL8K_FJ_BEACON_MAXLEN ?
- MWL8K_FJ_BEACON_MAXLEN : payload_len;
+ if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
+ payload_len = MWL8K_FJ_BEACON_MAXLEN;
if (payload && payload_len)
memcpy(cmd->beacon_data, &payload->u.beacon, payload_len);
@@ -2257,7 +2117,7 @@ struct mwl8k_cmd_update_sta_db {
__le32 action;
/* Peer MAC address */
- __u8 peer_addr[IEEE80211_ADDR_LEN];
+ __u8 peer_addr[ETH_ALEN];
__le32 reserved;
@@ -2273,7 +2133,6 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
struct mwl8k_cmd_update_sta_db *cmd;
struct peer_capability_info *peer_info;
struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
- DECLARE_MAC_BUF(mac);
int rc;
__u8 count, *rates;
@@ -2286,7 +2145,7 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
cmd->action = cpu_to_le32(action);
peer_info = &cmd->peer_info;
- memcpy(cmd->peer_addr, mv_vif->bssid, IEEE80211_ADDR_LEN);
+ memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN);
switch (action) {
case MWL8K_STA_DB_ADD_ENTRY:
@@ -2298,7 +2157,7 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
peer_info->amsdu_enabled = 0;
rates = peer_info->legacy_rates;
- for (count = 0 ; count < mv_vif->legacy_nrates; count++)
+ for (count = 0; count < mv_vif->legacy_nrates; count++)
rates[count] = bitrates[count].hw_value;
rc = mwl8k_post_cmd(hw, &cmd->header);
@@ -2323,25 +2182,19 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
/*
* CMD_SET_AID.
*/
-#define IEEE80211_OPMODE_DISABLED 0x00
-#define IEEE80211_OPMODE_NON_MEMBER_PROT_MODE 0x01
-#define IEEE80211_OPMODE_ONE_20MHZ_STA_PROT_MODE 0x02
-#define IEEE80211_OPMODE_HTMIXED_PROT_MODE 0x03
-
#define MWL8K_RATE_INDEX_MAX_ARRAY 14
#define MWL8K_FRAME_PROT_DISABLED 0x00
#define MWL8K_FRAME_PROT_11G 0x07
#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02
#define MWL8K_FRAME_PROT_11N_HT_ALL 0x06
-#define MWL8K_FRAME_PROT_MASK 0x07
struct mwl8k_cmd_update_set_aid {
struct mwl8k_cmd_pkt header;
__le16 aid;
/* AP's MAC address (BSSID) */
- __u8 bssid[IEEE80211_ADDR_LEN];
+ __u8 bssid[ETH_ALEN];
__le16 protection_mode;
__u8 supp_rates[MWL8K_RATE_INDEX_MAX_ARRAY];
} __attribute__((packed));
@@ -2365,9 +2218,7 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
cmd->header.length = cpu_to_le16(sizeof(*cmd));
cmd->aid = cpu_to_le16(info->aid);
- memcpy(cmd->bssid, mv_vif->bssid, IEEE80211_ADDR_LEN);
-
- prot_mode = MWL8K_FRAME_PROT_DISABLED;
+ memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN);
if (info->use_cts_prot) {
prot_mode = MWL8K_FRAME_PROT_11G;
@@ -2385,7 +2236,6 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
break;
}
}
-
cmd->protection_mode = cpu_to_le16(prot_mode);
for (count = 0; count < mv_vif->legacy_nrates; count++)
@@ -2439,10 +2289,6 @@ static int mwl8k_update_rateset(struct ieee80211_hw *hw,
*/
#define MWL8K_RATE_TABLE_SIZE 8
#define MWL8K_UCAST_RATE 0
-#define MWL8K_MCAST_RATE 1
-#define MWL8K_BCAST_RATE 2
-
-#define MWL8K_USE_FIXED_RATE 0x0001
#define MWL8K_USE_AUTO_RATE 0x0002
struct mwl8k_rate_entry {
@@ -2535,7 +2381,6 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
- status &= priv->int_mask;
if (!status)
return IRQ_NONE;
@@ -2548,17 +2393,14 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
}
if (status & MWL8K_A2H_INT_OPC_DONE) {
- if (priv->hostcmd_wait != NULL) {
+ if (priv->hostcmd_wait != NULL)
complete(priv->hostcmd_wait);
- priv->hostcmd_wait = NULL;
- }
}
if (status & MWL8K_A2H_INT_QUEUE_EMPTY) {
- if (!priv->inconfig &&
- priv->radio_state &&
- mwl8k_txq_busy(priv))
- mwl8k_tx_start(priv);
+ if (!mutex_is_locked(&priv->fw_mutex) &&
+ priv->radio_on && mwl8k_txq_busy(priv))
+ mwl8k_tx_start(priv);
}
return IRQ_HANDLED;
@@ -2586,365 +2428,68 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return rc;
}
-struct mwl8k_work_struct {
- /* Initialized by mwl8k_queue_work(). */
- struct work_struct wt;
-
- /* Required field passed in to mwl8k_queue_work(). */
- struct ieee80211_hw *hw;
-
- /* Required field passed in to mwl8k_queue_work(). */
- int (*wfunc)(struct work_struct *w);
-
- /* Initialized by mwl8k_queue_work(). */
- struct completion *cmd_wait;
-
- /* Result code. */
- int rc;
-
- /*
- * Optional field. Refer to explanation of MWL8K_WQ_XXX_XXX
- * flags for explanation. Defaults to MWL8K_WQ_DEFAULT_OPTIONS.
- */
- u32 options;
-
- /* Optional field. Defaults to MWL8K_CONFIG_TIMEOUT_MS. */
- unsigned long timeout_ms;
-
- /* Optional field. Defaults to MWL8K_WQ_TXWAIT_ATTEMPTS. */
- u32 txwait_attempts;
-
- /* Optional field. Defaults to MWL8K_TXWAIT_MS. */
- u32 tx_timeout_ms;
- u32 step;
-};
-
-/* Flags controlling behavior of config queue requests */
-
-/* Caller spins while waiting for completion. */
-#define MWL8K_WQ_SPIN 0x00000001
-
-/* Wait for TX queues to empty before proceeding with configuration. */
-#define MWL8K_WQ_TX_WAIT_EMPTY 0x00000002
-
-/* Queue request and return immediately. */
-#define MWL8K_WQ_POST_REQUEST 0x00000004
-
-/*
- * Caller sleeps and waits for task complete notification.
- * Do not use in atomic context.
- */
-#define MWL8K_WQ_SLEEP 0x00000008
-
-/* Free work struct when task is done. */
-#define MWL8K_WQ_FREE_WORKSTRUCT 0x00000010
-
-/*
- * Config request is queued and returns to caller imediately. Use
- * this in atomic context. Work struct is freed by mwl8k_queue_work()
- * when this flag is set.
- */
-#define MWL8K_WQ_QUEUE_ONLY (MWL8K_WQ_POST_REQUEST | \
- MWL8K_WQ_FREE_WORKSTRUCT)
-
-/* Default work queue behavior is to sleep and wait for tx completion. */
-#define MWL8K_WQ_DEFAULT_OPTIONS (MWL8K_WQ_SLEEP | MWL8K_WQ_TX_WAIT_EMPTY)
-
-/*
- * Default config request timeout. Add adjustments to make sure the
- * config thread waits long enough for both tx wait and cmd wait before
- * timing out.
- */
-
-/* Time to wait for all TXQs to drain. TX Doorbell is pressed each time. */
-#define MWL8K_TXWAIT_TIMEOUT_MS 1000
-
-/* Default number of TX wait attempts. */
-#define MWL8K_WQ_TXWAIT_ATTEMPTS 4
-
-/* Total time to wait for TXQ to drain. */
-#define MWL8K_TXWAIT_MS (MWL8K_TXWAIT_TIMEOUT_MS * \
- MWL8K_WQ_TXWAIT_ATTEMPTS)
-
-/* Scheduling slop. */
-#define MWL8K_OS_SCHEDULE_OVERHEAD_MS 200
-
-#define MWL8K_CONFIG_TIMEOUT_MS (MWL8K_CMD_TIMEOUT_MS + \
- MWL8K_TXWAIT_MS + \
- MWL8K_OS_SCHEDULE_OVERHEAD_MS)
-
-static void mwl8k_config_thread(struct work_struct *wt)
-{
- struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt;
- struct ieee80211_hw *hw = worker->hw;
- struct mwl8k_priv *priv = hw->priv;
- int rc = 0;
-
- spin_lock_irq(&priv->tx_lock);
- priv->inconfig = true;
- spin_unlock_irq(&priv->tx_lock);
-
- ieee80211_stop_queues(hw);
-
- /*
- * Wait for host queues to drain before doing PHY
- * reconfiguration. This avoids interrupting any in-flight
- * DMA transfers to the hardware.
- */
- if (worker->options & MWL8K_WQ_TX_WAIT_EMPTY) {
- u32 timeout;
- u32 time_remaining;
- u32 iter;
- u32 tx_wait_attempts = worker->txwait_attempts;
-
- time_remaining = worker->tx_timeout_ms;
- if (!tx_wait_attempts)
- tx_wait_attempts = 1;
-
- timeout = worker->tx_timeout_ms/tx_wait_attempts;
- if (!timeout)
- timeout = 1;
-
- iter = tx_wait_attempts;
- do {
- int wait_time;
-
- if (time_remaining > timeout) {
- time_remaining -= timeout;
- wait_time = timeout;
- } else
- wait_time = time_remaining;
-
- if (!wait_time)
- wait_time = 1;
-
- rc = mwl8k_tx_wait_empty(hw, wait_time);
- if (rc)
- printk(KERN_ERR "%s() txwait timeout=%ums "
- "Retry:%u/%u\n", __func__, timeout,
- tx_wait_attempts - iter + 1,
- tx_wait_attempts);
-
- } while (rc && --iter);
-
- rc = iter ? 0 : -ETIMEDOUT;
- }
- if (!rc)
- rc = worker->wfunc(wt);
-
- spin_lock_irq(&priv->tx_lock);
- priv->inconfig = false;
- if (priv->pending_tx_pkts && priv->radio_state)
- mwl8k_tx_start(priv);
- spin_unlock_irq(&priv->tx_lock);
- ieee80211_wake_queues(hw);
-
- worker->rc = rc;
- if (worker->options & MWL8K_WQ_SLEEP)
- complete(worker->cmd_wait);
-
- if (worker->options & MWL8K_WQ_FREE_WORKSTRUCT)
- kfree(wt);
-}
-
-static int mwl8k_queue_work(struct ieee80211_hw *hw,
- struct mwl8k_work_struct *worker,
- struct workqueue_struct *wqueue,
- int (*wfunc)(struct work_struct *w))
-{
- unsigned long timeout = 0;
- int rc = 0;
-
- DECLARE_COMPLETION_ONSTACK(cmd_wait);
-
- if (!worker->timeout_ms)
- worker->timeout_ms = MWL8K_CONFIG_TIMEOUT_MS;
-
- if (!worker->options)
- worker->options = MWL8K_WQ_DEFAULT_OPTIONS;
-
- if (!worker->txwait_attempts)
- worker->txwait_attempts = MWL8K_WQ_TXWAIT_ATTEMPTS;
-
- if (!worker->tx_timeout_ms)
- worker->tx_timeout_ms = MWL8K_TXWAIT_MS;
-
- worker->hw = hw;
- worker->cmd_wait = &cmd_wait;
- worker->rc = 1;
- worker->wfunc = wfunc;
-
- INIT_WORK(&worker->wt, mwl8k_config_thread);
- queue_work(wqueue, &worker->wt);
-
- if (worker->options & MWL8K_WQ_POST_REQUEST) {
- rc = 0;
- } else {
- if (worker->options & MWL8K_WQ_SPIN) {
- timeout = worker->timeout_ms;
- while (timeout && (worker->rc > 0)) {
- mdelay(1);
- timeout--;
- }
- } else if (worker->options & MWL8K_WQ_SLEEP)
- timeout = wait_for_completion_timeout(&cmd_wait,
- msecs_to_jiffies(worker->timeout_ms));
-
- if (timeout)
- rc = worker->rc;
- else {
- cancel_work_sync(&worker->wt);
- rc = -ETIMEDOUT;
- }
- }
-
- return rc;
-}
-
-struct mwl8k_start_worker {
- struct mwl8k_work_struct header;
-};
-
-static int mwl8k_start_wt(struct work_struct *wt)
-{
- struct mwl8k_start_worker *worker = (struct mwl8k_start_worker *)wt;
- struct ieee80211_hw *hw = worker->header.hw;
- struct mwl8k_priv *priv = hw->priv;
- int rc = 0;
-
- if (priv->vif != NULL) {
- rc = -EIO;
- goto mwl8k_start_exit;
- }
-
- /* Turn on radio */
- if (mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_ENABLE)) {
- rc = -EIO;
- goto mwl8k_start_exit;
- }
-
- /* Purge TX/RX HW queues */
- if (mwl8k_cmd_set_pre_scan(hw)) {
- rc = -EIO;
- goto mwl8k_start_exit;
- }
-
- if (mwl8k_cmd_set_post_scan(hw, "\x00\x00\x00\x00\x00\x00")) {
- rc = -EIO;
- goto mwl8k_start_exit;
- }
-
- /* Enable firmware rate adaptation */
- if (mwl8k_cmd_setrateadaptmode(hw, 0)) {
- rc = -EIO;
- goto mwl8k_start_exit;
- }
-
- /* Disable WMM. WMM gets enabled when stack sends WMM parms */
- if (mwl8k_set_wmm(hw, MWL8K_WMM_DISABLE)) {
- rc = -EIO;
- goto mwl8k_start_exit;
- }
-
- /* Disable sniffer mode */
- if (mwl8k_enable_sniffer(hw, 0))
- rc = -EIO;
-
-mwl8k_start_exit:
- return rc;
-}
-
static int mwl8k_start(struct ieee80211_hw *hw)
{
- struct mwl8k_start_worker *worker;
struct mwl8k_priv *priv = hw->priv;
int rc;
- /* Enable tx reclaim tasklet */
- tasklet_enable(&priv->tx_reclaim_task);
-
rc = request_irq(priv->pdev->irq, &mwl8k_interrupt,
IRQF_SHARED, MWL8K_NAME, hw);
if (rc) {
printk(KERN_ERR "%s: failed to register IRQ handler\n",
priv->name);
- rc = -EIO;
- goto mwl8k_start_disable_tasklet;
+ return -EIO;
}
- /* Enable interrupts */
- iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
-
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL) {
- rc = -ENOMEM;
- goto mwl8k_start_disable_irq;
- }
+ /* Enable tx reclaim tasklet */
+ tasklet_enable(&priv->tx_reclaim_task);
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq, mwl8k_start_wt);
- kfree(worker);
- if (!rc)
- return rc;
+ /* Enable interrupts */
+ iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
- if (rc == -ETIMEDOUT)
- printk(KERN_ERR "%s() timed out\n", __func__);
+ rc = mwl8k_fw_lock(hw);
+ if (!rc) {
+ rc = mwl8k_cmd_802_11_radio_enable(hw);
- rc = -EIO;
+ if (!rc)
+ rc = mwl8k_cmd_set_pre_scan(hw);
-mwl8k_start_disable_irq:
- spin_lock_irq(&priv->tx_lock);
- iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
- spin_unlock_irq(&priv->tx_lock);
- free_irq(priv->pdev->irq, hw);
+ if (!rc)
+ rc = mwl8k_cmd_set_post_scan(hw,
+ "\x00\x00\x00\x00\x00\x00");
-mwl8k_start_disable_tasklet:
- tasklet_disable(&priv->tx_reclaim_task);
+ if (!rc)
+ rc = mwl8k_cmd_setrateadaptmode(hw, 0);
- return rc;
-}
+ if (!rc)
+ rc = mwl8k_set_wmm(hw, 0);
-struct mwl8k_stop_worker {
- struct mwl8k_work_struct header;
-};
+ if (!rc)
+ rc = mwl8k_enable_sniffer(hw, 0);
-static int mwl8k_stop_wt(struct work_struct *wt)
-{
- struct mwl8k_stop_worker *worker = (struct mwl8k_stop_worker *)wt;
- struct ieee80211_hw *hw = worker->header.hw;
- int rc;
+ mwl8k_fw_unlock(hw);
+ }
- rc = mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE);
+ if (rc) {
+ iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
+ free_irq(priv->pdev->irq, hw);
+ tasklet_disable(&priv->tx_reclaim_task);
+ }
return rc;
}
static void mwl8k_stop(struct ieee80211_hw *hw)
{
- int rc;
- struct mwl8k_stop_worker *worker;
struct mwl8k_priv *priv = hw->priv;
int i;
- if (priv->vif != NULL)
- return;
+ mwl8k_cmd_802_11_radio_disable(hw);
ieee80211_stop_queues(hw);
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL)
- return;
-
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq, mwl8k_stop_wt);
- kfree(worker);
- if (rc == -ETIMEDOUT)
- printk(KERN_ERR "%s() timed out\n", __func__);
-
/* Disable interrupts */
- spin_lock_irq(&priv->tx_lock);
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
- spin_unlock_irq(&priv->tx_lock);
free_irq(priv->pdev->irq, hw);
/* Stop finalize join worker */
@@ -2978,8 +2523,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
/*
* We only support managed interfaces for now.
*/
- if (conf->type != NL80211_IFTYPE_STATION &&
- conf->type != NL80211_IFTYPE_MONITOR)
+ if (conf->type != NL80211_IFTYPE_STATION)
return -EINVAL;
/* Clean out driver private area */
@@ -2987,13 +2531,13 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
/* Save the mac address */
- memcpy(mwl8k_vif->mac_addr, conf->mac_addr, IEEE80211_ADDR_LEN);
+ memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN);
/* Back pointer to parent config block */
mwl8k_vif->priv = priv;
/* Setup initial PHY parameters */
- memcpy(mwl8k_vif->legacy_rates ,
+ memcpy(mwl8k_vif->legacy_rates,
priv->rates, sizeof(mwl8k_vif->legacy_rates));
mwl8k_vif->legacy_nrates = ARRAY_SIZE(priv->rates);
@@ -3017,213 +2561,148 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw,
priv->vif = NULL;
}
-struct mwl8k_config_worker {
- struct mwl8k_work_struct header;
- u32 changed;
-};
-
-static int mwl8k_config_wt(struct work_struct *wt)
+static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
{
- struct mwl8k_config_worker *worker =
- (struct mwl8k_config_worker *)wt;
- struct ieee80211_hw *hw = worker->header.hw;
struct ieee80211_conf *conf = &hw->conf;
struct mwl8k_priv *priv = hw->priv;
- int rc = 0;
+ int rc;
- if (!conf->radio_enabled) {
- mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE);
+ if (conf->flags & IEEE80211_CONF_IDLE) {
+ mwl8k_cmd_802_11_radio_disable(hw);
priv->current_channel = NULL;
- rc = 0;
- goto mwl8k_config_exit;
+ return 0;
}
- if (mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_ENABLE)) {
- rc = -EINVAL;
- goto mwl8k_config_exit;
- }
+ rc = mwl8k_fw_lock(hw);
+ if (rc)
+ return rc;
- priv->current_channel = conf->channel;
+ rc = mwl8k_cmd_802_11_radio_enable(hw);
+ if (rc)
+ goto out;
- if (mwl8k_cmd_set_rf_channel(hw, conf->channel)) {
- rc = -EINVAL;
- goto mwl8k_config_exit;
- }
+ rc = mwl8k_cmd_set_rf_channel(hw, conf->channel);
+ if (rc)
+ goto out;
+
+ priv->current_channel = conf->channel;
if (conf->power_level > 18)
conf->power_level = 18;
- if (mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level)) {
- rc = -EINVAL;
- goto mwl8k_config_exit;
- }
+ rc = mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level);
+ if (rc)
+ goto out;
if (mwl8k_cmd_mimo_config(hw, 0x7, 0x7))
rc = -EINVAL;
-mwl8k_config_exit:
+out:
+ mwl8k_fw_unlock(hw);
+
return rc;
}
-static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
+static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed)
{
- int rc = 0;
- struct mwl8k_config_worker *worker;
struct mwl8k_priv *priv = hw->priv;
-
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL)
- return -ENOMEM;
-
- worker->changed = changed;
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq, mwl8k_config_wt);
- if (rc == -ETIMEDOUT) {
- printk(KERN_ERR "%s() timed out.\n", __func__);
- rc = -EINVAL;
- }
-
- kfree(worker);
-
- /*
- * mac80211 will crash on anything other than -EINVAL on
- * error. Looks like wireless extensions which calls mac80211
- * may be the actual culprit...
- */
- return rc ? -EINVAL : 0;
-}
-
-struct mwl8k_bss_info_changed_worker {
- struct mwl8k_work_struct header;
- struct ieee80211_vif *vif;
- struct ieee80211_bss_conf *info;
- u32 changed;
-};
-
-static int mwl8k_bss_info_changed_wt(struct work_struct *wt)
-{
- struct mwl8k_bss_info_changed_worker *worker =
- (struct mwl8k_bss_info_changed_worker *)wt;
- struct ieee80211_hw *hw = worker->header.hw;
- struct ieee80211_vif *vif = worker->vif;
- struct ieee80211_bss_conf *info = worker->info;
- u32 changed;
+ struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
int rc;
- struct mwl8k_priv *priv = hw->priv;
- struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+ if (changed & BSS_CHANGED_BSSID)
+ memcpy(mwl8k_vif->bssid, info->bssid, ETH_ALEN);
+
+ if ((changed & BSS_CHANGED_ASSOC) == 0)
+ return;
- changed = worker->changed;
priv->capture_beacon = false;
+ rc = mwl8k_fw_lock(hw);
+ if (rc)
+ return;
+
if (info->assoc) {
memcpy(&mwl8k_vif->bss_info, info,
sizeof(struct ieee80211_bss_conf));
/* Install rates */
- if (mwl8k_update_rateset(hw, vif))
- goto mwl8k_bss_info_changed_exit;
+ rc = mwl8k_update_rateset(hw, vif);
+ if (rc)
+ goto out;
/* Turn on rate adaptation */
- if (mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE,
- MWL8K_UCAST_RATE, NULL))
- goto mwl8k_bss_info_changed_exit;
+ rc = mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE,
+ MWL8K_UCAST_RATE, NULL);
+ if (rc)
+ goto out;
/* Set radio preamble */
- if (mwl8k_set_radio_preamble(hw,
- info->use_short_preamble))
- goto mwl8k_bss_info_changed_exit;
+ rc = mwl8k_set_radio_preamble(hw, info->use_short_preamble);
+ if (rc)
+ goto out;
/* Set slot time */
- if (mwl8k_cmd_set_slot(hw, info->use_short_slot ?
- MWL8K_SHORT_SLOTTIME : MWL8K_LONG_SLOTTIME))
- goto mwl8k_bss_info_changed_exit;
+ rc = mwl8k_cmd_set_slot(hw, info->use_short_slot);
+ if (rc)
+ goto out;
/* Update peer rate info */
- if (mwl8k_cmd_update_sta_db(hw, vif,
- MWL8K_STA_DB_MODIFY_ENTRY))
- goto mwl8k_bss_info_changed_exit;
+ rc = mwl8k_cmd_update_sta_db(hw, vif,
+ MWL8K_STA_DB_MODIFY_ENTRY);
+ if (rc)
+ goto out;
/* Set AID */
- if (mwl8k_cmd_set_aid(hw, vif))
- goto mwl8k_bss_info_changed_exit;
+ rc = mwl8k_cmd_set_aid(hw, vif);
+ if (rc)
+ goto out;
/*
* Finalize the join. Tell rx handler to process
* next beacon from our BSSID.
*/
- memcpy(priv->capture_bssid,
- mwl8k_vif->bssid, IEEE80211_ADDR_LEN);
+ memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN);
priv->capture_beacon = true;
} else {
- mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY);
+ rc = mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY);
memset(&mwl8k_vif->bss_info, 0,
sizeof(struct ieee80211_bss_conf));
- memset(mwl8k_vif->bssid, 0, IEEE80211_ADDR_LEN);
+ memset(mwl8k_vif->bssid, 0, ETH_ALEN);
}
-mwl8k_bss_info_changed_exit:
- rc = 0;
- return rc;
+out:
+ mwl8k_fw_unlock(hw);
}
-static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info,
- u32 changed)
+static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
+ int mc_count, struct dev_addr_list *mclist)
{
- struct mwl8k_bss_info_changed_worker *worker;
- struct mwl8k_priv *priv = hw->priv;
- struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
- int rc;
-
- if (changed & BSS_CHANGED_BSSID)
- memcpy(mv_vif->bssid, info->bssid, IEEE80211_ADDR_LEN);
-
- if ((changed & BSS_CHANGED_ASSOC) == 0)
- return;
-
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL)
- return;
+ struct mwl8k_cmd_pkt *cmd;
- worker->vif = vif;
- worker->info = info;
- worker->changed = changed;
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq,
- mwl8k_bss_info_changed_wt);
- kfree(worker);
- if (rc == -ETIMEDOUT)
- printk(KERN_ERR "%s() timed out\n", __func__);
-}
-
-struct mwl8k_configure_filter_worker {
- struct mwl8k_work_struct header;
- unsigned int changed_flags;
- unsigned int *total_flags;
- int mc_count;
- struct dev_addr_list *mclist;
-};
+ cmd = __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
-#define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC
+ return (unsigned long)cmd;
+}
-static int mwl8k_configure_filter_wt(struct work_struct *wt)
+static void mwl8k_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ u64 multicast)
{
- struct mwl8k_configure_filter_worker *worker =
- (struct mwl8k_configure_filter_worker *)wt;
+ struct mwl8k_priv *priv = hw->priv;
+ struct mwl8k_cmd_pkt *multicast_adr_cmd;
- struct ieee80211_hw *hw = worker->header.hw;
- unsigned int changed_flags = worker->changed_flags;
- unsigned int *total_flags = worker->total_flags;
- int mc_count = worker->mc_count;
- struct dev_addr_list *mclist = worker->mclist;
+ /* Clear unsupported feature flags */
+ *total_flags &= FIF_BCN_PRBRESP_PROMISC;
- struct mwl8k_priv *priv = hw->priv;
- int rc = 0;
+ if (mwl8k_fw_lock(hw))
+ return;
if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
- rc = mwl8k_cmd_set_pre_scan(hw);
+ mwl8k_cmd_set_pre_scan(hw);
else {
u8 *bssid;
@@ -3231,151 +2710,45 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt)
if (priv->vif != NULL)
bssid = MWL8K_VIF(priv->vif)->bssid;
- rc = mwl8k_cmd_set_post_scan(hw, bssid);
+ mwl8k_cmd_set_post_scan(hw, bssid);
}
}
- if (rc)
- goto mwl8k_configure_filter_exit;
- if (mc_count) {
- mc_count = mc_count < priv->num_mcaddrs ?
- mc_count : priv->num_mcaddrs;
- rc = mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
- if (rc)
- printk(KERN_ERR
- "%s()Error setting multicast addresses\n",
- __func__);
+ multicast_adr_cmd = (void *)(unsigned long)multicast;
+ if (multicast_adr_cmd != NULL) {
+ mwl8k_post_cmd(hw, multicast_adr_cmd);
+ kfree(multicast_adr_cmd);
}
-mwl8k_configure_filter_exit:
- return rc;
-}
-
-static void mwl8k_configure_filter(struct ieee80211_hw *hw,
- unsigned int changed_flags,
- unsigned int *total_flags,
- int mc_count,
- struct dev_addr_list *mclist)
-{
-
- struct mwl8k_configure_filter_worker *worker;
- struct mwl8k_priv *priv = hw->priv;
-
- /* Clear unsupported feature flags */
- *total_flags &= MWL8K_SUPPORTED_IF_FLAGS;
-
- if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS) && !mc_count)
- return;
-
- worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
- if (worker == NULL)
- return;
-
- worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY;
- worker->changed_flags = changed_flags;
- worker->total_flags = total_flags;
- worker->mc_count = mc_count;
- worker->mclist = mclist;
-
- mwl8k_queue_work(hw, &worker->header, priv->config_wq,
- mwl8k_configure_filter_wt);
-}
-
-struct mwl8k_set_rts_threshold_worker {
- struct mwl8k_work_struct header;
- u32 value;
-};
-
-static int mwl8k_set_rts_threshold_wt(struct work_struct *wt)
-{
- struct mwl8k_set_rts_threshold_worker *worker =
- (struct mwl8k_set_rts_threshold_worker *)wt;
-
- struct ieee80211_hw *hw = worker->header.hw;
- u16 threshold = (u16)(worker->value);
- int rc;
-
- rc = mwl8k_rts_threshold(hw, MWL8K_CMD_SET, &threshold);
-
- return rc;
+ mwl8k_fw_unlock(hw);
}
static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
- int rc;
- struct mwl8k_set_rts_threshold_worker *worker;
- struct mwl8k_priv *priv = hw->priv;
-
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL)
- return -ENOMEM;
-
- worker->value = value;
-
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq,
- mwl8k_set_rts_threshold_wt);
- kfree(worker);
-
- if (rc == -ETIMEDOUT) {
- printk(KERN_ERR "%s() timed out\n", __func__);
- rc = -EINVAL;
- }
-
- return rc;
-}
-
-struct mwl8k_conf_tx_worker {
- struct mwl8k_work_struct header;
- u16 queue;
- const struct ieee80211_tx_queue_params *params;
-};
-
-static int mwl8k_conf_tx_wt(struct work_struct *wt)
-{
- struct mwl8k_conf_tx_worker *worker =
- (struct mwl8k_conf_tx_worker *)wt;
-
- struct ieee80211_hw *hw = worker->header.hw;
- u16 queue = worker->queue;
- const struct ieee80211_tx_queue_params *params = worker->params;
-
- struct mwl8k_priv *priv = hw->priv;
- int rc = 0;
-
- if (priv->wmm_mode == MWL8K_WMM_DISABLE)
- if (mwl8k_set_wmm(hw, MWL8K_WMM_ENABLE)) {
- rc = -EINVAL;
- goto mwl8k_conf_tx_exit;
- }
-
- if (mwl8k_set_edca_params(hw, GET_TXQ(queue), params->cw_min,
- params->cw_max, params->aifs, params->txop))
- rc = -EINVAL;
-mwl8k_conf_tx_exit:
- return rc;
+ return mwl8k_rts_threshold(hw, MWL8K_CMD_SET, value);
}
static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
- int rc;
- struct mwl8k_conf_tx_worker *worker;
struct mwl8k_priv *priv = hw->priv;
+ int rc;
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL)
- return -ENOMEM;
+ rc = mwl8k_fw_lock(hw);
+ if (!rc) {
+ if (!priv->wmm_enabled)
+ rc = mwl8k_set_wmm(hw, 1);
- worker->queue = queue;
- worker->params = params;
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq, mwl8k_conf_tx_wt);
- kfree(worker);
- if (rc == -ETIMEDOUT) {
- printk(KERN_ERR "%s() timed out\n", __func__);
- rc = -EINVAL;
+ if (!rc)
+ rc = mwl8k_set_edca_params(hw, queue,
+ params->cw_min,
+ params->cw_max,
+ params->aifs,
+ params->txop);
+
+ mwl8k_fw_unlock(hw);
}
+
return rc;
}
@@ -3393,44 +2766,14 @@ static int mwl8k_get_tx_stats(struct ieee80211_hw *hw,
sizeof(struct ieee80211_tx_queue_stats));
}
spin_unlock_bh(&priv->tx_lock);
- return 0;
-}
-
-struct mwl8k_get_stats_worker {
- struct mwl8k_work_struct header;
- struct ieee80211_low_level_stats *stats;
-};
-
-static int mwl8k_get_stats_wt(struct work_struct *wt)
-{
- struct mwl8k_get_stats_worker *worker =
- (struct mwl8k_get_stats_worker *)wt;
- return mwl8k_cmd_802_11_get_stat(worker->header.hw, worker->stats);
+ return 0;
}
static int mwl8k_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
- int rc;
- struct mwl8k_get_stats_worker *worker;
- struct mwl8k_priv *priv = hw->priv;
-
- worker = kzalloc(sizeof(*worker), GFP_KERNEL);
- if (worker == NULL)
- return -ENOMEM;
-
- worker->stats = stats;
- rc = mwl8k_queue_work(hw, &worker->header,
- priv->config_wq, mwl8k_get_stats_wt);
-
- kfree(worker);
- if (rc == -ETIMEDOUT) {
- printk(KERN_ERR "%s() timed out\n", __func__);
- rc = -EINVAL;
- }
-
- return rc;
+ return mwl8k_cmd_802_11_get_stat(hw, stats);
}
static const struct ieee80211_ops mwl8k_ops = {
@@ -3441,6 +2784,7 @@ static const struct ieee80211_ops mwl8k_ops = {
.remove_interface = mwl8k_remove_interface,
.config = mwl8k_config,
.bss_info_changed = mwl8k_bss_info_changed,
+ .prepare_multicast = mwl8k_prepare_multicast,
.configure_filter = mwl8k_configure_filter,
.set_rts_threshold = mwl8k_set_rts_threshold,
.conf_tx = mwl8k_conf_tx,
@@ -3458,12 +2802,9 @@ static void mwl8k_tx_reclaim_handler(unsigned long data)
for (i = 0; i < MWL8K_TX_QUEUES; i++)
mwl8k_txq_reclaim(hw, i, 0);
- if (priv->tx_wait != NULL) {
- int count = mwl8k_txq_busy(priv);
- if (count == 0) {
- complete(priv->tx_wait);
- priv->tx_wait = NULL;
- }
+ if (priv->tx_wait != NULL && mwl8k_txq_busy(priv) == 0) {
+ complete(priv->tx_wait);
+ priv->tx_wait = NULL;
}
spin_unlock_bh(&priv->tx_lock);
}
@@ -3473,7 +2814,7 @@ static void mwl8k_finalize_join_worker(struct work_struct *work)
struct mwl8k_priv *priv =
container_of(work, struct mwl8k_priv, finalize_join_worker);
struct sk_buff *skb = priv->beacon_skb;
- u8 dtim = (MWL8K_VIF(priv->vif))->bss_info.dtim_period;
+ u8 dtim = MWL8K_VIF(priv->vif)->bss_info.dtim_period;
mwl8k_finalize_join(priv->hw, skb->data, skb->len, dtim);
dev_kfree_skb(skb);
@@ -3484,12 +2825,16 @@ static void mwl8k_finalize_join_worker(struct work_struct *work)
static int __devinit mwl8k_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
+ static int printed_version = 0;
struct ieee80211_hw *hw;
struct mwl8k_priv *priv;
- DECLARE_MAC_BUF(mac);
int rc;
int i;
- u8 *fw;
+
+ if (!printed_version) {
+ printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION);
+ printed_version = 1;
+ }
rc = pci_enable_device(pdev);
if (rc) {
@@ -3517,16 +2862,10 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
priv = hw->priv;
priv->hw = hw;
priv->pdev = pdev;
- priv->hostcmd_wait = NULL;
- priv->tx_wait = NULL;
- priv->inconfig = false;
- priv->wep_enabled = 0;
- priv->wmm_mode = false;
+ priv->wmm_enabled = false;
priv->pending_tx_pkts = 0;
strncpy(priv->name, MWL8K_NAME, sizeof(priv->name));
- spin_lock_init(&priv->fw_lock);
-
SET_IEEE80211_DEV(hw, &pdev->dev);
pci_set_drvdata(pdev, hw);
@@ -3558,17 +2897,16 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
hw->queues = MWL8K_TX_QUEUES;
- hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_MONITOR);
+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
/* Set rssi and noise values to dBm */
- hw->flags |= (IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM);
+ hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM;
hw->vif_data_size = sizeof(struct mwl8k_vif);
priv->vif = NULL;
/* Set default radio state and preamble */
- priv->radio_preamble = MWL8K_RADIO_DEFAULT_PREAMBLE;
- priv->radio_state = MWL8K_RADIO_DISABLE;
+ priv->radio_on = 0;
+ priv->radio_short_preamble = 0;
/* Finalize join worker */
INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
@@ -3593,6 +2931,12 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
goto err_iounmap;
rxq_refill(hw, 0, INT_MAX);
+ mutex_init(&priv->fw_mutex);
+ priv->fw_mutex_owner = NULL;
+ priv->fw_mutex_depth = 0;
+ priv->tx_wait = NULL;
+ priv->hostcmd_wait = NULL;
+
spin_lock_init(&priv->tx_lock);
for (i = 0; i < MWL8K_TX_QUEUES; i++) {
@@ -3602,8 +2946,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
}
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
- priv->int_mask = 0;
- iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
+ iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
@@ -3640,9 +2983,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
* commands use interrupts and avoids polling. Disable
* interrupts when done.
*/
- priv->int_mask |= MWL8K_A2H_EVENTS;
-
- iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
+ iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
/* Get config data, mac addrs etc */
rc = mwl8k_cmd_get_hw_spec(hw);
@@ -3652,16 +2993,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
}
/* Turn radio off */
- rc = mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE);
+ rc = mwl8k_cmd_802_11_radio_disable(hw);
if (rc) {
printk(KERN_ERR "%s: Cannot disable\n", priv->name);
goto err_stop_firmware;
}
/* Disable interrupts */
- spin_lock_irq(&priv->tx_lock);
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
- spin_unlock_irq(&priv->tx_lock);
free_irq(priv->pdev->irq, hw);
rc = ieee80211_register_hw(hw);
@@ -3670,13 +3009,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
goto err_stop_firmware;
}
- fw = (u8 *)&priv->fw_rev;
- printk(KERN_INFO "%s: 88W%u %s\n", priv->name, priv->part_num,
- MWL8K_DESC);
- printk(KERN_INFO "%s: Driver Ver:%s Firmware Ver:%u.%u.%u.%u\n",
- priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]);
- printk(KERN_INFO "%s: MAC Address: %s\n", priv->name,
- print_mac(mac, hw->wiphy->perm_addr));
+ printk(KERN_INFO "%s: 88w%u v%d, %pM, firmware version %u.%u.%u.%u\n",
+ wiphy_name(hw->wiphy), priv->part_num, priv->hw_rev,
+ hw->wiphy->perm_addr,
+ (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff,
+ (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff);
return 0;
@@ -3685,9 +3022,7 @@ err_stop_firmware:
mwl8k_release_firmware(priv);
err_free_irq:
- spin_lock_irq(&priv->tx_lock);
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
- spin_unlock_irq(&priv->tx_lock);
free_irq(priv->pdev->irq, hw);
err_free_queues:
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index d63c8992f229..9498b46c99a4 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -203,7 +203,8 @@ static int netwave_open(struct net_device *dev); /* Open the device */
static int netwave_close(struct net_device *dev); /* Close the device */
/* Packet transmission and Packet reception */
-static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev);
+static netdev_tx_t netwave_start_xmit( struct sk_buff *skb,
+ struct net_device *dev);
static int netwave_rx( struct net_device *dev);
/* Interrupt routines */
@@ -1026,7 +1027,8 @@ static int netwave_hw_xmit(unsigned char* data, int len,
return 0;
}
-static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+static netdev_tx_t netwave_start_xmit(struct sk_buff *skb,
+ struct net_device *dev) {
/* This flag indicate that the hardware can't perform a transmission.
* Theoritically, NET3 check it before sending a packet to the driver,
* but in fact it never do that and pool continuously.
@@ -1047,7 +1049,7 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} /* netwave_start_xmit */
/*
diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig
index 44411eb4e91b..83b635fd7784 100644
--- a/drivers/net/wireless/orinoco/Kconfig
+++ b/drivers/net/wireless/orinoco/Kconfig
@@ -1,6 +1,7 @@
config HERMES
tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211
+ depends on CFG80211
select WIRELESS_EXT
select FW_LOADER
select CRYPTO
diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile
index 1fc7409d6699..9abd6329bcbd 100644
--- a/drivers/net/wireless/orinoco/Makefile
+++ b/drivers/net/wireless/orinoco/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the orinoco wireless device drivers.
#
-orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o
+orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o cfg.o
obj-$(CONFIG_HERMES) += orinoco.o
obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c
index 8c4065f1b0d0..c60df2c1aca3 100644
--- a/drivers/net/wireless/orinoco/airport.c
+++ b/drivers/net/wireless/orinoco/airport.c
@@ -27,6 +27,7 @@
struct airport {
struct macio_dev *mdev;
void __iomem *vaddr;
+ unsigned int irq;
int irq_requested;
int ndev_registered;
};
@@ -34,8 +35,9 @@ struct airport {
static int
airport_suspend(struct macio_dev *mdev, pm_message_t state)
{
- struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
+ struct net_device *dev = priv->ndev;
+ struct airport *card = priv->card;
unsigned long flags;
int err;
@@ -48,18 +50,10 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state)
return 0;
}
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
-
- priv->hw_unavailable++;
-
+ orinoco_down(priv);
orinoco_unlock(priv, &flags);
- disable_irq(dev->irq);
+ disable_irq(card->irq);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
macio_get_of_node(mdev), 0, 0);
@@ -69,8 +63,9 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state)
static int
airport_resume(struct macio_dev *mdev)
{
- struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
+ struct net_device *dev = priv->ndev;
+ struct airport *card = priv->card;
unsigned long flags;
int err;
@@ -80,47 +75,27 @@ airport_resume(struct macio_dev *mdev)
macio_get_of_node(mdev), 0, 1);
msleep(200);
- enable_irq(dev->irq);
-
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n",
- dev->name, err);
- return 0;
- }
+ enable_irq(card->irq);
spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
-
- priv->hw_unavailable--;
-
- if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
- dev->name, err);
- }
-
-
+ err = orinoco_up(priv);
spin_unlock_irqrestore(&priv->lock, flags);
- return 0;
+ return err;
}
static int
airport_detach(struct macio_dev *mdev)
{
- struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
struct airport *card = priv->card;
if (card->ndev_registered)
- unregister_netdev(dev);
+ orinoco_if_del(priv);
card->ndev_registered = 0;
if (card->irq_requested)
- free_irq(dev->irq, dev);
+ free_irq(card->irq, priv);
card->irq_requested = 0;
if (card->vaddr)
@@ -134,7 +109,7 @@ airport_detach(struct macio_dev *mdev)
ssleep(1);
macio_set_drvdata(mdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
return 0;
}
@@ -146,7 +121,6 @@ static int airport_hard_reset(struct orinoco_private *priv)
* re-initialize properly, it falls in a screaming heap
* shortly afterwards. */
#if 0
- struct net_device *dev = priv->ndev;
struct airport *card = priv->card;
/* Vitally important. If we don't do this it seems we get an
@@ -154,7 +128,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
* hw_unavailable is already set it doesn't get ACKed, we get
* into an interrupt loop and the PMU decides to turn us
* off. */
- disable_irq(dev->irq);
+ disable_irq(card->irq);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
macio_get_of_node(card->mdev), 0, 0);
@@ -163,7 +137,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
macio_get_of_node(card->mdev), 0, 1);
ssleep(1);
- enable_irq(dev->irq);
+ enable_irq(card->irq);
ssleep(1);
#endif
@@ -174,7 +148,6 @@ static int
airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
{
struct orinoco_private *priv;
- struct net_device *dev;
struct airport *card;
unsigned long phys_addr;
hermes_t *hw;
@@ -185,33 +158,29 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
}
/* Allocate space for private device-specific data */
- dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
- airport_hard_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
+ airport_hard_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
return -ENODEV;
}
- priv = netdev_priv(dev);
card = priv->card;
hw = &priv->hw;
card->mdev = mdev;
- if (macio_request_resource(mdev, 0, "airport")) {
+ if (macio_request_resource(mdev, 0, DRIVER_NAME)) {
printk(KERN_ERR PFX "can't request IO resource !\n");
- free_orinocodev(dev);
+ free_orinocodev(priv);
return -EBUSY;
}
- SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
-
- macio_set_drvdata(mdev, dev);
+ macio_set_drvdata(mdev, priv);
/* Setup interrupts & base address */
- dev->irq = macio_irq(mdev, 0);
+ card->irq = macio_irq(mdev, 0);
phys_addr = macio_resource_start(mdev, 0); /* Physical address */
printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr);
- dev->base_addr = phys_addr;
card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
if (!card->vaddr) {
printk(KERN_ERR PFX "ioremap() failed\n");
@@ -228,18 +197,23 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
/* Reset it before we get the interrupt */
hermes_init(hw);
- if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) {
- printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq);
+ if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) {
+ printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq);
goto failed;
}
card->irq_requested = 1;
- /* Tell the stack we exist */
- if (register_netdev(dev) != 0) {
- printk(KERN_ERR PFX "register_netdev() failed\n");
+ /* Initialise the main driver */
+ if (orinoco_init(priv) != 0) {
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
+ goto failed;
+ }
+
+ /* Register an interface with the stack */
+ if (orinoco_if_add(priv, phys_addr, card->irq) != 0) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
}
- printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name);
card->ndev_registered = 1;
return 0;
failed:
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
new file mode 100644
index 000000000000..27f2d3342645
--- /dev/null
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -0,0 +1,203 @@
+/* cfg80211 support
+ *
+ * See copyright notice in main.c
+ */
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include "hw.h"
+#include "main.h"
+#include "orinoco.h"
+
+#include "cfg.h"
+
+/* Supported bitrates. Must agree with hw.c */
+static struct ieee80211_rate orinoco_rates[] = {
+ { .bitrate = 10 },
+ { .bitrate = 20 },
+ { .bitrate = 55 },
+ { .bitrate = 110 },
+};
+
+static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid;
+
+/* Called after orinoco_private is allocated. */
+void orinoco_wiphy_init(struct wiphy *wiphy)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+
+ wiphy->privid = orinoco_wiphy_privid;
+
+ set_wiphy_dev(wiphy, priv->dev);
+}
+
+/* Called after firmware is initialised */
+int orinoco_wiphy_register(struct wiphy *wiphy)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int i, channels = 0;
+
+ if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+ wiphy->max_scan_ssids = 1;
+ else
+ wiphy->max_scan_ssids = 0;
+
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
+ /* TODO: should we set if we only have demo ad-hoc?
+ * (priv->has_port3)
+ */
+ if (priv->has_ibss)
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+
+ if (!priv->broken_monitor || force_monitor)
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+
+ priv->band.bitrates = orinoco_rates;
+ priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates);
+
+ /* Only support channels allowed by the card EEPROM */
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (priv->channel_mask & (1 << i)) {
+ priv->channels[i].center_freq =
+ ieee80211_dsss_chan_to_freq(i+1);
+ channels++;
+ }
+ }
+ priv->band.channels = priv->channels;
+ priv->band.n_channels = channels;
+
+ wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ i = 0;
+ if (priv->has_wep) {
+ priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40;
+ i++;
+
+ if (priv->has_big_wep) {
+ priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104;
+ i++;
+ }
+ }
+ if (priv->has_wpa) {
+ priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP;
+ i++;
+ }
+ wiphy->cipher_suites = priv->cipher_suites;
+ wiphy->n_cipher_suites = i;
+
+ wiphy->rts_threshold = priv->rts_thresh;
+ if (!priv->has_mwo)
+ wiphy->frag_threshold = priv->frag_thresh;
+
+ return wiphy_register(wiphy);
+}
+
+static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int err = 0;
+ unsigned long lock;
+
+ if (orinoco_lock(priv, &lock) != 0)
+ return -EBUSY;
+
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ if (!priv->has_ibss && !priv->has_port3)
+ err = -EINVAL;
+ break;
+
+ case NL80211_IFTYPE_STATION:
+ break;
+
+ case NL80211_IFTYPE_MONITOR:
+ if (priv->broken_monitor && !force_monitor) {
+ printk(KERN_WARNING "%s: Monitor mode support is "
+ "buggy in this firmware, not enabling\n",
+ wiphy_name(wiphy));
+ err = -EINVAL;
+ }
+ break;
+
+ default:
+ err = -EINVAL;
+ }
+
+ if (!err) {
+ priv->iw_mode = type;
+ set_port_type(priv);
+ err = orinoco_commit(priv);
+ }
+
+ orinoco_unlock(priv, &lock);
+
+ return err;
+}
+
+static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int err;
+
+ if (!request)
+ return -EINVAL;
+
+ if (priv->scan_request && priv->scan_request != request)
+ return -EBUSY;
+
+ priv->scan_request = request;
+
+ err = orinoco_hw_trigger_scan(priv, request->ssids);
+
+ return err;
+}
+
+static int orinoco_set_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int err = 0;
+ unsigned long flags;
+ int channel;
+
+ if (!chan)
+ return -EINVAL;
+
+ if (channel_type != NL80211_CHAN_NO_HT)
+ return -EINVAL;
+
+ if (chan->band != IEEE80211_BAND_2GHZ)
+ return -EINVAL;
+
+ channel = ieee80211_freq_to_dsss_chan(chan->center_freq);
+
+ if ((channel < 1) || (channel > NUM_CHANNELS) ||
+ !(priv->channel_mask & (1 << (channel-1))))
+ return -EINVAL;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+ priv->channel = channel;
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
+ /* Fast channel change - no commit if successful */
+ hermes_t *hw = &priv->hw;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_SET_CHANNEL,
+ channel, NULL);
+ }
+ orinoco_unlock(priv, &flags);
+
+ return err;
+}
+
+const struct cfg80211_ops orinoco_cfg_ops = {
+ .change_virtual_intf = orinoco_change_vif,
+ .set_channel = orinoco_set_channel,
+ .scan = orinoco_scan,
+};
diff --git a/drivers/net/wireless/orinoco/cfg.h b/drivers/net/wireless/orinoco/cfg.h
new file mode 100644
index 000000000000..3ddc96a06cd7
--- /dev/null
+++ b/drivers/net/wireless/orinoco/cfg.h
@@ -0,0 +1,15 @@
+/* cfg80211 support.
+ *
+ * See copyright notice in main.c
+ */
+#ifndef ORINOCO_CFG_H
+#define ORINOCO_CFG_H
+
+#include <net/cfg80211.h>
+
+extern const struct cfg80211_ops orinoco_cfg_ops;
+
+void orinoco_wiphy_init(struct wiphy *wiphy);
+int orinoco_wiphy_register(struct wiphy *wiphy);
+
+#endif /* ORINOCO_CFG_H */
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c
index 1084b43e04bc..1257250a1e22 100644
--- a/drivers/net/wireless/orinoco/fw.c
+++ b/drivers/net/wireless/orinoco/fw.c
@@ -4,6 +4,7 @@
*/
#include <linux/kernel.h>
#include <linux/firmware.h>
+#include <linux/device.h>
#include "hermes.h"
#include "hermes_dld.h"
@@ -99,7 +100,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
const void *end;
const char *firmware;
const char *fw_err;
- struct net_device *dev = priv->ndev;
+ struct device *dev = priv->dev;
int err = 0;
pda = kzalloc(fw->pda_size, GFP_KERNEL);
@@ -111,12 +112,11 @@ orinoco_dl_firmware(struct orinoco_private *priv,
else
firmware = fw->sta_fw;
- printk(KERN_DEBUG "%s: Attempting to download firmware %s\n",
- dev->name, firmware);
+ dev_dbg(dev, "Attempting to download firmware %s\n", firmware);
/* Read current plug data */
err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
- printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err);
+ dev_dbg(dev, "Read PDA returned %d\n", err);
if (err)
goto free;
@@ -124,8 +124,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
err = request_firmware(&fw_entry, firmware, priv->dev);
if (err) {
- printk(KERN_ERR "%s: Cannot find firmware %s\n",
- dev->name, firmware);
+ dev_err(dev, "Cannot find firmware %s\n", firmware);
err = -ENOENT;
goto free;
}
@@ -136,16 +135,15 @@ orinoco_dl_firmware(struct orinoco_private *priv,
fw_err = validate_fw(hdr, fw_entry->size);
if (fw_err) {
- printk(KERN_WARNING "%s: Invalid firmware image detected (%s). "
- "Aborting download\n",
- dev->name, fw_err);
+ dev_warn(dev, "Invalid firmware image detected (%s). "
+ "Aborting download\n", fw_err);
err = -EINVAL;
goto abort;
}
/* Enable aux port to allow programming */
err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
- printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err);
+ dev_dbg(dev, "Program init returned %d\n", err);
if (err != 0)
goto abort;
@@ -156,7 +154,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
end = fw_entry->data + fw_entry->size;
err = hermes_program(hw, first_block, end);
- printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err);
+ dev_dbg(dev, "Program returned %d\n", err);
if (err != 0)
goto abort;
@@ -167,19 +165,18 @@ orinoco_dl_firmware(struct orinoco_private *priv,
err = hermes_apply_pda_with_defaults(hw, first_block, end, pda,
&pda[fw->pda_size / sizeof(*pda)]);
- printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err);
+ dev_dbg(dev, "Apply PDA returned %d\n", err);
if (err)
goto abort;
/* Tell card we've finished */
err = hermesi_program_end(hw);
- printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err);
+ dev_dbg(dev, "Program end returned %d\n", err);
if (err != 0)
goto abort;
/* Check if we're running */
- printk(KERN_DEBUG "%s: hermes_present returned %d\n",
- dev->name, hermes_present(hw));
+ dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw));
abort:
/* If we requested the firmware, release it. */
@@ -282,14 +279,13 @@ static int
symbol_dl_firmware(struct orinoco_private *priv,
const struct fw_info *fw)
{
- struct net_device *dev = priv->ndev;
+ struct device *dev = priv->dev;
int ret;
const struct firmware *fw_entry;
if (!orinoco_cached_fw_get(priv, true)) {
if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->pri_fw);
+ dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw);
return -ENOENT;
}
} else
@@ -302,15 +298,13 @@ symbol_dl_firmware(struct orinoco_private *priv,
if (!orinoco_cached_fw_get(priv, true))
release_firmware(fw_entry);
if (ret) {
- printk(KERN_ERR "%s: Primary firmware download failed\n",
- dev->name);
+ dev_err(dev, "Primary firmware download failed\n");
return ret;
}
if (!orinoco_cached_fw_get(priv, false)) {
if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->sta_fw);
+ dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw);
return -ENOENT;
}
} else
@@ -322,8 +316,7 @@ symbol_dl_firmware(struct orinoco_private *priv,
if (!orinoco_cached_fw_get(priv, false))
release_firmware(fw_entry);
if (ret) {
- printk(KERN_ERR "%s: Secondary firmware download failed\n",
- dev->name);
+ dev_err(dev, "Secondary firmware download failed\n");
}
return ret;
diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c
index f2c918c2572d..1a2fca76fd3c 100644
--- a/drivers/net/wireless/orinoco/hermes.c
+++ b/drivers/net/wireless/orinoco/hermes.c
@@ -469,7 +469,7 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
u16 rlength, rtype;
unsigned nwords;
- if ((bufsize < 0) || (bufsize % 2))
+ if (bufsize % 2)
return -EINVAL;
err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h
index c78c442a02c8..2dddbb597c4d 100644
--- a/drivers/net/wireless/orinoco/hermes.h
+++ b/drivers/net/wireless/orinoco/hermes.h
@@ -342,7 +342,7 @@ struct agere_ext_scan_info {
__le64 timestamp;
__le16 beacon_interval;
__le16 capabilities;
- u8 data[316];
+ u8 data[0];
} __attribute__ ((packed));
#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000)
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index a9ba195cdada..a3eefe109df4 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -309,7 +309,7 @@ int hermes_read_pda(hermes_t *hw,
/* Open auxiliary port */
ret = hermes_aux_control(hw, 1);
- printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret);
+ pr_debug(PFX "AUX enable returned %d\n", ret);
if (ret)
return ret;
@@ -319,12 +319,12 @@ int hermes_read_pda(hermes_t *hw,
/* Close aux port */
ret = hermes_aux_control(hw, 0);
- printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret);
+ pr_debug(PFX "AUX disable returned %d\n", ret);
/* Check PDA length */
pda_size = le16_to_cpu(pda[0]);
- printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n",
- pda_size, pda_len);
+ pr_debug(PFX "Actual PDA length %d, Max allowed %d\n",
+ pda_size, pda_len);
if (pda_size > pda_len)
return -EINVAL;
@@ -422,20 +422,19 @@ int hermesi_program_init(hermes_t *hw, u32 offset)
return err;
err = hermes_aux_control(hw, 1);
- printk(KERN_DEBUG PFX "AUX enable returned %d\n", err);
+ pr_debug(PFX "AUX enable returned %d\n", err);
if (err)
return err;
- printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
+ pr_debug(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
err = hermes_doicmd_wait(hw,
HERMES_PROGRAM_ENABLE_VOLATILE,
offset & 0xFFFFu,
offset >> 16,
0,
NULL);
- printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n",
- err);
+ pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err);
return err;
}
@@ -454,16 +453,16 @@ int hermesi_program_end(hermes_t *hw)
rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
- printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, "
- "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
- rc, resp.resp0, resp.resp1, resp.resp2);
+ pr_debug(PFX "PROGRAM_DISABLE returned %d, "
+ "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
+ rc, resp.resp0, resp.resp1, resp.resp2);
if ((rc == 0) &&
((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
rc = -EIO;
err = hermes_aux_control(hw, 0);
- printk(KERN_DEBUG PFX "AUX disable returned %d\n", err);
+ pr_debug(PFX "AUX disable returned %d\n", err);
/* Acknowledge any outstanding command */
hermes_write_regn(hw, EVACK, 0xFFFF);
@@ -496,9 +495,8 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
while ((blkaddr != BLOCK_END) &&
(((void *) blk + blklen) <= end)) {
- printk(KERN_DEBUG PFX
- "Programming block of length %d to address 0x%08x\n",
- blklen, blkaddr);
+ pr_debug(PFX "Programming block of length %d "
+ "to address 0x%08x\n", blklen, blkaddr);
#if !LIMIT_PROGRAM_SIZE
/* wl_lkm driver splits this into writes of 2000 bytes */
@@ -510,10 +508,9 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
addr = blkaddr;
while (addr < (blkaddr + blklen)) {
- printk(KERN_DEBUG PFX
- "Programming subblock of length %d "
- "to address 0x%08x. Data @ %p\n",
- len, addr, &blk->data[addr - blkaddr]);
+ pr_debug(PFX "Programming subblock of length %d "
+ "to address 0x%08x. Data @ %p\n",
+ len, addr, &blk->data[addr - blkaddr]);
hermes_aux_setaddr(hw, addr);
hermes_write_bytes(hw, HERMES_AUXDATA,
@@ -643,8 +640,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
if (pdi)
- printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
- record_id, pdi);
+ pr_debug(PFX "Found record 0x%04x at %p\n",
+ record_id, pdi);
switch (record_id) {
case 0x110: /* Modem REFDAC values */
@@ -654,9 +651,9 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
default_pdi = NULL;
if (outdoor_pdi) {
pdi = outdoor_pdi;
- printk(KERN_DEBUG PFX
- "Using outdoor record 0x%04x at %p\n",
- record_id + 1, pdi);
+ pr_debug(PFX
+ "Using outdoor record 0x%04x at %p\n",
+ record_id + 1, pdi);
}
break;
case 0x5: /* HWIF Compatiblity */
@@ -684,9 +681,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
if (!pdi && default_pdi) {
/* Use default */
pdi = default_pdi;
- printk(KERN_DEBUG PFX
- "Using default record 0x%04x at %p\n",
- record_id, pdi);
+ pr_debug(PFX "Using default record 0x%04x at %p\n",
+ record_id, pdi);
}
if (pdi) {
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index b3946272c72e..359652d35e63 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -3,16 +3,22 @@
* See copyright notice in main.c
*/
#include <linux/kernel.h>
+#include <linux/device.h>
#include <linux/if_arp.h>
#include <linux/ieee80211.h>
#include <linux/wireless.h>
-
+#include <net/cfg80211.h>
#include "hermes.h"
#include "hermes_rid.h"
#include "orinoco.h"
#include "hw.h"
+#define SYMBOL_MAX_VER_LEN (14)
+
+/* Symbol firmware has a bug allocating buffers larger than this */
+#define TX_NICBUF_SIZE_BUG 1585
+
/********************************************************************/
/* Data tables */
/********************************************************************/
@@ -36,6 +42,343 @@ static const struct {
};
#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
+/* Firmware version encoding */
+struct comp_id {
+ u16 id, variant, major, minor;
+} __attribute__ ((packed));
+
+static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
+{
+ if (nic_id->id < 0x8000)
+ return FIRMWARE_TYPE_AGERE;
+ else if (nic_id->id == 0x8000 && nic_id->major == 0)
+ return FIRMWARE_TYPE_SYMBOL;
+ else
+ return FIRMWARE_TYPE_INTERSIL;
+}
+
+/* Set priv->firmware type, determine firmware properties
+ * This function can be called before we have registerred with netdev,
+ * so all errors go out with dev_* rather than printk
+ */
+int determine_fw_capabilities(struct orinoco_private *priv)
+{
+ struct device *dev = priv->dev;
+ hermes_t *hw = &priv->hw;
+ int err;
+ struct comp_id nic_id, sta_id;
+ unsigned int firmver;
+ char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
+
+ /* Get the hardware version */
+ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
+ if (err) {
+ dev_err(dev, "Cannot read hardware identity: error %d\n",
+ err);
+ return err;
+ }
+
+ le16_to_cpus(&nic_id.id);
+ le16_to_cpus(&nic_id.variant);
+ le16_to_cpus(&nic_id.major);
+ le16_to_cpus(&nic_id.minor);
+ dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n",
+ nic_id.id, nic_id.variant, nic_id.major, nic_id.minor);
+
+ priv->firmware_type = determine_firmware_type(&nic_id);
+
+ /* Get the firmware version */
+ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
+ if (err) {
+ dev_err(dev, "Cannot read station identity: error %d\n",
+ err);
+ return err;
+ }
+
+ le16_to_cpus(&sta_id.id);
+ le16_to_cpus(&sta_id.variant);
+ le16_to_cpus(&sta_id.major);
+ le16_to_cpus(&sta_id.minor);
+ dev_info(dev, "Station identity %04x:%04x:%04x:%04x\n",
+ sta_id.id, sta_id.variant, sta_id.major, sta_id.minor);
+
+ switch (sta_id.id) {
+ case 0x15:
+ dev_err(dev, "Primary firmware is active\n");
+ return -ENODEV;
+ case 0x14b:
+ dev_err(dev, "Tertiary firmware is active\n");
+ return -ENODEV;
+ case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */
+ case 0x21: /* Symbol Spectrum24 Trilogy */
+ break;
+ default:
+ dev_notice(dev, "Unknown station ID, please report\n");
+ break;
+ }
+
+ /* Default capabilities */
+ priv->has_sensitivity = 1;
+ priv->has_mwo = 0;
+ priv->has_preamble = 0;
+ priv->has_port3 = 1;
+ priv->has_ibss = 1;
+ priv->has_wep = 0;
+ priv->has_big_wep = 0;
+ priv->has_alt_txcntl = 0;
+ priv->has_ext_scan = 0;
+ priv->has_wpa = 0;
+ priv->do_fw_download = 0;
+
+ /* Determine capabilities from the firmware version */
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_AGERE:
+ /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
+ ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
+ snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+ "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
+
+ firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
+
+ priv->has_ibss = (firmver >= 0x60006);
+ priv->has_wep = (firmver >= 0x40020);
+ priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
+ Gold cards from the others? */
+ priv->has_mwo = (firmver >= 0x60000);
+ priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
+ priv->ibss_port = 1;
+ priv->has_hostscan = (firmver >= 0x8000a);
+ priv->do_fw_download = 1;
+ priv->broken_monitor = (firmver >= 0x80000);
+ priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
+ priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
+ priv->has_wpa = (firmver >= 0x9002a);
+ /* Tested with Agere firmware :
+ * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
+ * Tested CableTron firmware : 4.32 => Anton */
+ break;
+ case FIRMWARE_TYPE_SYMBOL:
+ /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
+ /* Intel MAC : 00:02:B3:* */
+ /* 3Com MAC : 00:50:DA:* */
+ memset(tmp, 0, sizeof(tmp));
+ /* Get the Symbol firmware version */
+ err = hermes_read_ltv(hw, USER_BAP,
+ HERMES_RID_SECONDARYVERSION_SYMBOL,
+ SYMBOL_MAX_VER_LEN, NULL, &tmp);
+ if (err) {
+ dev_warn(dev, "Error %d reading Symbol firmware info. "
+ "Wildly guessing capabilities...\n", err);
+ firmver = 0;
+ tmp[0] = '\0';
+ } else {
+ /* The firmware revision is a string, the format is
+ * something like : "V2.20-01".
+ * Quick and dirty parsing... - Jean II
+ */
+ firmver = ((tmp[1] - '0') << 16)
+ | ((tmp[3] - '0') << 12)
+ | ((tmp[4] - '0') << 8)
+ | ((tmp[6] - '0') << 4)
+ | (tmp[7] - '0');
+
+ tmp[SYMBOL_MAX_VER_LEN] = '\0';
+ }
+
+ snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+ "Symbol %s", tmp);
+
+ priv->has_ibss = (firmver >= 0x20000);
+ priv->has_wep = (firmver >= 0x15012);
+ priv->has_big_wep = (firmver >= 0x20000);
+ priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
+ (firmver >= 0x29000 && firmver < 0x30000) ||
+ firmver >= 0x31000;
+ priv->has_preamble = (firmver >= 0x20000);
+ priv->ibss_port = 4;
+
+ /* Symbol firmware is found on various cards, but
+ * there has been no attempt to check firmware
+ * download on non-spectrum_cs based cards.
+ *
+ * Given that the Agere firmware download works
+ * differently, we should avoid doing a firmware
+ * download with the Symbol algorithm on non-spectrum
+ * cards.
+ *
+ * For now we can identify a spectrum_cs based card
+ * because it has a firmware reset function.
+ */
+ priv->do_fw_download = (priv->stop_fw != NULL);
+
+ priv->broken_disableport = (firmver == 0x25013) ||
+ (firmver >= 0x30000 && firmver <= 0x31000);
+ priv->has_hostscan = (firmver >= 0x31001) ||
+ (firmver >= 0x29057 && firmver < 0x30000);
+ /* Tested with Intel firmware : 0x20015 => Jean II */
+ /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
+ break;
+ case FIRMWARE_TYPE_INTERSIL:
+ /* D-Link, Linksys, Adtron, ZoomAir, and many others...
+ * Samsung, Compaq 100/200 and Proxim are slightly
+ * different and less well tested */
+ /* D-Link MAC : 00:40:05:* */
+ /* Addtron MAC : 00:90:D1:* */
+ snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+ "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
+ sta_id.variant);
+
+ firmver = ((unsigned long)sta_id.major << 16) |
+ ((unsigned long)sta_id.minor << 8) | sta_id.variant;
+
+ priv->has_ibss = (firmver >= 0x000700); /* FIXME */
+ priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
+ priv->has_pm = (firmver >= 0x000700);
+ priv->has_hostscan = (firmver >= 0x010301);
+
+ if (firmver >= 0x000800)
+ priv->ibss_port = 0;
+ else {
+ dev_notice(dev, "Intersil firmware earlier than v0.8.x"
+ " - several features not supported\n");
+ priv->ibss_port = 1;
+ }
+ break;
+ }
+ dev_info(dev, "Firmware determined as %s\n", priv->fw_name);
+
+ return 0;
+}
+
+/* Read settings from EEPROM into our private structure.
+ * MAC address gets dropped into callers buffer
+ * Can be called before netdev registration.
+ */
+int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
+{
+ struct device *dev = priv->dev;
+ struct hermes_idstring nickbuf;
+ hermes_t *hw = &priv->hw;
+ int len;
+ int err;
+ u16 reclen;
+
+ /* Get the MAC address */
+ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+ ETH_ALEN, NULL, dev_addr);
+ if (err) {
+ dev_warn(dev, "Failed to read MAC address!\n");
+ goto out;
+ }
+
+ dev_dbg(dev, "MAC address %pM\n", dev_addr);
+
+ /* Get the station name */
+ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+ sizeof(nickbuf), &reclen, &nickbuf);
+ if (err) {
+ dev_err(dev, "failed to read station name\n");
+ goto out;
+ }
+ if (nickbuf.len)
+ len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
+ else
+ len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
+ memcpy(priv->nick, &nickbuf.val, len);
+ priv->nick[len] = '\0';
+
+ dev_dbg(dev, "Station name \"%s\"\n", priv->nick);
+
+ /* Get allowed channels */
+ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
+ &priv->channel_mask);
+ if (err) {
+ dev_err(dev, "Failed to read channel list!\n");
+ goto out;
+ }
+
+ /* Get initial AP density */
+ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
+ &priv->ap_density);
+ if (err || priv->ap_density < 1 || priv->ap_density > 3)
+ priv->has_sensitivity = 0;
+
+ /* Get initial RTS threshold */
+ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+ &priv->rts_thresh);
+ if (err) {
+ dev_err(dev, "Failed to read RTS threshold!\n");
+ goto out;
+ }
+
+ /* Get initial fragmentation settings */
+ if (priv->has_mwo)
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMWOROBUST_AGERE,
+ &priv->mwo_robust);
+ else
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+ &priv->frag_thresh);
+ if (err) {
+ dev_err(dev, "Failed to read fragmentation settings!\n");
+ goto out;
+ }
+
+ /* Power management setup */
+ if (priv->has_pm) {
+ priv->pm_on = 0;
+ priv->pm_mcast = 1;
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMAXSLEEPDURATION,
+ &priv->pm_period);
+ if (err) {
+ dev_err(dev, "Failed to read power management "
+ "period!\n");
+ goto out;
+ }
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPMHOLDOVERDURATION,
+ &priv->pm_timeout);
+ if (err) {
+ dev_err(dev, "Failed to read power management "
+ "timeout!\n");
+ goto out;
+ }
+ }
+
+ /* Preamble setup */
+ if (priv->has_preamble) {
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPREAMBLE_SYMBOL,
+ &priv->preamble);
+ }
+
+out:
+ return err;
+}
+
+/* Can be called before netdev registration */
+int orinoco_hw_allocate_fid(struct orinoco_private *priv)
+{
+ struct device *dev = priv->dev;
+ struct hermes *hw = &priv->hw;
+ int err;
+
+ err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+ if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
+ /* Try workaround for old Symbol firmware bug */
+ priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
+ err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+
+ dev_warn(dev, "Firmware ALLOC bug detected "
+ "(old Symbol firmware?). Work around %s\n",
+ err ? "failed!" : "ok.");
+ }
+
+ return err;
+}
+
int orinoco_get_bitratemode(int bitrate, int automatic)
{
int ratemode = -1;
@@ -63,12 +406,243 @@ void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic)
*automatic = bitrate_table[ratemode].automatic;
}
+int orinoco_hw_program_rids(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ struct wireless_dev *wdev = netdev_priv(dev);
+ hermes_t *hw = &priv->hw;
+ int err;
+ struct hermes_idstring idbuf;
+
+ /* Set the MAC address */
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+ HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting MAC address\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set up the link mode */
+ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
+ priv->port_type);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting port type\n",
+ dev->name, err);
+ return err;
+ }
+ /* Set the channel/frequency */
+ if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFOWNCHANNEL,
+ priv->channel);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting channel %d\n",
+ dev->name, err, priv->channel);
+ return err;
+ }
+ }
+
+ if (priv->has_ibss) {
+ u16 createibss;
+
+ if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
+ printk(KERN_WARNING "%s: This firmware requires an "
+ "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
+ /* With wvlan_cs, in this case, we would crash.
+ * hopefully, this driver will behave better...
+ * Jean II */
+ createibss = 0;
+ } else {
+ createibss = priv->createibss;
+ }
+
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFCREATEIBSS,
+ createibss);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ /* Set the desired BSSID */
+ err = __orinoco_hw_set_wap(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting AP address\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set the desired ESSID */
+ idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
+ memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
+ /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
+ HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+ &idbuf);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
+ dev->name, err);
+ return err;
+ }
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
+ HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+ &idbuf);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set the station name */
+ idbuf.len = cpu_to_le16(strlen(priv->nick));
+ memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+ HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
+ &idbuf);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting nickname\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set AP density */
+ if (priv->has_sensitivity) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSYSTEMSCALE,
+ priv->ap_density);
+ if (err) {
+ printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
+ "Disabling sensitivity control\n",
+ dev->name, err);
+
+ priv->has_sensitivity = 0;
+ }
+ }
+
+ /* Set RTS threshold */
+ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+ priv->rts_thresh);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set fragmentation threshold or MWO robustness */
+ if (priv->has_mwo)
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMWOROBUST_AGERE,
+ priv->mwo_robust);
+ else
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+ priv->frag_thresh);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting fragmentation\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set bitrate */
+ err = __orinoco_hw_set_bitrate(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting bitrate\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set power management */
+ if (priv->has_pm) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPMENABLED,
+ priv->pm_on);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMULTICASTRECEIVE,
+ priv->pm_mcast);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMAXSLEEPDURATION,
+ priv->pm_period);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPMHOLDOVERDURATION,
+ priv->pm_timeout);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ /* Set preamble - only for Symbol so far... */
+ if (priv->has_preamble) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPREAMBLE_SYMBOL,
+ priv->preamble);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting preamble\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ /* Set up encryption */
+ if (priv->has_wep || priv->has_wpa) {
+ err = __orinoco_hw_setup_enc(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d activating encryption\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
+ /* Enable monitor mode */
+ dev->type = ARPHRD_IEEE80211;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_MONITOR, 0, NULL);
+ } else {
+ /* Disable monitor mode */
+ dev->type = ARPHRD_ETHER;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_STOP, 0, NULL);
+ }
+ if (err)
+ return err;
+
+ /* Reset promiscuity / multicast*/
+ priv->promiscuous = 0;
+ priv->mc_count = 0;
+
+ /* Record mode change */
+ wdev->iftype = priv->iw_mode;
+
+ return 0;
+}
+
/* Get tsc from the firmware */
int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
{
hermes_t *hw = &priv->hw;
int err = 0;
- u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE];
+ u8 tsc_arr[4][ORINOCO_SEQ_LEN];
if ((key < 0) || (key >= 4))
return -EINVAL;
@@ -194,12 +768,29 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
{
hermes_t *hw = &priv->hw;
int err = 0;
+ int i;
switch (priv->firmware_type) {
case FIRMWARE_TYPE_AGERE:
+ {
+ struct orinoco_key keys[ORINOCO_MAX_KEYS];
+
+ memset(&keys, 0, sizeof(keys));
+ for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
+ int len = min(priv->keys[i].key_len,
+ ORINOCO_MAX_KEY_SIZE);
+ memcpy(&keys[i].data, priv->keys[i].key, len);
+ if (len > SMALL_KEY_SIZE)
+ keys[i].len = cpu_to_le16(LARGE_KEY_SIZE);
+ else if (len > 0)
+ keys[i].len = cpu_to_le16(SMALL_KEY_SIZE);
+ else
+ keys[i].len = cpu_to_le16(0);
+ }
+
err = HERMES_WRITE_RECORD(hw, USER_BAP,
HERMES_RID_CNFWEPKEYS_AGERE,
- &priv->keys);
+ &keys);
if (err)
return err;
err = hermes_write_wordrec(hw, USER_BAP,
@@ -208,28 +799,38 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
if (err)
return err;
break;
+ }
case FIRMWARE_TYPE_INTERSIL:
case FIRMWARE_TYPE_SYMBOL:
{
int keylen;
- int i;
/* Force uniform key length to work around
* firmware bugs */
- keylen = le16_to_cpu(priv->keys[priv->tx_key].len);
+ keylen = priv->keys[priv->tx_key].key_len;
if (keylen > LARGE_KEY_SIZE) {
printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
priv->ndev->name, priv->tx_key, keylen);
return -E2BIG;
- }
+ } else if (keylen > SMALL_KEY_SIZE)
+ keylen = LARGE_KEY_SIZE;
+ else if (keylen > 0)
+ keylen = SMALL_KEY_SIZE;
+ else
+ keylen = 0;
/* Write all 4 keys */
for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
+ u8 key[LARGE_KEY_SIZE] = { 0 };
+
+ memcpy(key, priv->keys[i].key,
+ priv->keys[i].key_len);
+
err = hermes_write_ltv(hw, USER_BAP,
HERMES_RID_CNFDEFAULTKEY0 + i,
HERMES_BYTES_TO_RECLEN(keylen),
- priv->keys[i].data);
+ key);
if (err)
return err;
}
@@ -255,8 +856,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
int auth_flag;
int enc_flag;
- /* Setup WEP keys for WEP and WPA */
- if (priv->encode_alg)
+ /* Setup WEP keys */
+ if (priv->encode_alg == ORINOCO_ALG_WEP)
__orinoco_hw_setup_wepkeys(priv);
if (priv->wep_restrict)
@@ -266,14 +867,14 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
if (priv->wpa_enabled)
enc_flag = 2;
- else if (priv->encode_alg == IW_ENCODE_ALG_WEP)
+ else if (priv->encode_alg == ORINOCO_ALG_WEP)
enc_flag = 1;
else
enc_flag = 0;
switch (priv->firmware_type) {
case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
- if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
+ if (priv->encode_alg == ORINOCO_ALG_WEP) {
/* Enable the shared-key authentication. */
err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFAUTHENTICATION_AGERE,
@@ -298,7 +899,7 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
- if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
+ if (priv->encode_alg == ORINOCO_ALG_WEP) {
if (priv->wep_restrict ||
(priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
@@ -314,7 +915,7 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
} else
master_wep_flag = 0;
- if (priv->iw_mode == IW_MODE_MONITOR)
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
/* Master WEP setting : on/off */
@@ -331,20 +932,22 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
}
/* key must be 32 bytes, including the tx and rx MIC keys.
- * rsc must be 8 bytes
- * tsc must be 8 bytes or NULL
+ * rsc must be NULL or up to 8 bytes
+ * tsc must be NULL or up to 8 bytes
*/
-int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
- u8 *key, u8 *rsc, u8 *tsc)
+int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
+ int set_tx, u8 *key, u8 *rsc, size_t rsc_len,
+ u8 *tsc, size_t tsc_len)
{
struct {
__le16 idx;
- u8 rsc[IW_ENCODE_SEQ_MAX_SIZE];
+ u8 rsc[ORINOCO_SEQ_LEN];
u8 key[TKIP_KEYLEN];
u8 tx_mic[MIC_KEYLEN];
u8 rx_mic[MIC_KEYLEN];
- u8 tsc[IW_ENCODE_SEQ_MAX_SIZE];
+ u8 tsc[ORINOCO_SEQ_LEN];
} __attribute__ ((packed)) buf;
+ hermes_t *hw = &priv->hw;
int ret;
int err;
int k;
@@ -359,17 +962,22 @@ int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
memcpy(buf.key, key,
sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic));
- if (rsc == NULL)
- memset(buf.rsc, 0, sizeof(buf.rsc));
- else
- memcpy(buf.rsc, rsc, sizeof(buf.rsc));
+ if (rsc_len > sizeof(buf.rsc))
+ rsc_len = sizeof(buf.rsc);
+
+ if (tsc_len > sizeof(buf.tsc))
+ tsc_len = sizeof(buf.tsc);
- if (tsc == NULL) {
- memset(buf.tsc, 0, sizeof(buf.tsc));
+ memset(buf.rsc, 0, sizeof(buf.rsc));
+ memset(buf.tsc, 0, sizeof(buf.tsc));
+
+ if (rsc != NULL)
+ memcpy(buf.rsc, rsc, rsc_len);
+
+ if (tsc != NULL)
+ memcpy(buf.tsc, tsc, tsc_len);
+ else
buf.tsc[4] = 0x10;
- } else {
- memcpy(buf.tsc, tsc, sizeof(buf.tsc));
- }
/* Wait upto 100ms for tx queue to empty */
for (k = 100; k > 0; k--) {
@@ -395,7 +1003,6 @@ int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx)
hermes_t *hw = &priv->hw;
int err;
- memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx]));
err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
key_idx);
@@ -582,3 +1189,124 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
return 0;
}
+
+int orinoco_hw_trigger_scan(struct orinoco_private *priv,
+ const struct cfg80211_ssid *ssid)
+{
+ struct net_device *dev = priv->ndev;
+ hermes_t *hw = &priv->hw;
+ unsigned long flags;
+ int err = 0;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+ /* Scanning with port 0 disabled would fail */
+ if (!netif_running(dev)) {
+ err = -ENETDOWN;
+ goto out;
+ }
+
+ /* In monitor mode, the scan results are always empty.
+ * Probe responses are passed to the driver as received
+ * frames and could be processed in software. */
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (priv->has_hostscan) {
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_SYMBOL:
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFHOSTSCAN_SYMBOL,
+ HERMES_HOSTSCAN_SYMBOL_ONCE |
+ HERMES_HOSTSCAN_SYMBOL_BCAST);
+ break;
+ case FIRMWARE_TYPE_INTERSIL: {
+ __le16 req[3];
+
+ req[0] = cpu_to_le16(0x3fff); /* All channels */
+ req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
+ req[2] = 0; /* Any ESSID */
+ err = HERMES_WRITE_RECORD(hw, USER_BAP,
+ HERMES_RID_CNFHOSTSCAN, &req);
+ break;
+ }
+ case FIRMWARE_TYPE_AGERE:
+ if (ssid->ssid_len > 0) {
+ struct hermes_idstring idbuf;
+ size_t len = ssid->ssid_len;
+
+ idbuf.len = cpu_to_le16(len);
+ memcpy(idbuf.val, ssid->ssid, len);
+
+ err = hermes_write_ltv(hw, USER_BAP,
+ HERMES_RID_CNFSCANSSID_AGERE,
+ HERMES_BYTES_TO_RECLEN(len + 2),
+ &idbuf);
+ } else
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSCANSSID_AGERE,
+ 0); /* Any ESSID */
+ if (err)
+ break;
+
+ if (priv->has_ext_scan) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSCANCHANNELS2GHZ,
+ 0x7FFF);
+ if (err)
+ goto out;
+
+ err = hermes_inquire(hw,
+ HERMES_INQ_CHANNELINFO);
+ } else
+ err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+ break;
+ }
+ } else
+ err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+ out:
+ orinoco_unlock(priv, &flags);
+
+ return err;
+}
+
+/* Disassociate from node with BSSID addr */
+int orinoco_hw_disassociate(struct orinoco_private *priv,
+ u8 *addr, u16 reason_code)
+{
+ hermes_t *hw = &priv->hw;
+ int err;
+
+ struct {
+ u8 addr[ETH_ALEN];
+ __le16 reason_code;
+ } __attribute__ ((packed)) buf;
+
+ /* Currently only supported by WPA enabled Agere fw */
+ if (!priv->has_wpa)
+ return -EOPNOTSUPP;
+
+ memcpy(buf.addr, addr, ETH_ALEN);
+ buf.reason_code = cpu_to_le16(reason_code);
+ err = HERMES_WRITE_RECORD(hw, USER_BAP,
+ HERMES_RID_CNFDISASSOCIATE,
+ &buf);
+ return err;
+}
+
+int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
+ u8 *addr)
+{
+ hermes_t *hw = &priv->hw;
+ int err;
+
+ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+ ETH_ALEN, NULL, addr);
+
+ return err;
+}
diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h
index dc3f23a9c1c7..8df6e8752be6 100644
--- a/drivers/net/wireless/orinoco/hw.h
+++ b/drivers/net/wireless/orinoco/hw.h
@@ -7,6 +7,7 @@
#include <linux/types.h>
#include <linux/wireless.h>
+#include <net/cfg80211.h>
/* Hardware BAPs */
#define USER_BAP 0
@@ -23,17 +24,22 @@
struct orinoco_private;
struct dev_addr_list;
+int determine_fw_capabilities(struct orinoco_private *priv);
+int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr);
+int orinoco_hw_allocate_fid(struct orinoco_private *priv);
int orinoco_get_bitratemode(int bitrate, int automatic);
void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic);
+int orinoco_hw_program_rids(struct orinoco_private *priv);
int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc);
int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate);
int __orinoco_hw_set_wap(struct orinoco_private *priv);
int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv);
int __orinoco_hw_setup_enc(struct orinoco_private *priv);
-int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
- u8 *key, u8 *rsc, u8 *tsc);
+int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
+ int set_tx, u8 *key, u8 *rsc, size_t rsc_len,
+ u8 *tsc, size_t tsc_len);
int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
struct dev_addr_list *mc_list,
@@ -43,5 +49,11 @@ int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
int orinoco_hw_get_freq(struct orinoco_private *priv);
int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
int *numrates, s32 *rates, int max);
+int orinoco_hw_trigger_scan(struct orinoco_private *priv,
+ const struct cfg80211_ssid *ssid);
+int orinoco_hw_disassociate(struct orinoco_private *priv,
+ u8 *addr, u16 reason_code);
+int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
+ u8 *addr);
#endif /* _ORINOCO_HW_H_ */
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index a370e510f19f..7a32bcb0c037 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -80,6 +80,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
@@ -88,6 +89,7 @@
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "hermes_rid.h"
#include "hermes_dld.h"
@@ -96,6 +98,7 @@
#include "mic.h"
#include "fw.h"
#include "wext.h"
+#include "cfg.h"
#include "main.h"
#include "orinoco.h"
@@ -142,13 +145,11 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
#define ORINOCO_MIN_MTU 256
#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
-#define SYMBOL_MAX_VER_LEN (14)
#define MAX_IRQLOOPS_PER_IRQ 10
#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of
* how many events the
* device could
* legitimately generate */
-#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */
#define DUMMY_FID 0xFFFF
@@ -205,11 +206,21 @@ struct orinoco_rx_data {
struct list_head list;
};
+struct orinoco_scan_data {
+ void *buf;
+ size_t len;
+ int type;
+ struct list_head list;
+};
+
/********************************************************************/
/* Function prototypes */
/********************************************************************/
-static void __orinoco_set_multicast_list(struct net_device *dev);
+static int __orinoco_set_multicast_list(struct net_device *dev);
+static int __orinoco_up(struct orinoco_private *priv);
+static int __orinoco_down(struct orinoco_private *priv);
+static int __orinoco_commit(struct orinoco_private *priv);
/********************************************************************/
/* Internal helper functions */
@@ -218,11 +229,11 @@ static void __orinoco_set_multicast_list(struct net_device *dev);
void set_port_type(struct orinoco_private *priv)
{
switch (priv->iw_mode) {
- case IW_MODE_INFRA:
+ case NL80211_IFTYPE_STATION:
priv->port_type = 1;
priv->createibss = 0;
break;
- case IW_MODE_ADHOC:
+ case NL80211_IFTYPE_ADHOC:
if (priv->prefer_port3) {
priv->port_type = 3;
priv->createibss = 0;
@@ -231,7 +242,7 @@ void set_port_type(struct orinoco_private *priv)
priv->createibss = 1;
}
break;
- case IW_MODE_MONITOR:
+ case NL80211_IFTYPE_MONITOR:
priv->port_type = 3;
priv->createibss = 0;
break;
@@ -247,14 +258,14 @@ void set_port_type(struct orinoco_private *priv)
static int orinoco_open(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int err;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- err = __orinoco_up(dev);
+ err = __orinoco_up(priv);
if (!err)
priv->open = 1;
@@ -266,7 +277,7 @@ static int orinoco_open(struct net_device *dev)
static int orinoco_stop(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = 0;
/* We mustn't use orinoco_lock() here, because we need to be
@@ -276,7 +287,7 @@ static int orinoco_stop(struct net_device *dev)
priv->open = 0;
- err = __orinoco_down(dev);
+ err = __orinoco_down(priv);
spin_unlock_irq(&priv->lock);
@@ -285,14 +296,14 @@ static int orinoco_stop(struct net_device *dev)
static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
return &priv->stats;
}
static void orinoco_set_multicast_list(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0) {
@@ -307,7 +318,7 @@ static void orinoco_set_multicast_list(struct net_device *dev)
static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
if ((new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU))
return -EINVAL;
@@ -326,16 +337,18 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
/* Tx path */
/********************************************************************/
-static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
+ struct orinoco_tkip_key *key;
hermes_t *hw = &priv->hw;
int err = 0;
u16 txfid = priv->txfid;
struct ethhdr *eh;
int tx_control;
unsigned long flags;
+ int do_mic;
if (!netif_running(dev)) {
printk(KERN_ERR "%s: Tx on stopped device!\n",
@@ -355,7 +368,8 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY;
}
- if (!netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
+ if (!netif_carrier_ok(dev) ||
+ (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
/* Oops, the firmware hasn't established a connection,
silently drop the packet (this seems to be the
safest approach). */
@@ -366,9 +380,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < ETH_HLEN)
goto drop;
+ key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
+
+ do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
+ (key != NULL));
+
tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
- if (priv->encode_alg == IW_ENCODE_ALG_TKIP)
+ if (do_mic)
tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
HERMES_TXCTRL_MIC;
@@ -450,7 +469,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* Calculate Michael MIC */
- if (priv->encode_alg == IW_ENCODE_ALG_TKIP) {
+ if (do_mic) {
u8 mic_buf[MICHAEL_MIC_LEN + 1];
u8 *mic;
size_t offset;
@@ -468,8 +487,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
len = MICHAEL_MIC_LEN;
}
- orinoco_mic(priv->tx_tfm_mic,
- priv->tkip_key[priv->tx_key].tx_mic,
+ orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
eh->h_dest, eh->h_source, 0 /* priority */,
skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
@@ -518,7 +536,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
u16 fid = hermes_read_regn(hw, ALLOCFID);
if (fid != priv->txfid) {
@@ -533,7 +551,7 @@ static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
stats->tx_packets++;
@@ -545,7 +563,7 @@ static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
u16 fid = hermes_read_regn(hw, TXCOMPLFID);
u16 status;
@@ -601,7 +619,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
static void orinoco_tx_timeout(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
struct hermes *hw = &priv->hw;
@@ -650,7 +668,7 @@ static void orinoco_stat_gather(struct net_device *dev,
struct sk_buff *skb,
struct hermes_rx_descriptor *desc)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
/* Using spy support with lots of Rx packets, like in an
* infrastructure (AP), will really slow down everything, because
@@ -687,7 +705,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
int err;
int len;
struct sk_buff *skb;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
hermes_t *hw = &priv->hw;
@@ -778,7 +796,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
struct iw_statistics *wstats = &priv->wstats;
struct sk_buff *skb = NULL;
@@ -816,7 +834,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
}
/* Handle frames in monitor mode */
- if (priv->iw_mode == IW_MODE_MONITOR) {
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
orinoco_rx_monitor(dev, rxfid, desc);
goto out;
}
@@ -902,7 +920,7 @@ static void orinoco_rx(struct net_device *dev,
struct hermes_rx_descriptor *desc,
struct sk_buff *skb)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
u16 status, fc;
int length;
@@ -914,6 +932,7 @@ static void orinoco_rx(struct net_device *dev,
/* Calculate and check MIC */
if (status & HERMES_RXSTAT_MIC) {
+ struct orinoco_tkip_key *key;
int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >>
HERMES_MIC_KEY_ID_SHIFT);
u8 mic[MICHAEL_MIC_LEN];
@@ -927,14 +946,18 @@ static void orinoco_rx(struct net_device *dev,
skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
length -= MICHAEL_MIC_LEN;
- orinoco_mic(priv->rx_tfm_mic,
- priv->tkip_key[key_id].rx_mic,
- desc->addr1,
- src,
+ key = (struct orinoco_tkip_key *) priv->keys[key_id].key;
+
+ if (!key) {
+ printk(KERN_WARNING "%s: Received encrypted frame from "
+ "%pM using key %i, but key is not installed\n",
+ dev->name, src, key_id);
+ goto drop;
+ }
+
+ orinoco_mic(priv->rx_tfm_mic, key->rx_mic, desc->addr1, src,
0, /* priority or QoS? */
- skb->data,
- skb->len,
- &mic[0]);
+ skb->data, skb->len, &mic[0]);
if (memcmp(mic, rxmic,
MICHAEL_MIC_LEN)) {
@@ -1016,8 +1039,8 @@ static void orinoco_rx(struct net_device *dev,
static void orinoco_rx_isr_tasklet(unsigned long data)
{
- struct net_device *dev = (struct net_device *) data;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = (struct orinoco_private *) data;
+ struct net_device *dev = priv->ndev;
struct orinoco_rx_data *rx_data, *temp;
struct hermes_rx_descriptor *desc;
struct sk_buff *skb;
@@ -1260,9 +1283,81 @@ static void orinoco_send_wevents(struct work_struct *work)
orinoco_unlock(priv, &flags);
}
+static void qbuf_scan(struct orinoco_private *priv, void *buf,
+ int len, int type)
+{
+ struct orinoco_scan_data *sd;
+ unsigned long flags;
+
+ sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
+ sd->buf = buf;
+ sd->len = len;
+ sd->type = type;
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ list_add_tail(&sd->list, &priv->scan_list);
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+ schedule_work(&priv->process_scan);
+}
+
+static void qabort_scan(struct orinoco_private *priv)
+{
+ struct orinoco_scan_data *sd;
+ unsigned long flags;
+
+ sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
+ sd->len = -1; /* Abort */
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ list_add_tail(&sd->list, &priv->scan_list);
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+ schedule_work(&priv->process_scan);
+}
+
+static void orinoco_process_scan_results(struct work_struct *work)
+{
+ struct orinoco_private *priv =
+ container_of(work, struct orinoco_private, process_scan);
+ struct orinoco_scan_data *sd, *temp;
+ unsigned long flags;
+ void *buf;
+ int len;
+ int type;
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ list_for_each_entry_safe(sd, temp, &priv->scan_list, list) {
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+ buf = sd->buf;
+ len = sd->len;
+ type = sd->type;
+
+ list_del(&sd->list);
+ kfree(sd);
+
+ if (len > 0) {
+ if (type == HERMES_INQ_CHANNELINFO)
+ orinoco_add_extscan_result(priv, buf, len);
+ else
+ orinoco_add_hostscan_results(priv, buf, len);
+
+ kfree(buf);
+ } else if (priv->scan_request) {
+ /* Either abort or complete the scan */
+ cfg80211_scan_done(priv->scan_request, (len < 0));
+ priv->scan_request = NULL;
+ }
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ }
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+}
+
static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
u16 infofid;
struct {
__le16 len;
@@ -1327,7 +1422,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
u16 newstatus;
int connected;
- if (priv->iw_mode == IW_MODE_MONITOR)
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
break;
if (len != sizeof(linkstatus)) {
@@ -1346,7 +1441,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
* the hostscan frame can be requested. */
if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
- priv->has_hostscan && priv->scan_inprogress) {
+ priv->has_hostscan && priv->scan_request) {
hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
break;
}
@@ -1372,7 +1467,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
}
break;
case HERMES_INQ_SCAN:
- if (!priv->scan_inprogress && priv->bssid_fixed &&
+ if (!priv->scan_request && priv->bssid_fixed &&
priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
schedule_work(&priv->join_work);
break;
@@ -1382,30 +1477,30 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
case HERMES_INQ_HOSTSCAN_SYMBOL: {
/* Result of a scanning. Contains information about
* cells in the vicinity - Jean II */
- union iwreq_data wrqu;
unsigned char *buf;
- /* Scan is no longer in progress */
- priv->scan_inprogress = 0;
-
/* Sanity check */
if (len > 4096) {
printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
dev->name, len);
+ qabort_scan(priv);
break;
}
/* Allocate buffer for results */
buf = kmalloc(len, GFP_ATOMIC);
- if (buf == NULL)
+ if (buf == NULL) {
/* No memory, so can't printk()... */
+ qabort_scan(priv);
break;
+ }
/* Read scan data */
err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
infofid, sizeof(info));
if (err) {
kfree(buf);
+ qabort_scan(priv);
break;
}
@@ -1419,24 +1514,14 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
}
#endif /* ORINOCO_DEBUG */
- if (orinoco_process_scan_results(priv, buf, len) == 0) {
- /* Send an empty event to user space.
- * We don't send the received data on the event because
- * it would require us to do complex transcoding, and
- * we want to minimise the work done in the irq handler
- * Use a request to extract the data - Jean II */
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
- }
- kfree(buf);
+ qbuf_scan(priv, buf, len, type);
}
break;
case HERMES_INQ_CHANNELINFO:
{
struct agere_ext_scan_info *bss;
- if (!priv->scan_inprogress) {
+ if (!priv->scan_request) {
printk(KERN_DEBUG "%s: Got chaninfo without scan, "
"len=%d\n", dev->name, len);
break;
@@ -1444,25 +1529,12 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
/* An empty result indicates that the scan is complete */
if (len == 0) {
- union iwreq_data wrqu;
-
- /* Scan is no longer in progress */
- priv->scan_inprogress = 0;
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+ qbuf_scan(priv, NULL, len, type);
break;
}
/* Sanity check */
- else if (len > sizeof(*bss)) {
- printk(KERN_WARNING
- "%s: Ext scan results too large (%d bytes). "
- "Truncating results to %zd bytes.\n",
- dev->name, len, sizeof(*bss));
- len = sizeof(*bss);
- } else if (len < (offsetof(struct agere_ext_scan_info,
+ else if (len < (offsetof(struct agere_ext_scan_info,
data) + 2)) {
/* Drop this result now so we don't have to
* keep checking later */
@@ -1472,21 +1544,18 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
break;
}
- bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+ bss = kmalloc(len, GFP_ATOMIC);
if (bss == NULL)
break;
/* Read scan data */
err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
infofid, sizeof(info));
- if (err) {
+ if (err)
kfree(bss);
- break;
- }
-
- orinoco_add_ext_scan_result(priv, bss);
+ else
+ qbuf_scan(priv, bss, len, type);
- kfree(bss);
break;
}
case HERMES_INQ_SEC_STAT_AGERE:
@@ -1501,6 +1570,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
/* We don't actually do anything about it */
break;
}
+
+ return;
}
static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
@@ -1513,15 +1584,15 @@ static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
/* Internal hardware control routines */
/********************************************************************/
-int __orinoco_up(struct net_device *dev)
+static int __orinoco_up(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct net_device *dev = priv->ndev;
struct hermes *hw = &priv->hw;
int err;
netif_carrier_off(dev); /* just to make sure */
- err = __orinoco_program_rids(dev);
+ err = __orinoco_commit(priv);
if (err) {
printk(KERN_ERR "%s: Error %d configuring card\n",
dev->name, err);
@@ -1541,11 +1612,10 @@ int __orinoco_up(struct net_device *dev)
return 0;
}
-EXPORT_SYMBOL(__orinoco_up);
-int __orinoco_down(struct net_device *dev)
+static int __orinoco_down(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct net_device *dev = priv->ndev;
struct hermes *hw = &priv->hw;
int err;
@@ -1573,31 +1643,9 @@ int __orinoco_down(struct net_device *dev)
return 0;
}
-EXPORT_SYMBOL(__orinoco_down);
-
-static int orinoco_allocate_fid(struct net_device *dev)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- struct hermes *hw = &priv->hw;
- int err;
-
- err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
- if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
- /* Try workaround for old Symbol firmware bug */
- priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
- err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-
- printk(KERN_WARNING "%s: firmware ALLOC bug detected "
- "(old Symbol firmware?). Work around %s\n",
- dev->name, err ? "failed!" : "ok.");
- }
-
- return err;
-}
-int orinoco_reinit_firmware(struct net_device *dev)
+static int orinoco_reinit_firmware(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
struct hermes *hw = &priv->hw;
int err;
@@ -1608,246 +1656,15 @@ int orinoco_reinit_firmware(struct net_device *dev)
priv->do_fw_download = 0;
}
if (!err)
- err = orinoco_allocate_fid(dev);
+ err = orinoco_hw_allocate_fid(priv);
return err;
}
-EXPORT_SYMBOL(orinoco_reinit_firmware);
-
-int __orinoco_program_rids(struct net_device *dev)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- hermes_t *hw = &priv->hw;
- int err;
- struct hermes_idstring idbuf;
-
- /* Set the MAC address */
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
- HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting MAC address\n",
- dev->name, err);
- return err;
- }
-
- /* Set up the link mode */
- err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
- priv->port_type);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting port type\n",
- dev->name, err);
- return err;
- }
- /* Set the channel/frequency */
- if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFOWNCHANNEL,
- priv->channel);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting channel %d\n",
- dev->name, err, priv->channel);
- return err;
- }
- }
-
- if (priv->has_ibss) {
- u16 createibss;
-
- if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
- printk(KERN_WARNING "%s: This firmware requires an "
- "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
- /* With wvlan_cs, in this case, we would crash.
- * hopefully, this driver will behave better...
- * Jean II */
- createibss = 0;
- } else {
- createibss = priv->createibss;
- }
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFCREATEIBSS,
- createibss);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
- dev->name, err);
- return err;
- }
- }
- /* Set the desired BSSID */
- err = __orinoco_hw_set_wap(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting AP address\n",
- dev->name, err);
- return err;
- }
- /* Set the desired ESSID */
- idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
- memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
- /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
- HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
- HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
- dev->name, err);
- return err;
- }
-
- /* Set the station name */
- idbuf.len = cpu_to_le16(strlen(priv->nick));
- memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
- HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting nickname\n",
- dev->name, err);
- return err;
- }
-
- /* Set AP density */
- if (priv->has_sensitivity) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSYSTEMSCALE,
- priv->ap_density);
- if (err) {
- printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
- "Disabling sensitivity control\n",
- dev->name, err);
-
- priv->has_sensitivity = 0;
- }
- }
-
- /* Set RTS threshold */
- err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
- priv->rts_thresh);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
- dev->name, err);
- return err;
- }
-
- /* Set fragmentation threshold or MWO robustness */
- if (priv->has_mwo)
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMWOROBUST_AGERE,
- priv->mwo_robust);
- else
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
- priv->frag_thresh);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting fragmentation\n",
- dev->name, err);
- return err;
- }
-
- /* Set bitrate */
- err = __orinoco_hw_set_bitrate(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting bitrate\n",
- dev->name, err);
- return err;
- }
-
- /* Set power management */
- if (priv->has_pm) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMENABLED,
- priv->pm_on);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMULTICASTRECEIVE,
- priv->pm_mcast);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION,
- priv->pm_period);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION,
- priv->pm_timeout);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set preamble - only for Symbol so far... */
- if (priv->has_preamble) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPREAMBLE_SYMBOL,
- priv->preamble);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting preamble\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set up encryption */
- if (priv->has_wep || priv->has_wpa) {
- err = __orinoco_hw_setup_enc(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d activating encryption\n",
- dev->name, err);
- return err;
- }
- }
-
- if (priv->iw_mode == IW_MODE_MONITOR) {
- /* Enable monitor mode */
- dev->type = ARPHRD_IEEE80211;
- err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_MONITOR, 0, NULL);
- } else {
- /* Disable monitor mode */
- dev->type = ARPHRD_ETHER;
- err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_STOP, 0, NULL);
- }
- if (err)
- return err;
-
- /* Set promiscuity / multicast*/
- priv->promiscuous = 0;
- priv->mc_count = 0;
-
- /* FIXME: what about netif_tx_lock */
- __orinoco_set_multicast_list(dev);
-
- return 0;
-}
-
-/* FIXME: return int? */
-static void
+static int
__orinoco_set_multicast_list(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = 0;
int promisc, mc_count;
@@ -1864,6 +1681,8 @@ __orinoco_set_multicast_list(struct net_device *dev)
err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count,
promisc);
+
+ return err;
}
/* This must be called from user context, without locks held - use
@@ -1896,9 +1715,11 @@ void orinoco_reset(struct work_struct *work)
orinoco_unlock(priv, &flags);
- /* Scanning support: Cleanup of driver struct */
- orinoco_clear_scan_results(priv, 0);
- priv->scan_inprogress = 0;
+ /* Scanning support: Notify scan cancellation */
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, 1);
+ priv->scan_request = NULL;
+ }
if (priv->hard_reset) {
err = (*priv->hard_reset)(priv);
@@ -1909,7 +1730,7 @@ void orinoco_reset(struct work_struct *work)
}
}
- err = orinoco_reinit_firmware(dev);
+ err = orinoco_reinit_firmware(priv);
if (err) {
printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
dev->name, err);
@@ -1924,7 +1745,7 @@ void orinoco_reset(struct work_struct *work)
/* priv->open or priv->hw_unavailable might have changed while
* we dropped the lock */
if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(dev);
+ err = __orinoco_up(priv);
if (err) {
printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
dev->name, err);
@@ -1941,6 +1762,64 @@ void orinoco_reset(struct work_struct *work)
printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
}
+static int __orinoco_commit(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ int err = 0;
+
+ err = orinoco_hw_program_rids(priv);
+
+ /* FIXME: what about netif_tx_lock */
+ (void) __orinoco_set_multicast_list(dev);
+
+ return err;
+}
+
+/* Ensures configuration changes are applied. May result in a reset.
+ * The caller should hold priv->lock
+ */
+int orinoco_commit(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ hermes_t *hw = &priv->hw;
+ int err;
+
+ if (priv->broken_disableport) {
+ schedule_work(&priv->reset_work);
+ return 0;
+ }
+
+ err = hermes_disable_port(hw, 0);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to disable port "
+ "while reconfiguring card\n", dev->name);
+ priv->broken_disableport = 1;
+ goto out;
+ }
+
+ err = __orinoco_commit(priv);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to reconfigure card\n",
+ dev->name);
+ goto out;
+ }
+
+ err = hermes_enable_port(hw, 0);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
+ dev->name);
+ goto out;
+ }
+
+ out:
+ if (err) {
+ printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
+ schedule_work(&priv->reset_work);
+ err = 0;
+ }
+ return err;
+}
+
/********************************************************************/
/* Interrupt handler */
/********************************************************************/
@@ -1960,8 +1839,8 @@ static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
irqreturn_t orinoco_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = dev_id;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_id;
+ struct net_device *dev = priv->ndev;
hermes_t *hw = &priv->hw;
int count = MAX_IRQLOOPS_PER_IRQ;
u16 evstat, events;
@@ -2096,227 +1975,12 @@ static void orinoco_unregister_pm_notifier(struct orinoco_private *priv)
/* Initialization */
/********************************************************************/
-struct comp_id {
- u16 id, variant, major, minor;
-} __attribute__ ((packed));
-
-static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
-{
- if (nic_id->id < 0x8000)
- return FIRMWARE_TYPE_AGERE;
- else if (nic_id->id == 0x8000 && nic_id->major == 0)
- return FIRMWARE_TYPE_SYMBOL;
- else
- return FIRMWARE_TYPE_INTERSIL;
-}
-
-/* Set priv->firmware type, determine firmware properties */
-static int determine_firmware(struct net_device *dev)
+int orinoco_init(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
- hermes_t *hw = &priv->hw;
- int err;
- struct comp_id nic_id, sta_id;
- unsigned int firmver;
- char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
-
- /* Get the hardware version */
- err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
- if (err) {
- printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n",
- dev->name, err);
- return err;
- }
-
- le16_to_cpus(&nic_id.id);
- le16_to_cpus(&nic_id.variant);
- le16_to_cpus(&nic_id.major);
- le16_to_cpus(&nic_id.minor);
- printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n",
- dev->name, nic_id.id, nic_id.variant,
- nic_id.major, nic_id.minor);
-
- priv->firmware_type = determine_firmware_type(&nic_id);
-
- /* Get the firmware version */
- err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
- if (err) {
- printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
- dev->name, err);
- return err;
- }
-
- le16_to_cpus(&sta_id.id);
- le16_to_cpus(&sta_id.variant);
- le16_to_cpus(&sta_id.major);
- le16_to_cpus(&sta_id.minor);
- printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n",
- dev->name, sta_id.id, sta_id.variant,
- sta_id.major, sta_id.minor);
-
- switch (sta_id.id) {
- case 0x15:
- printk(KERN_ERR "%s: Primary firmware is active\n",
- dev->name);
- return -ENODEV;
- case 0x14b:
- printk(KERN_ERR "%s: Tertiary firmware is active\n",
- dev->name);
- return -ENODEV;
- case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */
- case 0x21: /* Symbol Spectrum24 Trilogy */
- break;
- default:
- printk(KERN_NOTICE "%s: Unknown station ID, please report\n",
- dev->name);
- break;
- }
-
- /* Default capabilities */
- priv->has_sensitivity = 1;
- priv->has_mwo = 0;
- priv->has_preamble = 0;
- priv->has_port3 = 1;
- priv->has_ibss = 1;
- priv->has_wep = 0;
- priv->has_big_wep = 0;
- priv->has_alt_txcntl = 0;
- priv->has_ext_scan = 0;
- priv->has_wpa = 0;
- priv->do_fw_download = 0;
-
- /* Determine capabilities from the firmware version */
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
- ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
-
- firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
-
- priv->has_ibss = (firmver >= 0x60006);
- priv->has_wep = (firmver >= 0x40020);
- priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
- Gold cards from the others? */
- priv->has_mwo = (firmver >= 0x60000);
- priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
- priv->ibss_port = 1;
- priv->has_hostscan = (firmver >= 0x8000a);
- priv->do_fw_download = 1;
- priv->broken_monitor = (firmver >= 0x80000);
- priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
- priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
- priv->has_wpa = (firmver >= 0x9002a);
- /* Tested with Agere firmware :
- * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
- * Tested CableTron firmware : 4.32 => Anton */
- break;
- case FIRMWARE_TYPE_SYMBOL:
- /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
- /* Intel MAC : 00:02:B3:* */
- /* 3Com MAC : 00:50:DA:* */
- memset(tmp, 0, sizeof(tmp));
- /* Get the Symbol firmware version */
- err = hermes_read_ltv(hw, USER_BAP,
- HERMES_RID_SECONDARYVERSION_SYMBOL,
- SYMBOL_MAX_VER_LEN, NULL, &tmp);
- if (err) {
- printk(KERN_WARNING
- "%s: Error %d reading Symbol firmware info. "
- "Wildly guessing capabilities...\n",
- dev->name, err);
- firmver = 0;
- tmp[0] = '\0';
- } else {
- /* The firmware revision is a string, the format is
- * something like : "V2.20-01".
- * Quick and dirty parsing... - Jean II
- */
- firmver = ((tmp[1] - '0') << 16)
- | ((tmp[3] - '0') << 12)
- | ((tmp[4] - '0') << 8)
- | ((tmp[6] - '0') << 4)
- | (tmp[7] - '0');
-
- tmp[SYMBOL_MAX_VER_LEN] = '\0';
- }
-
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Symbol %s", tmp);
-
- priv->has_ibss = (firmver >= 0x20000);
- priv->has_wep = (firmver >= 0x15012);
- priv->has_big_wep = (firmver >= 0x20000);
- priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
- (firmver >= 0x29000 && firmver < 0x30000) ||
- firmver >= 0x31000;
- priv->has_preamble = (firmver >= 0x20000);
- priv->ibss_port = 4;
-
- /* Symbol firmware is found on various cards, but
- * there has been no attempt to check firmware
- * download on non-spectrum_cs based cards.
- *
- * Given that the Agere firmware download works
- * differently, we should avoid doing a firmware
- * download with the Symbol algorithm on non-spectrum
- * cards.
- *
- * For now we can identify a spectrum_cs based card
- * because it has a firmware reset function.
- */
- priv->do_fw_download = (priv->stop_fw != NULL);
-
- priv->broken_disableport = (firmver == 0x25013) ||
- (firmver >= 0x30000 && firmver <= 0x31000);
- priv->has_hostscan = (firmver >= 0x31001) ||
- (firmver >= 0x29057 && firmver < 0x30000);
- /* Tested with Intel firmware : 0x20015 => Jean II */
- /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
- break;
- case FIRMWARE_TYPE_INTERSIL:
- /* D-Link, Linksys, Adtron, ZoomAir, and many others...
- * Samsung, Compaq 100/200 and Proxim are slightly
- * different and less well tested */
- /* D-Link MAC : 00:40:05:* */
- /* Addtron MAC : 00:90:D1:* */
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
- sta_id.variant);
-
- firmver = ((unsigned long)sta_id.major << 16) |
- ((unsigned long)sta_id.minor << 8) | sta_id.variant;
-
- priv->has_ibss = (firmver >= 0x000700); /* FIXME */
- priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
- priv->has_pm = (firmver >= 0x000700);
- priv->has_hostscan = (firmver >= 0x010301);
-
- if (firmver >= 0x000800)
- priv->ibss_port = 0;
- else {
- printk(KERN_NOTICE "%s: Intersil firmware earlier "
- "than v0.8.x - several features not supported\n",
- dev->name);
- priv->ibss_port = 1;
- }
- break;
- }
- printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name,
- priv->fw_name);
-
- return 0;
-}
-
-static int orinoco_init(struct net_device *dev)
-{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct device *dev = priv->dev;
+ struct wiphy *wiphy = priv_to_wiphy(priv);
hermes_t *hw = &priv->hw;
int err = 0;
- struct hermes_idstring nickbuf;
- u16 reclen;
- int len;
/* No need to lock, the hw_unavailable flag is already set in
* alloc_orinocodev() */
@@ -2325,15 +1989,14 @@ static int orinoco_init(struct net_device *dev)
/* Initialize the firmware */
err = hermes_init(hw);
if (err != 0) {
- printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
- dev->name, err);
+ dev_err(dev, "Failed to initialize firmware (err = %d)\n",
+ err);
goto out;
}
- err = determine_firmware(dev);
+ err = determine_fw_capabilities(priv);
if (err != 0) {
- printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
- dev->name);
+ dev_err(dev, "Incompatible firmware, aborting\n");
goto out;
}
@@ -2347,154 +2010,48 @@ static int orinoco_init(struct net_device *dev)
priv->do_fw_download = 0;
/* Check firmware version again */
- err = determine_firmware(dev);
+ err = determine_fw_capabilities(priv);
if (err != 0) {
- printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
- dev->name);
+ dev_err(dev, "Incompatible firmware, aborting\n");
goto out;
}
}
if (priv->has_port3)
- printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n",
- dev->name);
+ dev_info(dev, "Ad-hoc demo mode supported\n");
if (priv->has_ibss)
- printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n",
- dev->name);
- if (priv->has_wep) {
- printk(KERN_DEBUG "%s: WEP supported, %s-bit key\n", dev->name,
- priv->has_big_wep ? "104" : "40");
- }
+ dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n");
+ if (priv->has_wep)
+ dev_info(dev, "WEP supported, %s-bit key\n",
+ priv->has_big_wep ? "104" : "40");
if (priv->has_wpa) {
- printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name);
+ dev_info(dev, "WPA-PSK supported\n");
if (orinoco_mic_init(priv)) {
- printk(KERN_ERR "%s: Failed to setup MIC crypto "
- "algorithm. Disabling WPA support\n", dev->name);
+ dev_err(dev, "Failed to setup MIC crypto algorithm. "
+ "Disabling WPA support\n");
priv->has_wpa = 0;
}
}
- /* Now we have the firmware capabilities, allocate appropiate
- * sized scan buffers */
- if (orinoco_bss_data_allocate(priv))
- goto out;
- orinoco_bss_data_init(priv);
-
- /* Get the MAC address */
- err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
- ETH_ALEN, NULL, dev->dev_addr);
- if (err) {
- printk(KERN_WARNING "%s: failed to read MAC address!\n",
- dev->name);
- goto out;
- }
-
- printk(KERN_DEBUG "%s: MAC address %pM\n",
- dev->name, dev->dev_addr);
-
- /* Get the station name */
- err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
- sizeof(nickbuf), &reclen, &nickbuf);
- if (err) {
- printk(KERN_ERR "%s: failed to read station name\n",
- dev->name);
- goto out;
- }
- if (nickbuf.len)
- len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
- else
- len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
- memcpy(priv->nick, &nickbuf.val, len);
- priv->nick[len] = '\0';
-
- printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
-
- err = orinoco_allocate_fid(dev);
- if (err) {
- printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
- dev->name);
- goto out;
- }
-
- /* Get allowed channels */
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
- &priv->channel_mask);
- if (err) {
- printk(KERN_ERR "%s: failed to read channel list!\n",
- dev->name);
- goto out;
- }
-
- /* Get initial AP density */
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
- &priv->ap_density);
- if (err || priv->ap_density < 1 || priv->ap_density > 3)
- priv->has_sensitivity = 0;
-
- /* Get initial RTS threshold */
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
- &priv->rts_thresh);
- if (err) {
- printk(KERN_ERR "%s: failed to read RTS threshold!\n",
- dev->name);
+ err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr);
+ if (err)
goto out;
- }
- /* Get initial fragmentation settings */
- if (priv->has_mwo)
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMWOROBUST_AGERE,
- &priv->mwo_robust);
- else
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
- &priv->frag_thresh);
+ err = orinoco_hw_allocate_fid(priv);
if (err) {
- printk(KERN_ERR "%s: failed to read fragmentation settings!\n",
- dev->name);
+ dev_err(dev, "Failed to allocate NIC buffer!\n");
goto out;
}
- /* Power management setup */
- if (priv->has_pm) {
- priv->pm_on = 0;
- priv->pm_mcast = 1;
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION,
- &priv->pm_period);
- if (err) {
- printk(KERN_ERR "%s: failed to read power management period!\n",
- dev->name);
- goto out;
- }
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION,
- &priv->pm_timeout);
- if (err) {
- printk(KERN_ERR "%s: failed to read power management timeout!\n",
- dev->name);
- goto out;
- }
- }
-
- /* Preamble setup */
- if (priv->has_preamble) {
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPREAMBLE_SYMBOL,
- &priv->preamble);
- if (err)
- goto out;
- }
-
/* Set up the default configuration */
- priv->iw_mode = IW_MODE_INFRA;
+ priv->iw_mode = NL80211_IFTYPE_STATION;
/* By default use IEEE/IBSS ad-hoc mode if we have it */
priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss);
set_port_type(priv);
priv->channel = 0; /* use firmware default */
priv->promiscuous = 0;
- priv->encode_alg = IW_ENCODE_ALG_NONE;
+ priv->encode_alg = ORINOCO_ALG_NONE;
priv->tx_key = 0;
priv->wpa_enabled = 0;
priv->tkip_cm_active = 0;
@@ -2502,20 +2059,25 @@ static int orinoco_init(struct net_device *dev)
priv->wpa_ie_len = 0;
priv->wpa_ie = NULL;
+ if (orinoco_wiphy_register(wiphy)) {
+ err = -ENODEV;
+ goto out;
+ }
+
/* Make the hardware available, as long as it hasn't been
* removed elsewhere (e.g. by PCMCIA hot unplug) */
spin_lock_irq(&priv->lock);
priv->hw_unavailable--;
spin_unlock_irq(&priv->lock);
- printk(KERN_DEBUG "%s: ready\n", dev->name);
+ dev_dbg(dev, "Ready\n");
out:
return err;
}
+EXPORT_SYMBOL(orinoco_init);
static const struct net_device_ops orinoco_netdev_ops = {
- .ndo_init = orinoco_init,
.ndo_open = orinoco_open,
.ndo_stop = orinoco_stop,
.ndo_start_xmit = orinoco_xmit,
@@ -2527,40 +2089,64 @@ static const struct net_device_ops orinoco_netdev_ops = {
.ndo_get_stats = orinoco_get_stats,
};
-struct net_device
+/* Allocate private data.
+ *
+ * This driver has a number of structures associated with it
+ * netdev - Net device structure for each network interface
+ * wiphy - structure associated with wireless phy
+ * wireless_dev (wdev) - structure for each wireless interface
+ * hw - structure for hermes chip info
+ * card - card specific structure for use by the card driver
+ * (airport, orinoco_cs)
+ * priv - orinoco private data
+ * device - generic linux device structure
+ *
+ * +---------+ +---------+
+ * | wiphy | | netdev |
+ * | +-------+ | +-------+
+ * | | priv | | | wdev |
+ * | | +-----+ +-+-------+
+ * | | | hw |
+ * | +-+-----+
+ * | | card |
+ * +-+-------+
+ *
+ * priv has a link to netdev and device
+ * wdev has a link to wiphy
+ */
+struct orinoco_private
*alloc_orinocodev(int sizeof_card,
struct device *device,
int (*hard_reset)(struct orinoco_private *),
int (*stop_fw)(struct orinoco_private *, int))
{
- struct net_device *dev;
struct orinoco_private *priv;
+ struct wiphy *wiphy;
- dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
- if (!dev)
+ /* allocate wiphy
+ * NOTE: We only support a single virtual interface
+ * but this may change when monitor mode is added
+ */
+ wiphy = wiphy_new(&orinoco_cfg_ops,
+ sizeof(struct orinoco_private) + sizeof_card);
+ if (!wiphy)
return NULL;
- priv = netdev_priv(dev);
- priv->ndev = dev;
+
+ priv = wiphy_priv(wiphy);
+ priv->dev = device;
+
if (sizeof_card)
priv->card = (void *)((unsigned long)priv
+ sizeof(struct orinoco_private));
else
priv->card = NULL;
- priv->dev = device;
- /* Setup / override net_device fields */
- dev->netdev_ops = &orinoco_netdev_ops;
- dev->watchdog_timeo = HZ; /* 1 second timeout */
- dev->ethtool_ops = &orinoco_ethtool_ops;
- dev->wireless_handlers = &orinoco_handler_def;
+ orinoco_wiphy_init(wiphy);
+
#ifdef WIRELESS_SPY
priv->wireless_data.spy_data = &priv->spy_data;
- dev->wireless_data = &priv->wireless_data;
#endif
- /* Reserve space in skb for the SNAP header */
- dev->hard_header_len += ENCAPS_OVERHEAD;
-
/* Set up default callbacks */
priv->hard_reset = hard_reset;
priv->stop_fw = stop_fw;
@@ -2576,9 +2162,12 @@ struct net_device
INIT_LIST_HEAD(&priv->rx_list);
tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet,
- (unsigned long) dev);
+ (unsigned long) priv);
+
+ spin_lock_init(&priv->scan_lock);
+ INIT_LIST_HEAD(&priv->scan_list);
+ INIT_WORK(&priv->process_scan, orinoco_process_scan_results);
- netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
@@ -2589,14 +2178,91 @@ struct net_device
/* Register PM notifiers */
orinoco_register_pm_notifier(priv);
- return dev;
+ return priv;
}
EXPORT_SYMBOL(alloc_orinocodev);
-void free_orinocodev(struct net_device *dev)
+/* We can only support a single interface. We provide a separate
+ * function to set it up to distinguish between hardware
+ * initialisation and interface setup.
+ *
+ * The base_addr and irq parameters are passed on to netdev for use
+ * with SIOCGIFMAP.
+ */
+int orinoco_if_add(struct orinoco_private *priv,
+ unsigned long base_addr,
+ unsigned int irq)
+{
+ struct wiphy *wiphy = priv_to_wiphy(priv);
+ struct wireless_dev *wdev;
+ struct net_device *dev;
+ int ret;
+
+ dev = alloc_etherdev(sizeof(struct wireless_dev));
+
+ if (!dev)
+ return -ENOMEM;
+
+ /* Initialise wireless_dev */
+ wdev = netdev_priv(dev);
+ wdev->wiphy = wiphy;
+ wdev->iftype = NL80211_IFTYPE_STATION;
+
+ /* Setup / override net_device fields */
+ dev->ieee80211_ptr = wdev;
+ dev->netdev_ops = &orinoco_netdev_ops;
+ dev->watchdog_timeo = HZ; /* 1 second timeout */
+ dev->ethtool_ops = &orinoco_ethtool_ops;
+ dev->wireless_handlers = &orinoco_handler_def;
+#ifdef WIRELESS_SPY
+ dev->wireless_data = &priv->wireless_data;
+#endif
+ /* we use the default eth_mac_addr for setting the MAC addr */
+
+ /* Reserve space in skb for the SNAP header */
+ dev->hard_header_len += ENCAPS_OVERHEAD;
+
+ netif_carrier_off(dev);
+
+ memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
+
+ dev->base_addr = base_addr;
+ dev->irq = irq;
+
+ SET_NETDEV_DEV(dev, priv->dev);
+ ret = register_netdev(dev);
+ if (ret)
+ goto fail;
+
+ priv->ndev = dev;
+
+ /* Report what we've done */
+ dev_dbg(priv->dev, "Registerred interface %s.\n", dev->name);
+
+ return 0;
+
+ fail:
+ free_netdev(dev);
+ return ret;
+}
+EXPORT_SYMBOL(orinoco_if_add);
+
+void orinoco_if_del(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+
+ unregister_netdev(dev);
+ free_netdev(dev);
+}
+EXPORT_SYMBOL(orinoco_if_del);
+
+void free_orinocodev(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct wiphy *wiphy = priv_to_wiphy(priv);
struct orinoco_rx_data *rx_data, *temp;
+ struct orinoco_scan_data *sd, *sdtemp;
+
+ wiphy_unregister(wiphy);
/* If the tasklet is scheduled when we call tasklet_kill it
* will run one final time. However the tasklet will only
@@ -2612,21 +2278,80 @@ void free_orinocodev(struct net_device *dev)
kfree(rx_data);
}
+ cancel_work_sync(&priv->process_scan);
+ /* Explicitly drain priv->scan_list */
+ list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) {
+ list_del(&sd->list);
+
+ if ((sd->len > 0) && sd->buf)
+ kfree(sd->buf);
+ kfree(sd);
+ }
+
orinoco_unregister_pm_notifier(priv);
orinoco_uncache_fw(priv);
priv->wpa_ie_len = 0;
kfree(priv->wpa_ie);
orinoco_mic_free(priv);
- orinoco_bss_data_free(priv);
- free_netdev(dev);
+ wiphy_free(wiphy);
}
EXPORT_SYMBOL(free_orinocodev);
+int orinoco_up(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ err = orinoco_reinit_firmware(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
+ dev->name, err);
+ goto exit;
+ }
+
+ netif_device_attach(dev);
+ priv->hw_unavailable--;
+
+ if (priv->open && !priv->hw_unavailable) {
+ err = __orinoco_up(priv);
+ if (err)
+ printk(KERN_ERR "%s: Error %d restarting card\n",
+ dev->name, err);
+ }
+
+exit:
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(orinoco_up);
+
+void orinoco_down(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ err = __orinoco_down(priv);
+ if (err)
+ printk(KERN_WARNING "%s: Error %d downing interface\n",
+ dev->name, err);
+
+ netif_device_detach(dev);
+ priv->hw_unavailable++;
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(orinoco_down);
+
static void orinoco_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
diff --git a/drivers/net/wireless/orinoco/main.h b/drivers/net/wireless/orinoco/main.h
index af2bae4fe395..21ab36cd76c7 100644
--- a/drivers/net/wireless/orinoco/main.h
+++ b/drivers/net/wireless/orinoco/main.h
@@ -29,10 +29,9 @@ struct net_device;
struct work_struct;
void set_port_type(struct orinoco_private *priv);
-int __orinoco_program_rids(struct net_device *dev);
+int orinoco_commit(struct orinoco_private *priv);
void orinoco_reset(struct work_struct *work);
-
/* Information element helpers - find a home for these... */
static inline u8 *orinoco_get_ie(u8 *data, size_t len,
enum ieee80211_eid eid)
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index 8e5a72cc297f..9ac6f1dda4b0 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -14,6 +14,7 @@
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "hermes.h"
@@ -24,6 +25,7 @@
#define MAX_SCAN_LEN 4096
+#define ORINOCO_SEQ_LEN 8
#define ORINOCO_MAX_KEY_SIZE 14
#define ORINOCO_MAX_KEYS 4
@@ -41,24 +43,18 @@ struct orinoco_tkip_key {
u8 rx_mic[MIC_KEYLEN];
};
+enum orinoco_alg {
+ ORINOCO_ALG_NONE,
+ ORINOCO_ALG_WEP,
+ ORINOCO_ALG_TKIP
+};
+
typedef enum {
FIRMWARE_TYPE_AGERE,
FIRMWARE_TYPE_INTERSIL,
FIRMWARE_TYPE_SYMBOL
} fwtype_t;
-struct bss_element {
- union hermes_scan_info bss;
- unsigned long last_scanned;
- struct list_head list;
-};
-
-struct xbss_element {
- struct agere_ext_scan_info bss;
- unsigned long last_scanned;
- struct list_head list;
-};
-
struct firmware;
struct orinoco_private {
@@ -67,6 +63,10 @@ struct orinoco_private {
int (*hard_reset)(struct orinoco_private *);
int (*stop_fw)(struct orinoco_private *, int);
+ struct ieee80211_supported_band band;
+ struct ieee80211_channel channels[14];
+ u32 cipher_suites[3];
+
/* Synchronisation stuff */
spinlock_t lock;
int hw_unavailable;
@@ -114,12 +114,14 @@ struct orinoco_private {
unsigned int do_fw_download:1;
unsigned int broken_disableport:1;
unsigned int broken_monitor:1;
+ unsigned int prefer_port3:1;
/* Configuration paramaters */
- u32 iw_mode;
- int prefer_port3;
- u16 encode_alg, wep_restrict, tx_key;
- struct orinoco_key keys[ORINOCO_MAX_KEYS];
+ enum nl80211_iftype iw_mode;
+ enum orinoco_alg encode_alg;
+ u16 wep_restrict, tx_key;
+ struct key_params keys[ORINOCO_MAX_KEYS];
+
int bitratemode;
char nick[IW_ESSID_MAX_SIZE+1];
char desired_essid[IW_ESSID_MAX_SIZE+1];
@@ -140,18 +142,15 @@ struct orinoco_private {
int promiscuous, mc_count;
/* Scanning support */
- struct list_head bss_list;
- struct list_head bss_free_list;
- void *bss_xbss_data;
-
- int scan_inprogress; /* Scan pending... */
- u32 scan_mode; /* Type of scan done */
+ struct cfg80211_scan_request *scan_request;
+ struct work_struct process_scan;
+ struct list_head scan_list;
+ spinlock_t scan_lock; /* protects the scan list */
/* WPA support */
u8 *wpa_ie;
int wpa_ie_len;
- struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS];
struct crypto_hash *rx_tfm_mic;
struct crypto_hash *tx_tfm_mic;
@@ -182,14 +181,18 @@ extern int orinoco_debug;
/* Exported prototypes */
/********************************************************************/
-extern struct net_device *alloc_orinocodev(
+extern struct orinoco_private *alloc_orinocodev(
int sizeof_card, struct device *device,
int (*hard_reset)(struct orinoco_private *),
int (*stop_fw)(struct orinoco_private *, int));
-extern void free_orinocodev(struct net_device *dev);
-extern int __orinoco_up(struct net_device *dev);
-extern int __orinoco_down(struct net_device *dev);
-extern int orinoco_reinit_firmware(struct net_device *dev);
+extern void free_orinocodev(struct orinoco_private *priv);
+extern int orinoco_init(struct orinoco_private *priv);
+extern int orinoco_if_add(struct orinoco_private *priv,
+ unsigned long base_addr,
+ unsigned int irq);
+extern void orinoco_if_del(struct orinoco_private *priv);
+extern int orinoco_up(struct orinoco_private *priv);
+extern void orinoco_down(struct orinoco_private *priv);
extern irqreturn_t orinoco_interrupt(int irq, void *dev_id);
/********************************************************************/
@@ -215,4 +218,10 @@ static inline void orinoco_unlock(struct orinoco_private *priv,
spin_unlock_irqrestore(&priv->lock, *flags);
}
+/*** Navigate from net_device to orinoco_private ***/
+static inline struct orinoco_private *ndev_priv(struct net_device *dev)
+{
+ struct wireless_dev *wdev = netdev_priv(dev);
+ return wdev_priv(wdev);
+}
#endif /* _ORINOCO_H */
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index b381aed24d73..38c1c9d2abb8 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -106,26 +106,24 @@ orinoco_cs_hard_reset(struct orinoco_private *priv)
static int
orinoco_cs_probe(struct pcmcia_device *link)
{
- struct net_device *dev;
struct orinoco_private *priv;
struct orinoco_pccard *card;
- dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
- orinoco_cs_hard_reset, NULL);
- if (!dev)
+ priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+ orinoco_cs_hard_reset, NULL);
+ if (!priv)
return -ENOMEM;
- priv = netdev_priv(dev);
card = priv->card;
/* Link both structures together */
card->p_dev = link;
- link->priv = dev;
+ link->priv = priv;
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = orinoco_interrupt;
- link->irq.Instance = dev;
+ link->irq.Instance = priv;
/* General socket configuration defaults can go here. In this
* client, we assume very little, and rely on the CIS for
@@ -146,14 +144,14 @@ orinoco_cs_probe(struct pcmcia_device *link)
*/
static void orinoco_cs_detach(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
+ struct orinoco_private *priv = link->priv;
if (link->dev_node)
- unregister_netdev(dev);
+ orinoco_if_del(priv);
orinoco_cs_release(link);
- free_orinocodev(dev);
+ free_orinocodev(priv);
} /* orinoco_cs_detach */
/*
@@ -239,8 +237,7 @@ next_entry:
static int
orinoco_cs_config(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
hermes_t *hw = &priv->hw;
int last_fn, last_ret;
@@ -295,29 +292,27 @@ orinoco_cs_config(struct pcmcia_device *link)
pcmcia_request_configuration(link, &link->conf));
/* Ok, we have the configuration, prepare to register the netdev */
- dev->base_addr = link->io.BasePort1;
- dev->irq = link->irq.AssignedIRQ;
card->node.major = card->node.minor = 0;
- SET_NETDEV_DEV(dev, &handle_to_dev(link));
- /* Tell the stack we exist */
- if (register_netdev(dev) != 0) {
- printk(KERN_ERR PFX "register_netdev() failed\n");
+ /* Initialise the main driver */
+ if (orinoco_init(priv) != 0) {
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
+ goto failed;
+ }
+
+ /* Register an interface with the stack */
+ if (orinoco_if_add(priv, link->io.BasePort1,
+ link->irq.AssignedIRQ) != 0) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
}
/* At this point, the dev_node_t structure(s) needs to be
* initialized and arranged in a linked list at link->dev_node. */
- strcpy(card->node.dev_name, dev->name);
+ strcpy(card->node.dev_name, priv->ndev->name);
link->dev_node = &card->node; /* link->dev_node being non-NULL is also
* used to indicate that the
* net_device has been registered */
-
- /* Finally, report what we've done */
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
- link->irq.AssignedIRQ, link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
return 0;
cs_failed:
@@ -336,8 +331,7 @@ orinoco_cs_config(struct pcmcia_device *link)
static void
orinoco_cs_release(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
unsigned long flags;
/* We're committed to taking the device away now, so mark the
@@ -353,62 +347,26 @@ orinoco_cs_release(struct pcmcia_device *link)
static int orinoco_cs_suspend(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
- int err = 0;
- unsigned long flags;
/* This is probably racy, but I can't think of
a better way, short of rewriting the PCMCIA
layer to not suck :-( */
- if (!test_bit(0, &card->hard_reset_in_progress)) {
- spin_lock_irqsave(&priv->lock, flags);
-
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
- priv->hw_unavailable++;
-
- spin_unlock_irqrestore(&priv->lock, flags);
- }
+ if (!test_bit(0, &card->hard_reset_in_progress))
+ orinoco_down(priv);
return 0;
}
static int orinoco_cs_resume(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
int err = 0;
- unsigned long flags;
-
- if (!test_bit(0, &card->hard_reset_in_progress)) {
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
- dev->name, err);
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
- netif_device_attach(dev);
- priv->hw_unavailable--;
-
- if (priv->open && !priv->hw_unavailable) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card\n",
- dev->name, err);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
- }
+ if (!test_bit(0, &card->hard_reset_in_progress))
+ err = orinoco_up(priv);
return err;
}
diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c
index b01726255c6f..c13a4c383410 100644
--- a/drivers/net/wireless/orinoco/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco/orinoco_nortel.c
@@ -144,7 +144,6 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io, *bridge_io, *attr_io;
err = pci_enable_device(pdev);
@@ -181,24 +180,22 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_nortel_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_nortel_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
card->attr_io = attr_io;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -217,24 +214,28 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -256,17 +257,16 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
struct orinoco_pci_card *card = priv->card;
/* Clear LEDs */
iowrite16(0, card->bridge_io + 10);
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->attr_io);
pci_iounmap(pdev, card->bridge_io);
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c
index 78cafff1fb2e..fea7781948e7 100644
--- a/drivers/net/wireless/orinoco/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco/orinoco_pci.c
@@ -116,7 +116,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io;
err = pci_enable_device(pdev);
@@ -139,22 +138,20 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_pci_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_pci_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -167,24 +164,28 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -200,13 +201,12 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_release_regions(pdev);
pci_disable_device(pdev);
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h
index c655b4a3de16..ea7231af40a8 100644
--- a/drivers/net/wireless/orinoco/orinoco_pci.h
+++ b/drivers/net/wireless/orinoco/orinoco_pci.h
@@ -21,30 +21,10 @@ struct orinoco_pci_card {
#ifdef CONFIG_PM
static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
- int err;
-
- err = orinoco_lock(priv, &flags);
- if (err) {
- printk(KERN_ERR "%s: cannot lock hardware for suspend\n",
- dev->name);
- return err;
- }
-
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: error %d bringing interface down "
- "for suspend\n", dev->name, err);
-
- netif_device_detach(dev);
-
- priv->hw_unavailable++;
-
- orinoco_unlock(priv, &flags);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
- free_irq(pdev->irq, dev);
+ orinoco_down(priv);
+ free_irq(pdev->irq, priv);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
@@ -54,9 +34,8 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
static int orinoco_pci_resume(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
+ struct net_device *dev = priv->ndev;
int err;
pci_set_power_state(pdev, 0);
@@ -69,7 +48,7 @@ static int orinoco_pci_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ dev->name, priv);
if (err) {
printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n",
dev->name);
@@ -77,29 +56,9 @@ static int orinoco_pci_resume(struct pci_dev *pdev)
return -EBUSY;
}
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: error %d re-initializing firmware "
- "on resume\n", dev->name, err);
- return err;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
+ err = orinoco_up(priv);
- priv->hw_unavailable--;
-
- if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card on resume\n",
- dev->name, err);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
+ return err;
}
#else
#define orinoco_pci_suspend NULL
diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c
index a2a4471c0337..3f2942a1e4f5 100644
--- a/drivers/net/wireless/orinoco/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco/orinoco_plx.c
@@ -183,7 +183,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io, *attr_io, *bridge_io;
err = pci_enable_device(pdev);
@@ -220,24 +219,22 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_plx_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_plx_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
card->attr_io = attr_io;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -256,24 +253,28 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -295,14 +296,13 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
struct orinoco_pci_card *card = priv->card;
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->attr_io);
pci_iounmap(pdev, card->bridge_io);
diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c
index cda0e6e4d7a1..d3452548cc71 100644
--- a/drivers/net/wireless/orinoco/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco/orinoco_tmd.c
@@ -94,7 +94,6 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io, *bridge_io;
err = pci_enable_device(pdev);
@@ -124,23 +123,21 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_tmd_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_tmd_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -153,24 +150,28 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -189,14 +190,13 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
struct orinoco_pci_card *card = priv->card;
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->bridge_io);
pci_release_regions(pdev);
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
index 89d699d4dfe6..d2f10e9c2162 100644
--- a/drivers/net/wireless/orinoco/scan.c
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -5,147 +5,166 @@
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
#include "hermes.h"
#include "orinoco.h"
+#include "main.h"
#include "scan.h"
-#define ORINOCO_MAX_BSS_COUNT 64
+#define ZERO_DBM_OFFSET 0x95
+#define MAX_SIGNAL_LEVEL 0x8A
+#define MIN_SIGNAL_LEVEL 0x2F
-#define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data)
-#define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data)
+#define SIGNAL_TO_DBM(x) \
+ (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL) \
+ - ZERO_DBM_OFFSET)
+#define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100)
-int orinoco_bss_data_allocate(struct orinoco_private *priv)
+static int symbol_build_supp_rates(u8 *buf, const __le16 *rates)
{
- if (priv->bss_xbss_data)
- return 0;
-
- if (priv->has_ext_scan)
- priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
- sizeof(struct xbss_element),
- GFP_KERNEL);
- else
- priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
- sizeof(struct bss_element),
- GFP_KERNEL);
-
- if (!priv->bss_xbss_data) {
- printk(KERN_WARNING "Out of memory allocating beacons");
- return -ENOMEM;
+ int i;
+ u8 rate;
+
+ buf[0] = WLAN_EID_SUPP_RATES;
+ for (i = 0; i < 5; i++) {
+ rate = le16_to_cpu(rates[i]);
+ /* NULL terminated */
+ if (rate == 0x0)
+ break;
+ buf[i + 2] = rate;
}
- return 0;
-}
+ buf[1] = i;
-void orinoco_bss_data_free(struct orinoco_private *priv)
-{
- kfree(priv->bss_xbss_data);
- priv->bss_xbss_data = NULL;
+ return i + 2;
}
-void orinoco_bss_data_init(struct orinoco_private *priv)
+static int prism_build_supp_rates(u8 *buf, const u8 *rates)
{
int i;
- INIT_LIST_HEAD(&priv->bss_free_list);
- INIT_LIST_HEAD(&priv->bss_list);
- if (priv->has_ext_scan)
- for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
- list_add_tail(&(PRIV_XBSS[i].list),
- &priv->bss_free_list);
- else
- for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
- list_add_tail(&(PRIV_BSS[i].list),
- &priv->bss_free_list);
-
-}
-
-void orinoco_clear_scan_results(struct orinoco_private *priv,
- unsigned long scan_age)
-{
- if (priv->has_ext_scan) {
- struct xbss_element *bss;
- struct xbss_element *tmp_bss;
-
- /* Blow away current list of scan results */
- list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
- if (!scan_age ||
- time_after(jiffies, bss->last_scanned + scan_age)) {
- list_move_tail(&bss->list,
- &priv->bss_free_list);
- /* Don't blow away ->list, just BSS data */
- memset(&bss->bss, 0, sizeof(bss->bss));
- bss->last_scanned = 0;
- }
- }
- } else {
- struct bss_element *bss;
- struct bss_element *tmp_bss;
-
- /* Blow away current list of scan results */
- list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
- if (!scan_age ||
- time_after(jiffies, bss->last_scanned + scan_age)) {
- list_move_tail(&bss->list,
- &priv->bss_free_list);
- /* Don't blow away ->list, just BSS data */
- memset(&bss->bss, 0, sizeof(bss->bss));
- bss->last_scanned = 0;
- }
+ buf[0] = WLAN_EID_SUPP_RATES;
+ for (i = 0; i < 8; i++) {
+ /* NULL terminated */
+ if (rates[i] == 0x0)
+ break;
+ buf[i + 2] = rates[i];
+ }
+ buf[1] = i;
+
+ /* We might still have another 2 rates, which need to go in
+ * extended supported rates */
+ if (i == 8 && rates[i] > 0) {
+ buf[10] = WLAN_EID_EXT_SUPP_RATES;
+ for (; i < 10; i++) {
+ /* NULL terminated */
+ if (rates[i] == 0x0)
+ break;
+ buf[i + 2] = rates[i];
}
+ buf[11] = i - 8;
}
+
+ return (i < 8) ? i + 2 : i + 4;
}
-void orinoco_add_ext_scan_result(struct orinoco_private *priv,
- struct agere_ext_scan_info *atom)
+static void orinoco_add_hostscan_result(struct orinoco_private *priv,
+ const union hermes_scan_info *bss)
{
- struct xbss_element *bss = NULL;
- int found = 0;
-
- /* Try to update an existing bss first */
- list_for_each_entry(bss, &priv->bss_list, list) {
- if (compare_ether_addr(bss->bss.bssid, atom->bssid))
- continue;
- /* ESSID lengths */
- if (bss->bss.data[1] != atom->data[1])
- continue;
- if (memcmp(&bss->bss.data[2], &atom->data[2],
- atom->data[1]))
- continue;
- found = 1;
+ struct wiphy *wiphy = priv_to_wiphy(priv);
+ struct ieee80211_channel *channel;
+ u8 *ie;
+ u8 ie_buf[46];
+ u64 timestamp;
+ s32 signal;
+ u16 capability;
+ u16 beacon_interval;
+ int ie_len;
+ int freq;
+ int len;
+
+ len = le16_to_cpu(bss->a.essid_len);
+
+ /* Reconstruct SSID and bitrate IEs to pass up */
+ ie_buf[0] = WLAN_EID_SSID;
+ ie_buf[1] = len;
+ memcpy(&ie_buf[2], bss->a.essid, len);
+
+ ie = ie_buf + len + 2;
+ ie_len = ie_buf[1] + 2;
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_SYMBOL:
+ ie_len += symbol_build_supp_rates(ie, bss->s.rates);
break;
- }
- /* Grab a bss off the free list */
- if (!found && !list_empty(&priv->bss_free_list)) {
- bss = list_entry(priv->bss_free_list.next,
- struct xbss_element, list);
- list_del(priv->bss_free_list.next);
+ case FIRMWARE_TYPE_INTERSIL:
+ ie_len += prism_build_supp_rates(ie, bss->p.rates);
+ break;
- list_add_tail(&bss->list, &priv->bss_list);
+ case FIRMWARE_TYPE_AGERE:
+ default:
+ break;
}
- if (bss) {
- /* Always update the BSS to get latest beacon info */
- memcpy(&bss->bss, atom, sizeof(bss->bss));
- bss->last_scanned = jiffies;
- }
+ freq = ieee80211_dsss_chan_to_freq(le16_to_cpu(bss->a.channel));
+ channel = ieee80211_get_channel(wiphy, freq);
+ timestamp = 0;
+ capability = le16_to_cpu(bss->a.capabilities);
+ beacon_interval = le16_to_cpu(bss->a.beacon_interv);
+ signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
+
+ cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
+ capability, beacon_interval, ie_buf, ie_len,
+ signal, GFP_KERNEL);
}
-int orinoco_process_scan_results(struct orinoco_private *priv,
- unsigned char *buf,
- int len)
+void orinoco_add_extscan_result(struct orinoco_private *priv,
+ struct agere_ext_scan_info *bss,
+ size_t len)
{
- int offset; /* In the scan data */
- union hermes_scan_info *atom;
- int atom_len;
+ struct wiphy *wiphy = priv_to_wiphy(priv);
+ struct ieee80211_channel *channel;
+ u8 *ie;
+ u64 timestamp;
+ s32 signal;
+ u16 capability;
+ u16 beacon_interval;
+ size_t ie_len;
+ int chan, freq;
+
+ ie_len = len - sizeof(*bss);
+ ie = orinoco_get_ie(bss->data, ie_len, WLAN_EID_DS_PARAMS);
+ chan = ie ? ie[2] : 0;
+ freq = ieee80211_dsss_chan_to_freq(chan);
+ channel = ieee80211_get_channel(wiphy, freq);
+
+ timestamp = le64_to_cpu(bss->timestamp);
+ capability = le16_to_cpu(bss->capabilities);
+ beacon_interval = le16_to_cpu(bss->beacon_interval);
+ ie = bss->data;
+ signal = SIGNAL_TO_MBM(bss->level);
+
+ cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
+ capability, beacon_interval, ie, ie_len,
+ signal, GFP_KERNEL);
+}
+
+void orinoco_add_hostscan_results(struct orinoco_private *priv,
+ unsigned char *buf,
+ size_t len)
+{
+ int offset; /* In the scan data */
+ size_t atom_len;
+ bool abort = false;
switch (priv->firmware_type) {
case FIRMWARE_TYPE_AGERE:
atom_len = sizeof(struct agere_scan_apinfo);
offset = 0;
break;
+
case FIRMWARE_TYPE_SYMBOL:
/* Lack of documentation necessitates this hack.
* Different firmwares have 68 or 76 byte long atoms.
@@ -163,6 +182,7 @@ int orinoco_process_scan_results(struct orinoco_private *priv,
atom_len = 68;
offset = 0;
break;
+
case FIRMWARE_TYPE_INTERSIL:
offset = 4;
if (priv->has_hostscan) {
@@ -170,64 +190,41 @@ int orinoco_process_scan_results(struct orinoco_private *priv,
/* Sanity check for atom_len */
if (atom_len < sizeof(struct prism2_scan_apinfo)) {
printk(KERN_ERR "%s: Invalid atom_len in scan "
- "data: %d\n", priv->ndev->name,
+ "data: %zu\n", priv->ndev->name,
atom_len);
- return -EIO;
+ abort = true;
+ goto scan_abort;
}
} else
atom_len = offsetof(struct prism2_scan_apinfo, atim);
break;
+
default:
- return -EOPNOTSUPP;
+ abort = true;
+ goto scan_abort;
}
/* Check that we got an whole number of atoms */
if ((len - offset) % atom_len) {
- printk(KERN_ERR "%s: Unexpected scan data length %d, "
- "atom_len %d, offset %d\n", priv->ndev->name, len,
+ printk(KERN_ERR "%s: Unexpected scan data length %zu, "
+ "atom_len %zu, offset %d\n", priv->ndev->name, len,
atom_len, offset);
- return -EIO;
+ abort = true;
+ goto scan_abort;
}
- orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
-
- /* Read the entries one by one */
+ /* Process the entries one by one */
for (; offset + atom_len <= len; offset += atom_len) {
- int found = 0;
- struct bss_element *bss = NULL;
+ union hermes_scan_info *atom;
- /* Get next atom */
atom = (union hermes_scan_info *) (buf + offset);
- /* Try to update an existing bss first */
- list_for_each_entry(bss, &priv->bss_list, list) {
- if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
- continue;
- if (le16_to_cpu(bss->bss.a.essid_len) !=
- le16_to_cpu(atom->a.essid_len))
- continue;
- if (memcmp(bss->bss.a.essid, atom->a.essid,
- le16_to_cpu(atom->a.essid_len)))
- continue;
- found = 1;
- break;
- }
-
- /* Grab a bss off the free list */
- if (!found && !list_empty(&priv->bss_free_list)) {
- bss = list_entry(priv->bss_free_list.next,
- struct bss_element, list);
- list_del(priv->bss_free_list.next);
-
- list_add_tail(&bss->list, &priv->bss_list);
- }
-
- if (bss) {
- /* Always update the BSS to get latest beacon info */
- memcpy(&bss->bss, atom, sizeof(bss->bss));
- bss->last_scanned = jiffies;
- }
+ orinoco_add_hostscan_result(priv, atom);
}
- return 0;
+ scan_abort:
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, abort);
+ priv->scan_request = NULL;
+ }
}
diff --git a/drivers/net/wireless/orinoco/scan.h b/drivers/net/wireless/orinoco/scan.h
index f319f7466af1..2dc4e046dbdb 100644
--- a/drivers/net/wireless/orinoco/scan.h
+++ b/drivers/net/wireless/orinoco/scan.h
@@ -9,21 +9,12 @@
struct orinoco_private;
struct agere_ext_scan_info;
-/* Setup and free memory for scan results */
-int orinoco_bss_data_allocate(struct orinoco_private *priv);
-void orinoco_bss_data_free(struct orinoco_private *priv);
-void orinoco_bss_data_init(struct orinoco_private *priv);
-
/* Add scan results */
-void orinoco_add_ext_scan_result(struct orinoco_private *priv,
- struct agere_ext_scan_info *atom);
-int orinoco_process_scan_results(struct orinoco_private *dev,
- unsigned char *buf,
- int len);
-
-/* Clear scan results */
-void orinoco_clear_scan_results(struct orinoco_private *priv,
- unsigned long scan_age);
-
+void orinoco_add_extscan_result(struct orinoco_private *priv,
+ struct agere_ext_scan_info *atom,
+ size_t len);
+void orinoco_add_hostscan_results(struct orinoco_private *dev,
+ unsigned char *buf,
+ size_t len);
#endif /* _ORINOCO_SCAN_H_ */
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index 38e5198e44c7..c361310b885d 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -178,27 +178,25 @@ spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
static int
spectrum_cs_probe(struct pcmcia_device *link)
{
- struct net_device *dev;
struct orinoco_private *priv;
struct orinoco_pccard *card;
- dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
- spectrum_cs_hard_reset,
- spectrum_cs_stop_firmware);
- if (!dev)
+ priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+ spectrum_cs_hard_reset,
+ spectrum_cs_stop_firmware);
+ if (!priv)
return -ENOMEM;
- priv = netdev_priv(dev);
card = priv->card;
/* Link both structures together */
card->p_dev = link;
- link->priv = dev;
+ link->priv = priv;
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = orinoco_interrupt;
- link->irq.Instance = dev;
+ link->irq.Instance = priv;
/* General socket configuration defaults can go here. In this
* client, we assume very little, and rely on the CIS for
@@ -219,14 +217,14 @@ spectrum_cs_probe(struct pcmcia_device *link)
*/
static void spectrum_cs_detach(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
+ struct orinoco_private *priv = link->priv;
if (link->dev_node)
- unregister_netdev(dev);
+ orinoco_if_del(priv);
spectrum_cs_release(link);
- free_orinocodev(dev);
+ free_orinocodev(priv);
} /* spectrum_cs_detach */
/*
@@ -306,8 +304,7 @@ next_entry:
static int
spectrum_cs_config(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
hermes_t *hw = &priv->hw;
int last_fn, last_ret;
@@ -362,34 +359,31 @@ spectrum_cs_config(struct pcmcia_device *link)
pcmcia_request_configuration(link, &link->conf));
/* Ok, we have the configuration, prepare to register the netdev */
- dev->base_addr = link->io.BasePort1;
- dev->irq = link->irq.AssignedIRQ;
card->node.major = card->node.minor = 0;
/* Reset card */
if (spectrum_cs_hard_reset(priv) != 0)
goto failed;
- SET_NETDEV_DEV(dev, &handle_to_dev(link));
- /* Tell the stack we exist */
- if (register_netdev(dev) != 0) {
- printk(KERN_ERR PFX "register_netdev() failed\n");
+ /* Initialise the main driver */
+ if (orinoco_init(priv) != 0) {
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
+ goto failed;
+ }
+
+ /* Register an interface with the stack */
+ if (orinoco_if_add(priv, link->io.BasePort1,
+ link->irq.AssignedIRQ) != 0) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
}
/* At this point, the dev_node_t structure(s) needs to be
* initialized and arranged in a linked list at link->dev_node. */
- strcpy(card->node.dev_name, dev->name);
+ strcpy(card->node.dev_name, priv->ndev->name);
link->dev_node = &card->node; /* link->dev_node being non-NULL is also
* used to indicate that the
* net_device has been registered */
-
- /* Finally, report what we've done */
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
- link->irq.AssignedIRQ, link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
-
return 0;
cs_failed:
@@ -408,8 +402,7 @@ spectrum_cs_config(struct pcmcia_device *link)
static void
spectrum_cs_release(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
unsigned long flags;
/* We're committed to taking the device away now, so mark the
@@ -427,23 +420,11 @@ spectrum_cs_release(struct pcmcia_device *link)
static int
spectrum_cs_suspend(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
+ struct orinoco_private *priv = link->priv;
int err = 0;
/* Mark the device as stopped, to block IO until later */
- spin_lock_irqsave(&priv->lock, flags);
-
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
- priv->hw_unavailable++;
-
- spin_unlock_irqrestore(&priv->lock, flags);
+ orinoco_down(priv);
return err;
}
@@ -451,33 +432,10 @@ spectrum_cs_suspend(struct pcmcia_device *link)
static int
spectrum_cs_resume(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
- int err;
-
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
- dev->name, err);
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
- priv->hw_unavailable--;
+ struct orinoco_private *priv = link->priv;
+ int err = orinoco_up(priv);
- if (priv->open && !priv->hw_unavailable) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card\n",
- dev->name, err);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
+ return err;
}
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index 3f0814234392..7698fdd6a3a2 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -7,6 +7,7 @@
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "hermes.h"
#include "hermes_rid.h"
@@ -21,9 +22,70 @@
#define MAX_RID_LEN 1024
+/* Helper routine to record keys
+ * Do not call from interrupt context */
+static int orinoco_set_key(struct orinoco_private *priv, int index,
+ enum orinoco_alg alg, const u8 *key, int key_len,
+ const u8 *seq, int seq_len)
+{
+ kzfree(priv->keys[index].key);
+ kzfree(priv->keys[index].seq);
+
+ if (key_len) {
+ priv->keys[index].key = kzalloc(key_len, GFP_KERNEL);
+ if (!priv->keys[index].key)
+ goto nomem;
+ } else
+ priv->keys[index].key = NULL;
+
+ if (seq_len) {
+ priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL);
+ if (!priv->keys[index].seq)
+ goto free_key;
+ } else
+ priv->keys[index].seq = NULL;
+
+ priv->keys[index].key_len = key_len;
+ priv->keys[index].seq_len = seq_len;
+
+ if (key_len)
+ memcpy(priv->keys[index].key, key, key_len);
+ if (seq_len)
+ memcpy(priv->keys[index].seq, seq, seq_len);
+
+ switch (alg) {
+ case ORINOCO_ALG_TKIP:
+ priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
+ break;
+
+ case ORINOCO_ALG_WEP:
+ priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
+ WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
+ break;
+
+ case ORINOCO_ALG_NONE:
+ default:
+ priv->keys[index].cipher = 0;
+ break;
+ }
+
+ return 0;
+
+free_key:
+ kfree(priv->keys[index].key);
+ priv->keys[index].key = NULL;
+
+nomem:
+ priv->keys[index].key_len = 0;
+ priv->keys[index].seq_len = 0;
+ priv->keys[index].cipher = 0;
+
+ return -ENOMEM;
+}
+
static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
struct iw_statistics *wstats = &priv->wstats;
int err;
@@ -51,7 +113,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
* here so we're not safe to sleep here. */
hermes_inquire(hw, HERMES_INQ_TALLIES);
- if (priv->iw_mode == IW_MODE_ADHOC) {
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
memset(&wstats->qual, 0, sizeof(wstats->qual));
/* If a spy address is defined, we report stats of the
* first spy address - Jean II */
@@ -87,31 +149,12 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
/* Wireless extensions */
/********************************************************************/
-static int orinoco_ioctl_getname(struct net_device *dev,
- struct iw_request_info *info,
- char *name,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int numrates;
- int err;
-
- err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
-
- if (!err && (numrates > 2))
- strcpy(name, "IEEE 802.11b");
- else
- strcpy(name, "IEEE 802.11-DS");
-
- return 0;
-}
-
static int orinoco_ioctl_setwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
@@ -142,7 +185,7 @@ static int orinoco_ioctl_setwap(struct net_device *dev,
goto out;
}
- if (priv->iw_mode != IW_MODE_INFRA) {
+ if (priv->iw_mode != NL80211_IFTYPE_STATION) {
printk(KERN_WARNING "%s: Manual roaming supported only in "
"managed mode\n", dev->name);
err = -EOPNOTSUPP;
@@ -172,9 +215,8 @@ static int orinoco_ioctl_getwap(struct net_device *dev,
struct sockaddr *ap_addr,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
- hermes_t *hw = &priv->hw;
int err = 0;
unsigned long flags;
@@ -182,197 +224,23 @@ static int orinoco_ioctl_getwap(struct net_device *dev,
return -EBUSY;
ap_addr->sa_family = ARPHRD_ETHER;
- err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
- ETH_ALEN, NULL, ap_addr->sa_data);
+ err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data);
orinoco_unlock(priv, &flags);
return err;
}
-static int orinoco_ioctl_setmode(struct net_device *dev,
- struct iw_request_info *info,
- u32 *mode,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int err = -EINPROGRESS; /* Call commit handler */
- unsigned long flags;
-
- if (priv->iw_mode == *mode)
- return 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (*mode) {
- case IW_MODE_ADHOC:
- if (!priv->has_ibss && !priv->has_port3)
- err = -EOPNOTSUPP;
- break;
-
- case IW_MODE_INFRA:
- break;
-
- case IW_MODE_MONITOR:
- if (priv->broken_monitor && !force_monitor) {
- printk(KERN_WARNING "%s: Monitor mode support is "
- "buggy in this firmware, not enabling\n",
- dev->name);
- err = -EOPNOTSUPP;
- }
- break;
-
- default:
- err = -EOPNOTSUPP;
- break;
- }
-
- if (err == -EINPROGRESS) {
- priv->iw_mode = *mode;
- set_port_type(priv);
- }
-
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_getmode(struct net_device *dev,
- struct iw_request_info *info,
- u32 *mode,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
-
- *mode = priv->iw_mode;
- return 0;
-}
-
-static int orinoco_ioctl_getiwrange(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *rrq,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
- struct iw_range *range = (struct iw_range *) extra;
- int numrates;
- int i, k;
-
- rrq->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(struct iw_range));
-
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 22;
-
- /* Set available channels/frequencies */
- range->num_channels = NUM_CHANNELS;
- k = 0;
- for (i = 0; i < NUM_CHANNELS; i++) {
- if (priv->channel_mask & (1 << i)) {
- range->freq[k].i = i + 1;
- range->freq[k].m = (ieee80211_dsss_chan_to_freq(i + 1) *
- 100000);
- range->freq[k].e = 1;
- k++;
- }
-
- if (k >= IW_MAX_FREQUENCIES)
- break;
- }
- range->num_frequency = k;
- range->sensitivity = 3;
-
- if (priv->has_wep) {
- range->max_encoding_tokens = ORINOCO_MAX_KEYS;
- range->encoding_size[0] = SMALL_KEY_SIZE;
- range->num_encoding_sizes = 1;
-
- if (priv->has_big_wep) {
- range->encoding_size[1] = LARGE_KEY_SIZE;
- range->num_encoding_sizes = 2;
- }
- }
-
- if (priv->has_wpa)
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
-
- if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))) {
- /* Quality stats meaningless in ad-hoc mode */
- } else {
- range->max_qual.qual = 0x8b - 0x2f;
- range->max_qual.level = 0x2f - 0x95 - 1;
- range->max_qual.noise = 0x2f - 0x95 - 1;
- /* Need to get better values */
- range->avg_qual.qual = 0x24;
- range->avg_qual.level = 0xC2;
- range->avg_qual.noise = 0x9E;
- }
-
- err = orinoco_hw_get_bitratelist(priv, &numrates,
- range->bitrate, IW_MAX_BITRATES);
- if (err)
- return err;
- range->num_bitrates = numrates;
-
- /* Set an indication of the max TCP throughput in bit/s that we can
- * expect using this interface. May be use for QoS stuff...
- * Jean II */
- if (numrates > 2)
- range->throughput = 5 * 1000 * 1000; /* ~5 Mb/s */
- else
- range->throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */
-
- range->min_rts = 0;
- range->max_rts = 2347;
- range->min_frag = 256;
- range->max_frag = 2346;
-
- range->min_pmp = 0;
- range->max_pmp = 65535000;
- range->min_pmt = 0;
- range->max_pmt = 65535 * 1000; /* ??? */
- range->pmp_flags = IW_POWER_PERIOD;
- range->pmt_flags = IW_POWER_TIMEOUT;
- range->pm_capa = (IW_POWER_PERIOD | IW_POWER_TIMEOUT |
- IW_POWER_UNICAST_R);
-
- range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
- range->retry_flags = IW_RETRY_LIMIT;
- range->r_time_flags = IW_RETRY_LIFETIME;
- range->min_retry = 0;
- range->max_retry = 65535; /* ??? */
- range->min_r_time = 0;
- range->max_r_time = 65535 * 1000; /* ??? */
-
- if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
- range->scan_capa = IW_SCAN_CAPA_ESSID;
- else
- range->scan_capa = IW_SCAN_CAPA_NONE;
-
- /* Event capability (kernel) */
- IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
- /* Event capability (driver) */
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
- IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
-
- return 0;
-}
-
static int orinoco_ioctl_setiwencode(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq,
char *keybuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
int setindex = priv->tx_key;
- int encode_alg = priv->encode_alg;
+ enum orinoco_alg encode_alg = priv->encode_alg;
int restricted = priv->wep_restrict;
- u16 xlen = 0;
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
@@ -392,25 +260,17 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
return -EBUSY;
/* Clear any TKIP key we have */
- if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP))
+ if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP))
(void) orinoco_clear_tkip_key(priv, setindex);
if (erq->length > 0) {
if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
index = priv->tx_key;
- /* Adjust key length to a supported value */
- if (erq->length > SMALL_KEY_SIZE)
- xlen = LARGE_KEY_SIZE;
- else if (erq->length > 0)
- xlen = SMALL_KEY_SIZE;
- else
- xlen = 0;
-
/* Switch on WEP if off */
- if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) {
+ if (encode_alg != ORINOCO_ALG_WEP) {
setindex = index;
- encode_alg = IW_ENCODE_ALG_WEP;
+ encode_alg = ORINOCO_ALG_WEP;
}
} else {
/* Important note : if the user do "iwconfig eth0 enc off",
@@ -423,7 +283,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
}
} else {
/* Set the index : Check that the key is valid */
- if (priv->keys[index].len == 0) {
+ if (priv->keys[index].key_len == 0) {
err = -EINVAL;
goto out;
}
@@ -432,17 +292,15 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
}
if (erq->flags & IW_ENCODE_DISABLED)
- encode_alg = IW_ENCODE_ALG_NONE;
+ encode_alg = ORINOCO_ALG_NONE;
if (erq->flags & IW_ENCODE_OPEN)
restricted = 0;
if (erq->flags & IW_ENCODE_RESTRICTED)
restricted = 1;
if (erq->pointer && erq->length > 0) {
- priv->keys[index].len = cpu_to_le16(xlen);
- memset(priv->keys[index].data, 0,
- sizeof(priv->keys[index].data));
- memcpy(priv->keys[index].data, keybuf, erq->length);
+ err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf,
+ erq->length, NULL, 0);
}
priv->tx_key = setindex;
@@ -469,9 +327,8 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev,
struct iw_point *erq,
char *keybuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
- u16 xlen = 0;
unsigned long flags;
if (!priv->has_wep)
@@ -493,11 +350,9 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev,
else
erq->flags |= IW_ENCODE_OPEN;
- xlen = le16_to_cpu(priv->keys[index].len);
-
- erq->length = xlen;
+ erq->length = priv->keys[index].key_len;
- memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
+ memcpy(keybuf, priv->keys[index].key, erq->length);
orinoco_unlock(priv, &flags);
return 0;
@@ -508,7 +363,7 @@ static int orinoco_ioctl_setessid(struct net_device *dev,
struct iw_point *erq,
char *essidbuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
@@ -539,7 +394,7 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
struct iw_point *erq,
char *essidbuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int active;
int err = 0;
unsigned long flags;
@@ -562,59 +417,18 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
return 0;
}
-static int orinoco_ioctl_setnick(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *nrq,
- char *nickbuf)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
-
- if (nrq->length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- memset(priv->nick, 0, sizeof(priv->nick));
- memcpy(priv->nick, nickbuf, nrq->length);
-
- orinoco_unlock(priv, &flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int orinoco_ioctl_getnick(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *nrq,
- char *nickbuf)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE);
- orinoco_unlock(priv, &flags);
-
- nrq->length = strlen(priv->nick);
-
- return 0;
-}
-
static int orinoco_ioctl_setfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int chan = -1;
unsigned long flags;
int err = -EINPROGRESS; /* Call commit handler */
/* In infrastructure mode the AP sets the channel */
- if (priv->iw_mode == IW_MODE_INFRA)
+ if (priv->iw_mode == NL80211_IFTYPE_STATION)
return -EBUSY;
if ((frq->e == 0) && (frq->m <= 1000)) {
@@ -640,7 +454,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
return -EBUSY;
priv->channel = chan;
- if (priv->iw_mode == IW_MODE_MONITOR) {
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
/* Fast channel change - no commit if successful */
hermes_t *hw = &priv->hw;
err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
@@ -657,7 +471,7 @@ static int orinoco_ioctl_getfreq(struct net_device *dev,
struct iw_freq *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int tmp;
/* Locking done in there */
@@ -676,7 +490,7 @@ static int orinoco_ioctl_getsens(struct net_device *dev,
struct iw_param *srq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
u16 val;
int err;
@@ -705,7 +519,7 @@ static int orinoco_ioctl_setsens(struct net_device *dev,
struct iw_param *srq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = srq->value;
unsigned long flags;
@@ -728,7 +542,7 @@ static int orinoco_ioctl_setrts(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = rrq->value;
unsigned long flags;
@@ -752,7 +566,7 @@ static int orinoco_ioctl_getrts(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
rrq->value = priv->rts_thresh;
rrq->disabled = (rrq->value == 2347);
@@ -766,7 +580,7 @@ static int orinoco_ioctl_setfrag(struct net_device *dev,
struct iw_param *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
@@ -806,7 +620,7 @@ static int orinoco_ioctl_getfrag(struct net_device *dev,
struct iw_param *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err;
u16 val;
@@ -847,7 +661,7 @@ static int orinoco_ioctl_setrate(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int ratemode;
int bitrate; /* 100s of kilobits */
unsigned long flags;
@@ -881,7 +695,7 @@ static int orinoco_ioctl_getrate(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = 0;
int bitrate, automatic;
unsigned long flags;
@@ -910,7 +724,7 @@ static int orinoco_ioctl_setpower(struct net_device *dev,
struct iw_param *prq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
@@ -964,7 +778,7 @@ static int orinoco_ioctl_getpower(struct net_device *dev,
struct iw_param *prq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err = 0;
u16 enable, period, timeout, mcast;
@@ -1018,13 +832,12 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
union iwreq_data *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int idx, alg = ext->alg, set_key = 1;
unsigned long flags;
int err = -EINVAL;
- u16 key_len;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
@@ -1056,48 +869,41 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
/* Set the requested key first */
switch (alg) {
case IW_ENCODE_ALG_NONE:
- priv->encode_alg = alg;
- priv->keys[idx].len = 0;
+ priv->encode_alg = ORINOCO_ALG_NONE;
+ err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE,
+ NULL, 0, NULL, 0);
break;
case IW_ENCODE_ALG_WEP:
- if (ext->key_len > SMALL_KEY_SIZE)
- key_len = LARGE_KEY_SIZE;
- else if (ext->key_len > 0)
- key_len = SMALL_KEY_SIZE;
- else
+ if (ext->key_len <= 0)
goto out;
- priv->encode_alg = alg;
- priv->keys[idx].len = cpu_to_le16(key_len);
-
- key_len = min(ext->key_len, key_len);
-
- memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE);
- memcpy(priv->keys[idx].data, ext->key, key_len);
+ priv->encode_alg = ORINOCO_ALG_WEP;
+ err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP,
+ ext->key, ext->key_len, NULL, 0);
break;
case IW_ENCODE_ALG_TKIP:
{
- hermes_t *hw = &priv->hw;
u8 *tkip_iv = NULL;
if (!priv->has_wpa ||
- (ext->key_len > sizeof(priv->tkip_key[0])))
+ (ext->key_len > sizeof(struct orinoco_tkip_key)))
goto out;
- priv->encode_alg = alg;
- memset(&priv->tkip_key[idx], 0,
- sizeof(priv->tkip_key[idx]));
- memcpy(&priv->tkip_key[idx], ext->key, ext->key_len);
+ priv->encode_alg = ORINOCO_ALG_TKIP;
if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
tkip_iv = &ext->rx_seq[0];
- err = __orinoco_hw_set_tkip_key(hw, idx,
+ err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP,
+ ext->key, ext->key_len, tkip_iv,
+ ORINOCO_SEQ_LEN);
+
+ err = __orinoco_hw_set_tkip_key(priv, idx,
ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
- (u8 *) &priv->tkip_key[idx],
- tkip_iv, NULL);
+ priv->keys[idx].key,
+ tkip_iv, ORINOCO_SEQ_LEN, NULL, 0);
if (err)
printk(KERN_ERR "%s: Error %d setting TKIP key"
"\n", dev->name, err);
@@ -1120,7 +926,7 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev,
union iwreq_data *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int idx, max_key_len;
@@ -1146,22 +952,22 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev,
encoding->flags = idx + 1;
memset(ext, 0, sizeof(*ext));
- ext->alg = priv->encode_alg;
switch (priv->encode_alg) {
- case IW_ENCODE_ALG_NONE:
+ case ORINOCO_ALG_NONE:
+ ext->alg = IW_ENCODE_ALG_NONE;
ext->key_len = 0;
encoding->flags |= IW_ENCODE_DISABLED;
break;
- case IW_ENCODE_ALG_WEP:
- ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len),
- max_key_len);
- memcpy(ext->key, priv->keys[idx].data, ext->key_len);
+ case ORINOCO_ALG_WEP:
+ ext->alg = IW_ENCODE_ALG_WEP;
+ ext->key_len = min(priv->keys[idx].key_len, max_key_len);
+ memcpy(ext->key, priv->keys[idx].key, ext->key_len);
encoding->flags |= IW_ENCODE_ENABLED;
break;
- case IW_ENCODE_ALG_TKIP:
- ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key),
- max_key_len);
- memcpy(ext->key, &priv->tkip_key[idx], ext->key_len);
+ case ORINOCO_ALG_TKIP:
+ ext->alg = IW_ENCODE_ALG_TKIP;
+ ext->key_len = min(priv->keys[idx].key_len, max_key_len);
+ memcpy(ext->key, priv->keys[idx].key, ext->key_len);
encoding->flags |= IW_ENCODE_ENABLED;
break;
}
@@ -1177,7 +983,7 @@ static int orinoco_ioctl_set_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
struct iw_param *param = &wrqu->param;
unsigned long flags;
@@ -1255,7 +1061,7 @@ static int orinoco_ioctl_get_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct iw_param *param = &wrqu->param;
unsigned long flags;
int ret = 0;
@@ -1295,7 +1101,7 @@ static int orinoco_ioctl_set_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
u8 *buf;
unsigned long flags;
@@ -1338,7 +1144,7 @@ static int orinoco_ioctl_get_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int err = 0;
@@ -1367,8 +1173,7 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
- hermes_t *hw = &priv->hw;
+ struct orinoco_private *priv = ndev_priv(dev);
struct iw_mlme *mlme = (struct iw_mlme *)extra;
unsigned long flags;
int ret = 0;
@@ -1382,19 +1187,11 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev,
break;
case IW_MLME_DISASSOC:
- {
- struct {
- u8 addr[ETH_ALEN];
- __le16 reason_code;
- } __attribute__ ((packed)) buf;
-
- memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN);
- buf.reason_code = cpu_to_le16(mlme->reason_code);
- ret = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFDISASSOCIATE,
- &buf);
+
+ ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data,
+ mlme->reason_code);
break;
- }
+
default:
ret = -EOPNOTSUPP;
}
@@ -1408,7 +1205,7 @@ static int orinoco_ioctl_getretry(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err = 0;
u16 short_limit, long_limit, lifetime;
@@ -1462,7 +1259,7 @@ static int orinoco_ioctl_reset(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -1487,14 +1284,14 @@ static int orinoco_ioctl_setibssport(struct net_device *dev,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = *((int *) extra);
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- priv->ibss_port = val ;
+ priv->ibss_port = val;
/* Actually update the mode we are using */
set_port_type(priv);
@@ -1508,7 +1305,7 @@ static int orinoco_ioctl_getibssport(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int *val = (int *) extra;
*val = priv->ibss_port;
@@ -1520,7 +1317,7 @@ static int orinoco_ioctl_setport3(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = *((int *) extra);
int err = 0;
unsigned long flags;
@@ -1566,7 +1363,7 @@ static int orinoco_ioctl_getport3(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int *val = (int *) extra;
*val = priv->prefer_port3;
@@ -1578,7 +1375,7 @@ static int orinoco_ioctl_setpreamble(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int val;
@@ -1610,7 +1407,7 @@ static int orinoco_ioctl_getpreamble(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int *val = (int *) extra;
if (!priv->has_preamble)
@@ -1630,7 +1427,7 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
struct iw_point *data,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int rid = data->flags;
u16 length;
@@ -1661,519 +1458,6 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
return err;
}
-/* Trigger a scan (look for other cells in the vicinity) */
-static int orinoco_ioctl_setscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *srq,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- hermes_t *hw = &priv->hw;
- struct iw_scan_req *si = (struct iw_scan_req *) extra;
- int err = 0;
- unsigned long flags;
-
- /* Note : you may have realised that, as this is a SET operation,
- * this is privileged and therefore a normal user can't
- * perform scanning.
- * This is not an error, while the device perform scanning,
- * traffic doesn't flow, so it's a perfect DoS...
- * Jean II */
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Scanning with port 0 disabled would fail */
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
-
- /* In monitor mode, the scan results are always empty.
- * Probe responses are passed to the driver as received
- * frames and could be processed in software. */
- if (priv->iw_mode == IW_MODE_MONITOR) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- /* Note : because we don't lock out the irq handler, the way
- * we access scan variables in priv is critical.
- * o scan_inprogress : not touched by irq handler
- * o scan_mode : not touched by irq handler
- * Before modifying anything on those variables, please think hard !
- * Jean II */
-
- /* Save flags */
- priv->scan_mode = srq->flags;
-
- /* Always trigger scanning, even if it's in progress.
- * This way, if the info frame get lost, we will recover somewhat
- * gracefully - Jean II */
-
- if (priv->has_hostscan) {
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_SYMBOL:
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFHOSTSCAN_SYMBOL,
- HERMES_HOSTSCAN_SYMBOL_ONCE |
- HERMES_HOSTSCAN_SYMBOL_BCAST);
- break;
- case FIRMWARE_TYPE_INTERSIL: {
- __le16 req[3];
-
- req[0] = cpu_to_le16(0x3fff); /* All channels */
- req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
- req[2] = 0; /* Any ESSID */
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFHOSTSCAN, &req);
- }
- break;
- case FIRMWARE_TYPE_AGERE:
- if (priv->scan_mode & IW_SCAN_THIS_ESSID) {
- struct hermes_idstring idbuf;
- size_t len = min(sizeof(idbuf.val),
- (size_t) si->essid_len);
- idbuf.len = cpu_to_le16(len);
- memcpy(idbuf.val, si->essid, len);
-
- err = hermes_write_ltv(hw, USER_BAP,
- HERMES_RID_CNFSCANSSID_AGERE,
- HERMES_BYTES_TO_RECLEN(len + 2),
- &idbuf);
- } else
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSCANSSID_AGERE,
- 0); /* Any ESSID */
- if (err)
- break;
-
- if (priv->has_ext_scan) {
- /* Clear scan results at the start of
- * an extended scan */
- orinoco_clear_scan_results(priv,
- msecs_to_jiffies(15000));
-
- /* TODO: Is this available on older firmware?
- * Can we use it to scan specific channels
- * for IW_SCAN_THIS_FREQ? */
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSCANCHANNELS2GHZ,
- 0x7FFF);
- if (err)
- goto out;
-
- err = hermes_inquire(hw,
- HERMES_INQ_CHANNELINFO);
- } else
- err = hermes_inquire(hw, HERMES_INQ_SCAN);
- break;
- }
- } else
- err = hermes_inquire(hw, HERMES_INQ_SCAN);
-
- /* One more client */
- if (!err)
- priv->scan_inprogress = 1;
-
- out:
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-#define MAX_CUSTOM_LEN 64
-
-/* Translate scan data returned from the card to a card independant
- * format that the Wireless Tools will understand - Jean II */
-static inline char *orinoco_translate_scan(struct net_device *dev,
- struct iw_request_info *info,
- char *current_ev,
- char *end_buf,
- union hermes_scan_info *bss,
- unsigned long last_scanned)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- u16 capabilities;
- u16 channel;
- struct iw_event iwe; /* Temporary buffer */
- char custom[MAX_CUSTOM_LEN];
-
- memset(&iwe, 0, sizeof(iwe));
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- /* Other entries will be displayed in the order we give them */
-
- /* Add the ESSID */
- iwe.u.data.length = le16_to_cpu(bss->a.essid_len);
- if (iwe.u.data.length > 32)
- iwe.u.data.length = 32;
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss->a.essid);
-
- /* Add mode */
- iwe.cmd = SIOCGIWMODE;
- capabilities = le16_to_cpu(bss->a.capabilities);
- if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
- if (capabilities & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- channel = bss->s.channel;
- if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
- /* Add channel and frequency */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = channel;
- iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
-
- iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
- }
-
- /* Add quality statistics. level and noise in dB. No link quality */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
- iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
- iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
- /* Wireless tools prior to 27.pre22 will show link quality
- * anyway, so we provide a reasonable value. */
- if (iwe.u.qual.level > iwe.u.qual.noise)
- iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
- else
- iwe.u.qual.qual = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (capabilities & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, NULL);
-
- /* Bit rate is not available in Lucent/Agere firmwares */
- if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
- char *current_val = current_ev + iwe_stream_lcp_len(info);
- int i;
- int step;
-
- if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
- step = 2;
- else
- step = 1;
-
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
- /* Max 10 values */
- for (i = 0; i < 10; i += step) {
- /* NULL terminated */
- if (bss->p.rates[i] == 0x0)
- break;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value =
- ((bss->p.rates[i] & 0x7f) * 500000);
- current_val = iwe_stream_add_value(info, current_ev,
- current_val,
- end_buf, &iwe,
- IW_EV_PARAM_LEN);
- }
- /* Check if we added any event */
- if ((current_val - current_ev) > iwe_stream_lcp_len(info))
- current_ev = current_val;
- }
-
- /* Beacon interval */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "bcn_int=%d",
- le16_to_cpu(bss->a.beacon_interv));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Capabilites */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "capab=0x%04x",
- capabilities);
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Add EXTRA: Age to display seconds since last beacon/probe response
- * for given network. */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- " Last beacon: %dms ago",
- jiffies_to_msecs(jiffies - last_scanned));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- return current_ev;
-}
-
-static inline char *orinoco_translate_ext_scan(struct net_device *dev,
- struct iw_request_info *info,
- char *current_ev,
- char *end_buf,
- struct agere_ext_scan_info *bss,
- unsigned long last_scanned)
-{
- u16 capabilities;
- u16 channel;
- struct iw_event iwe; /* Temporary buffer */
- char custom[MAX_CUSTOM_LEN];
- u8 *ie;
-
- memset(&iwe, 0, sizeof(iwe));
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- /* Other entries will be displayed in the order we give them */
-
- /* Add the ESSID */
- ie = bss->data;
- iwe.u.data.length = ie[1];
- if (iwe.u.data.length) {
- if (iwe.u.data.length > 32)
- iwe.u.data.length = 32;
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, &ie[2]);
- }
-
- /* Add mode */
- capabilities = le16_to_cpu(bss->capabilities);
- if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
- iwe.cmd = SIOCGIWMODE;
- if (capabilities & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS);
- channel = ie ? ie[2] : 0;
- if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
- /* Add channel and frequency */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = channel;
- iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
-
- iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
- }
-
- /* Add quality statistics. level and noise in dB. No link quality */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
- iwe.u.qual.level = bss->level - 0x95;
- iwe.u.qual.noise = bss->noise - 0x95;
- /* Wireless tools prior to 27.pre22 will show link quality
- * anyway, so we provide a reasonable value. */
- if (iwe.u.qual.level > iwe.u.qual.noise)
- iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
- else
- iwe.u.qual.qual = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (capabilities & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, NULL);
-
- /* WPA IE */
- ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data));
- if (ie) {
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = ie[1] + 2;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, ie);
- }
-
- /* RSN IE */
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN);
- if (ie) {
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = ie[1] + 2;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, ie);
- }
-
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES);
- if (ie) {
- char *p = current_ev + iwe_stream_lcp_len(info);
- int i;
-
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-
- for (i = 2; i < (ie[1] + 2); i++) {
- iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000);
- p = iwe_stream_add_value(info, current_ev, p, end_buf,
- &iwe, IW_EV_PARAM_LEN);
- }
- /* Check if we added any event */
- if (p > (current_ev + iwe_stream_lcp_len(info)))
- current_ev = p;
- }
-
- /* Timestamp */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length =
- snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx",
- (unsigned long long) le64_to_cpu(bss->timestamp));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Beacon interval */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "bcn_int=%d",
- le16_to_cpu(bss->beacon_interval));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Capabilites */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "capab=0x%04x",
- capabilities);
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Add EXTRA: Age to display seconds since last beacon/probe response
- * for given network. */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- " Last beacon: %dms ago",
- jiffies_to_msecs(jiffies - last_scanned));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- return current_ev;
-}
-
-/* Return results of a scan */
-static int orinoco_ioctl_getscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *srq,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
- unsigned long flags;
- char *current_ev = extra;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if (priv->scan_inprogress) {
- /* Important note : we don't want to block the caller
- * until results are ready for various reasons.
- * First, managing wait queues is complex and racy.
- * Second, we grab some rtnetlink lock before comming
- * here (in dev_ioctl()).
- * Third, we generate an Wireless Event, so the
- * caller can wait itself on that - Jean II */
- err = -EAGAIN;
- goto out;
- }
-
- if (priv->has_ext_scan) {
- struct xbss_element *bss;
-
- list_for_each_entry(bss, &priv->bss_list, list) {
- /* Translate this entry to WE format */
- current_ev =
- orinoco_translate_ext_scan(dev, info,
- current_ev,
- extra + srq->length,
- &bss->bss,
- bss->last_scanned);
-
- /* Check if there is space for one more entry */
- if ((extra + srq->length - current_ev)
- <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a
- * bigger buffer */
- err = -E2BIG;
- goto out;
- }
- }
-
- } else {
- struct bss_element *bss;
-
- list_for_each_entry(bss, &priv->bss_list, list) {
- /* Translate this entry to WE format */
- current_ev = orinoco_translate_scan(dev, info,
- current_ev,
- extra + srq->length,
- &bss->bss,
- bss->last_scanned);
-
- /* Check if there is space for one more entry */
- if ((extra + srq->length - current_ev)
- <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a
- * bigger buffer */
- err = -E2BIG;
- goto out;
- }
- }
- }
-
- srq->length = (current_ev - extra);
- srq->flags = (__u16) priv->scan_mode;
-
-out:
- orinoco_unlock(priv, &flags);
- return err;
-}
/* Commit handler, called after set operations */
static int orinoco_ioctl_commit(struct net_device *dev,
@@ -2181,50 +1465,17 @@ static int orinoco_ioctl_commit(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
- struct hermes *hw = &priv->hw;
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int err = 0;
if (!priv->open)
return 0;
- if (priv->broken_disableport) {
- orinoco_reset(&priv->reset_work);
- return 0;
- }
-
if (orinoco_lock(priv, &flags) != 0)
return err;
- err = hermes_disable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to disable port "
- "while reconfiguring card\n", dev->name);
- priv->broken_disableport = 1;
- goto out;
- }
-
- err = __orinoco_program_rids(dev);
- if (err) {
- printk(KERN_WARNING "%s: Unable to reconfigure card\n",
- dev->name);
- goto out;
- }
-
- err = hermes_enable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
- dev->name);
- goto out;
- }
-
- out:
- if (err) {
- printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
- schedule_work(&priv->reset_work);
- err = 0;
- }
+ err = orinoco_commit(priv);
orinoco_unlock(priv, &flags);
return err;
@@ -2258,26 +1509,24 @@ static const struct iw_priv_args orinoco_privtab[] = {
[IW_IOCTL_IDX(id)] = (iw_handler) func
static const iw_handler orinoco_handler[] = {
STD_IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit),
- STD_IW_HANDLER(SIOCGIWNAME, orinoco_ioctl_getname),
+ STD_IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname),
STD_IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq),
STD_IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq),
- STD_IW_HANDLER(SIOCSIWMODE, orinoco_ioctl_setmode),
- STD_IW_HANDLER(SIOCGIWMODE, orinoco_ioctl_getmode),
+ STD_IW_HANDLER(SIOCSIWMODE, cfg80211_wext_siwmode),
+ STD_IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode),
STD_IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens),
STD_IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens),
- STD_IW_HANDLER(SIOCGIWRANGE, orinoco_ioctl_getiwrange),
+ STD_IW_HANDLER(SIOCGIWRANGE, cfg80211_wext_giwrange),
STD_IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
STD_IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
STD_IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap),
STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap),
- STD_IW_HANDLER(SIOCSIWSCAN, orinoco_ioctl_setscan),
- STD_IW_HANDLER(SIOCGIWSCAN, orinoco_ioctl_getscan),
+ STD_IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan),
+ STD_IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan),
STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid),
STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid),
- STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick),
- STD_IW_HANDLER(SIOCGIWNICKN, orinoco_ioctl_getnick),
STD_IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate),
STD_IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate),
STD_IW_HANDLER(SIOCSIWRTS, orinoco_ioctl_setrts),
diff --git a/drivers/net/wireless/p54/Makefile b/drivers/net/wireless/p54/Makefile
index c2050dee6293..b542e68f1781 100644
--- a/drivers/net/wireless/p54/Makefile
+++ b/drivers/net/wireless/p54/Makefile
@@ -1,3 +1,6 @@
+p54common-objs := eeprom.o fwio.o txrx.o main.o
+p54common-$(CONFIG_P54_LEDS) += led.o
+
obj-$(CONFIG_P54_COMMON) += p54common.o
obj-$(CONFIG_P54_USB) += p54usb.o
obj-$(CONFIG_P54_PCI) += p54pci.o
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
new file mode 100644
index 000000000000..0efe67deedee
--- /dev/null
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -0,0 +1,753 @@
+/*
+ * EEPROM parser code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/sort.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "eeprom.h"
+#include "lmac.h"
+
+static struct ieee80211_rate p54_bgrates[] = {
+ { .bitrate = 10, .hw_value = 0, },
+ { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 60, .hw_value = 4, },
+ { .bitrate = 90, .hw_value = 5, },
+ { .bitrate = 120, .hw_value = 6, },
+ { .bitrate = 180, .hw_value = 7, },
+ { .bitrate = 240, .hw_value = 8, },
+ { .bitrate = 360, .hw_value = 9, },
+ { .bitrate = 480, .hw_value = 10, },
+ { .bitrate = 540, .hw_value = 11, },
+};
+
+static struct ieee80211_rate p54_arates[] = {
+ { .bitrate = 60, .hw_value = 4, },
+ { .bitrate = 90, .hw_value = 5, },
+ { .bitrate = 120, .hw_value = 6, },
+ { .bitrate = 180, .hw_value = 7, },
+ { .bitrate = 240, .hw_value = 8, },
+ { .bitrate = 360, .hw_value = 9, },
+ { .bitrate = 480, .hw_value = 10, },
+ { .bitrate = 540, .hw_value = 11, },
+};
+
+#define CHAN_HAS_CAL BIT(0)
+#define CHAN_HAS_LIMIT BIT(1)
+#define CHAN_HAS_CURVE BIT(2)
+#define CHAN_HAS_ALL (CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE)
+
+struct p54_channel_entry {
+ u16 freq;
+ u16 data;
+ int index;
+ enum ieee80211_band band;
+};
+
+struct p54_channel_list {
+ struct p54_channel_entry *channels;
+ size_t entries;
+ size_t max_entries;
+ size_t band_channel_num[IEEE80211_NUM_BANDS];
+};
+
+static int p54_get_band_from_freq(u16 freq)
+{
+ /* FIXME: sync these values with the 802.11 spec */
+
+ if ((freq >= 2412) && (freq <= 2484))
+ return IEEE80211_BAND_2GHZ;
+
+ if ((freq >= 4920) && (freq <= 5825))
+ return IEEE80211_BAND_5GHZ;
+
+ return -1;
+}
+
+static int p54_compare_channels(const void *_a,
+ const void *_b)
+{
+ const struct p54_channel_entry *a = _a;
+ const struct p54_channel_entry *b = _b;
+
+ return a->index - b->index;
+}
+
+static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
+ struct ieee80211_supported_band *band_entry,
+ enum ieee80211_band band)
+{
+ /* TODO: generate rate array dynamically */
+
+ switch (band) {
+ case IEEE80211_BAND_2GHZ:
+ band_entry->bitrates = p54_bgrates;
+ band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates);
+ break;
+ case IEEE80211_BAND_5GHZ:
+ band_entry->bitrates = p54_arates;
+ band_entry->n_bitrates = ARRAY_SIZE(p54_arates);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int p54_generate_band(struct ieee80211_hw *dev,
+ struct p54_channel_list *list,
+ enum ieee80211_band band)
+{
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_supported_band *tmp, *old;
+ unsigned int i, j;
+ int ret = -ENOMEM;
+
+ if ((!list->entries) || (!list->band_channel_num[band]))
+ return 0;
+
+ tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ goto err_out;
+
+ tmp->channels = kzalloc(sizeof(struct ieee80211_channel) *
+ list->band_channel_num[band], GFP_KERNEL);
+ if (!tmp->channels)
+ goto err_out;
+
+ ret = p54_fill_band_bitrates(dev, tmp, band);
+ if (ret)
+ goto err_out;
+
+ for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
+ (i < list->entries); i++) {
+
+ if (list->channels[i].band != band)
+ continue;
+
+ if (list->channels[i].data != CHAN_HAS_ALL) {
+ printk(KERN_ERR "%s:%s%s%s is/are missing for "
+ "channel:%d [%d MHz].\n",
+ wiphy_name(dev->wiphy),
+ (list->channels[i].data & CHAN_HAS_CAL ? "" :
+ " [iqauto calibration data]"),
+ (list->channels[i].data & CHAN_HAS_LIMIT ? "" :
+ " [output power limits]"),
+ (list->channels[i].data & CHAN_HAS_CURVE ? "" :
+ " [curve data]"),
+ list->channels[i].index, list->channels[i].freq);
+ }
+
+ tmp->channels[j].band = list->channels[i].band;
+ tmp->channels[j].center_freq = list->channels[i].freq;
+ j++;
+ }
+
+ tmp->n_channels = list->band_channel_num[band];
+ old = priv->band_table[band];
+ priv->band_table[band] = tmp;
+ if (old) {
+ kfree(old->channels);
+ kfree(old);
+ }
+
+ return 0;
+
+err_out:
+ if (tmp) {
+ kfree(tmp->channels);
+ kfree(tmp);
+ }
+
+ return ret;
+}
+
+static void p54_update_channel_param(struct p54_channel_list *list,
+ u16 freq, u16 data)
+{
+ int band, i;
+
+ /*
+ * usually all lists in the eeprom are mostly sorted.
+ * so it's very likely that the entry we are looking for
+ * is right at the end of the list
+ */
+ for (i = list->entries; i >= 0; i--) {
+ if (freq == list->channels[i].freq) {
+ list->channels[i].data |= data;
+ break;
+ }
+ }
+
+ if ((i < 0) && (list->entries < list->max_entries)) {
+ /* entry does not exist yet. Initialize a new one. */
+ band = p54_get_band_from_freq(freq);
+
+ /*
+ * filter out frequencies which don't belong into
+ * any supported band.
+ */
+ if (band < 0)
+ return ;
+
+ i = list->entries++;
+ list->band_channel_num[band]++;
+
+ list->channels[i].freq = freq;
+ list->channels[i].data = data;
+ list->channels[i].band = band;
+ list->channels[i].index = ieee80211_frequency_to_channel(freq);
+ /* TODO: parse output_limit and fill max_power */
+ }
+}
+
+static int p54_generate_channel_lists(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_channel_list *list;
+ unsigned int i, j, max_channel_num;
+ int ret = -ENOMEM;
+ u16 freq;
+
+ if ((priv->iq_autocal_len != priv->curve_data->entries) ||
+ (priv->iq_autocal_len != priv->output_limit->entries))
+ printk(KERN_ERR "%s: EEPROM is damaged... you may not be able"
+ "to use all channels with this device.\n",
+ wiphy_name(dev->wiphy));
+
+ max_channel_num = max_t(unsigned int, priv->output_limit->entries,
+ priv->iq_autocal_len);
+ max_channel_num = max_t(unsigned int, max_channel_num,
+ priv->curve_data->entries);
+
+ list = kzalloc(sizeof(*list), GFP_KERNEL);
+ if (!list)
+ goto free;
+
+ list->max_entries = max_channel_num;
+ list->channels = kzalloc(sizeof(struct p54_channel_entry) *
+ max_channel_num, GFP_KERNEL);
+ if (!list->channels)
+ goto free;
+
+ for (i = 0; i < max_channel_num; i++) {
+ if (i < priv->iq_autocal_len) {
+ freq = le16_to_cpu(priv->iq_autocal[i].freq);
+ p54_update_channel_param(list, freq, CHAN_HAS_CAL);
+ }
+
+ if (i < priv->output_limit->entries) {
+ freq = le16_to_cpup((__le16 *) (i *
+ priv->output_limit->entry_size +
+ priv->output_limit->offset +
+ priv->output_limit->data));
+
+ p54_update_channel_param(list, freq, CHAN_HAS_LIMIT);
+ }
+
+ if (i < priv->curve_data->entries) {
+ freq = le16_to_cpup((__le16 *) (i *
+ priv->curve_data->entry_size +
+ priv->curve_data->offset +
+ priv->curve_data->data));
+
+ p54_update_channel_param(list, freq, CHAN_HAS_CURVE);
+ }
+ }
+
+ /* sort the list by the channel index */
+ sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
+ p54_compare_channels, NULL);
+
+ for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) {
+ if (list->band_channel_num[i]) {
+ ret = p54_generate_band(dev, list, i);
+ if (ret)
+ goto free;
+
+ j++;
+ }
+ }
+ if (j == 0) {
+ /* no useable band available. */
+ ret = -EINVAL;
+ }
+
+free:
+ if (list) {
+ kfree(list->channels);
+ kfree(list);
+ }
+
+ return ret;
+}
+
+static int p54_convert_rev0(struct ieee80211_hw *dev,
+ struct pda_pa_curve_data *curve_data)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_pa_curve_data_sample *dst;
+ struct pda_pa_curve_data_sample_rev0 *src;
+ size_t cd_len = sizeof(*curve_data) +
+ (curve_data->points_per_channel*sizeof(*dst) + 2) *
+ curve_data->channels;
+ unsigned int i, j;
+ void *source, *target;
+
+ priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
+ GFP_KERNEL);
+ if (!priv->curve_data)
+ return -ENOMEM;
+
+ priv->curve_data->entries = curve_data->channels;
+ priv->curve_data->entry_size = sizeof(__le16) +
+ sizeof(*dst) * curve_data->points_per_channel;
+ priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
+ priv->curve_data->len = cd_len;
+ memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
+ source = curve_data->data;
+ target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
+ for (i = 0; i < curve_data->channels; i++) {
+ __le16 *freq = source;
+ source += sizeof(__le16);
+ *((__le16 *)target) = *freq;
+ target += sizeof(__le16);
+ for (j = 0; j < curve_data->points_per_channel; j++) {
+ dst = target;
+ src = source;
+
+ dst->rf_power = src->rf_power;
+ dst->pa_detector = src->pa_detector;
+ dst->data_64qam = src->pcv;
+ /* "invent" the points for the other modulations */
+#define SUB(x, y) (u8)(((x) - (y)) > (x) ? 0 : (x) - (y))
+ dst->data_16qam = SUB(src->pcv, 12);
+ dst->data_qpsk = SUB(dst->data_16qam, 12);
+ dst->data_bpsk = SUB(dst->data_qpsk, 12);
+ dst->data_barker = SUB(dst->data_bpsk, 14);
+#undef SUB
+ target += sizeof(*dst);
+ source += sizeof(*src);
+ }
+ }
+
+ return 0;
+}
+
+static int p54_convert_rev1(struct ieee80211_hw *dev,
+ struct pda_pa_curve_data *curve_data)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_pa_curve_data_sample *dst;
+ struct pda_pa_curve_data_sample_rev1 *src;
+ size_t cd_len = sizeof(*curve_data) +
+ (curve_data->points_per_channel*sizeof(*dst) + 2) *
+ curve_data->channels;
+ unsigned int i, j;
+ void *source, *target;
+
+ priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
+ GFP_KERNEL);
+ if (!priv->curve_data)
+ return -ENOMEM;
+
+ priv->curve_data->entries = curve_data->channels;
+ priv->curve_data->entry_size = sizeof(__le16) +
+ sizeof(*dst) * curve_data->points_per_channel;
+ priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
+ priv->curve_data->len = cd_len;
+ memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
+ source = curve_data->data;
+ target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
+ for (i = 0; i < curve_data->channels; i++) {
+ __le16 *freq = source;
+ source += sizeof(__le16);
+ *((__le16 *)target) = *freq;
+ target += sizeof(__le16);
+ for (j = 0; j < curve_data->points_per_channel; j++) {
+ memcpy(target, source, sizeof(*src));
+
+ target += sizeof(*dst);
+ source += sizeof(*src);
+ }
+ source++;
+ }
+
+ return 0;
+}
+
+static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2",
+ "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" };
+
+static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
+ u16 type)
+{
+ struct p54_common *priv = dev->priv;
+ int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
+ int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
+ int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
+ int i;
+
+ if (len != (entry_size * num_entries)) {
+ printk(KERN_ERR "%s: unknown rssi calibration data packing "
+ " type:(%x) len:%d.\n",
+ wiphy_name(dev->wiphy), type, len);
+
+ print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
+ data, len);
+
+ printk(KERN_ERR "%s: please report this issue.\n",
+ wiphy_name(dev->wiphy));
+ return;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ struct pda_rssi_cal_entry *cal = data +
+ (offset + i * entry_size);
+ priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
+ priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
+ }
+}
+
+static void p54_parse_default_country(struct ieee80211_hw *dev,
+ void *data, int len)
+{
+ struct pda_country *country;
+
+ if (len != sizeof(*country)) {
+ printk(KERN_ERR "%s: found possible invalid default country "
+ "eeprom entry. (entry size: %d)\n",
+ wiphy_name(dev->wiphy), len);
+
+ print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
+ data, len);
+
+ printk(KERN_ERR "%s: please report this issue.\n",
+ wiphy_name(dev->wiphy));
+ return;
+ }
+
+ country = (struct pda_country *) data;
+ if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
+ regulatory_hint(dev->wiphy, country->alpha2);
+ else {
+ /* TODO:
+ * write a shared/common function that converts
+ * "Regulatory domain codes" (802.11-2007 14.8.2.2)
+ * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
+ */
+ }
+}
+
+static int p54_convert_output_limits(struct ieee80211_hw *dev,
+ u8 *data, size_t len)
+{
+ struct p54_common *priv = dev->priv;
+
+ if (len < 2)
+ return -EINVAL;
+
+ if (data[0] != 0) {
+ printk(KERN_ERR "%s: unknown output power db revision:%x\n",
+ wiphy_name(dev->wiphy), data[0]);
+ return -EINVAL;
+ }
+
+ if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
+ return -EINVAL;
+
+ priv->output_limit = kmalloc(data[1] *
+ sizeof(struct pda_channel_output_limit) +
+ sizeof(*priv->output_limit), GFP_KERNEL);
+
+ if (!priv->output_limit)
+ return -ENOMEM;
+
+ priv->output_limit->offset = 0;
+ priv->output_limit->entries = data[1];
+ priv->output_limit->entry_size =
+ sizeof(struct pda_channel_output_limit);
+ priv->output_limit->len = priv->output_limit->entry_size *
+ priv->output_limit->entries +
+ priv->output_limit->offset;
+
+ memcpy(priv->output_limit->data, &data[2],
+ data[1] * sizeof(struct pda_channel_output_limit));
+
+ return 0;
+}
+
+static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
+ size_t total_len)
+{
+ struct p54_cal_database *dst;
+ size_t payload_len, entries, entry_size, offset;
+
+ payload_len = le16_to_cpu(src->len);
+ entries = le16_to_cpu(src->entries);
+ entry_size = le16_to_cpu(src->entry_size);
+ offset = le16_to_cpu(src->offset);
+ if (((entries * entry_size + offset) != payload_len) ||
+ (payload_len + sizeof(*src) != total_len))
+ return NULL;
+
+ dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
+ if (!dst)
+ return NULL;
+
+ dst->entries = entries;
+ dst->entry_size = entry_size;
+ dst->offset = offset;
+ dst->len = payload_len;
+
+ memcpy(dst->data, src->data, payload_len);
+ return dst;
+}
+
+int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
+{
+ struct p54_common *priv = dev->priv;
+ struct eeprom_pda_wrap *wrap;
+ struct pda_entry *entry;
+ unsigned int data_len, entry_len;
+ void *tmp;
+ int err;
+ u8 *end = (u8 *)eeprom + len;
+ u16 synth = 0;
+
+ wrap = (struct eeprom_pda_wrap *) eeprom;
+ entry = (void *)wrap->data + le16_to_cpu(wrap->len);
+
+ /* verify that at least the entry length/code fits */
+ while ((u8 *)entry <= end - sizeof(*entry)) {
+ entry_len = le16_to_cpu(entry->len);
+ data_len = ((entry_len - 1) << 1);
+
+ /* abort if entry exceeds whole structure */
+ if ((u8 *)entry + sizeof(*entry) + data_len > end)
+ break;
+
+ switch (le16_to_cpu(entry->code)) {
+ case PDR_MAC_ADDRESS:
+ if (data_len != ETH_ALEN)
+ break;
+ SET_IEEE80211_PERM_ADDR(dev, entry->data);
+ break;
+ case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
+ if (priv->output_limit)
+ break;
+ err = p54_convert_output_limits(dev, entry->data,
+ data_len);
+ if (err)
+ goto err;
+ break;
+ case PDR_PRISM_PA_CAL_CURVE_DATA: {
+ struct pda_pa_curve_data *curve_data =
+ (struct pda_pa_curve_data *)entry->data;
+ if (data_len < sizeof(*curve_data)) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ switch (curve_data->cal_method_rev) {
+ case 0:
+ err = p54_convert_rev0(dev, curve_data);
+ break;
+ case 1:
+ err = p54_convert_rev1(dev, curve_data);
+ break;
+ default:
+ printk(KERN_ERR "%s: unknown curve data "
+ "revision %d\n",
+ wiphy_name(dev->wiphy),
+ curve_data->cal_method_rev);
+ err = -ENODEV;
+ break;
+ }
+ if (err)
+ goto err;
+ }
+ break;
+ case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
+ priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
+ if (!priv->iq_autocal) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(priv->iq_autocal, entry->data, data_len);
+ priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
+ break;
+ case PDR_DEFAULT_COUNTRY:
+ p54_parse_default_country(dev, entry->data, data_len);
+ break;
+ case PDR_INTERFACE_LIST:
+ tmp = entry->data;
+ while ((u8 *)tmp < entry->data + data_len) {
+ struct exp_if *exp_if = tmp;
+ if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000))
+ synth = le16_to_cpu(exp_if->variant);
+ tmp += sizeof(*exp_if);
+ }
+ break;
+ case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
+ if (data_len < 2)
+ break;
+ priv->version = *(u8 *)(entry->data + 1);
+ break;
+ case PDR_RSSI_LINEAR_APPROXIMATION:
+ case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
+ case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
+ p54_parse_rssical(dev, entry->data, data_len,
+ le16_to_cpu(entry->code));
+ break;
+ case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: {
+ __le16 *src = (void *) entry->data;
+ s16 *dst = (void *) &priv->rssical_db;
+ int i;
+
+ if (data_len != sizeof(priv->rssical_db)) {
+ err = -EINVAL;
+ goto err;
+ }
+ for (i = 0; i < sizeof(priv->rssical_db) /
+ sizeof(*src); i++)
+ *(dst++) = (s16) le16_to_cpu(*(src++));
+ }
+ break;
+ case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
+ struct pda_custom_wrapper *pda = (void *) entry->data;
+ if (priv->output_limit || data_len < sizeof(*pda))
+ break;
+ priv->output_limit = p54_convert_db(pda, data_len);
+ }
+ break;
+ case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
+ struct pda_custom_wrapper *pda = (void *) entry->data;
+ if (priv->curve_data || data_len < sizeof(*pda))
+ break;
+ priv->curve_data = p54_convert_db(pda, data_len);
+ }
+ break;
+ case PDR_END:
+ /* make it overrun */
+ entry_len = len;
+ break;
+ default:
+ break;
+ }
+
+ entry = (void *)entry + (entry_len + 1)*2;
+ }
+
+ if (!synth || !priv->iq_autocal || !priv->output_limit ||
+ !priv->curve_data) {
+ printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
+ wiphy_name(dev->wiphy));
+ err = -EINVAL;
+ goto err;
+ }
+
+ err = p54_generate_channel_lists(dev);
+ if (err)
+ goto err;
+
+ priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
+ p54_init_xbow_synth(priv);
+ if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
+ dev->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ priv->band_table[IEEE80211_BAND_2GHZ];
+ if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
+ dev->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ priv->band_table[IEEE80211_BAND_5GHZ];
+ if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
+ priv->rx_diversity_mask = 3;
+ if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
+ priv->tx_diversity_mask = 3;
+
+ if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+ u8 perm_addr[ETH_ALEN];
+
+ printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
+ wiphy_name(dev->wiphy));
+ random_ether_addr(perm_addr);
+ SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+ }
+
+ printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
+ wiphy_name(dev->wiphy), dev->wiphy->perm_addr, priv->version,
+ p54_rf_chips[priv->rxhw]);
+
+ return 0;
+
+err:
+ kfree(priv->iq_autocal);
+ kfree(priv->output_limit);
+ kfree(priv->curve_data);
+ priv->iq_autocal = NULL;
+ priv->output_limit = NULL;
+ priv->curve_data = NULL;
+
+ printk(KERN_ERR "%s: eeprom parse failed!\n",
+ wiphy_name(dev->wiphy));
+ return err;
+}
+EXPORT_SYMBOL_GPL(p54_parse_eeprom);
+
+int p54_read_eeprom(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
+ int ret = -ENOMEM;
+ void *eeprom;
+
+ maxblocksize = EEPROM_READBACK_LEN;
+ if (priv->fw_var >= 0x509)
+ maxblocksize -= 0xc;
+ else
+ maxblocksize -= 0x4;
+
+ eeprom = kzalloc(eeprom_size, GFP_KERNEL);
+ if (unlikely(!eeprom))
+ goto free;
+
+ while (eeprom_size) {
+ blocksize = min(eeprom_size, maxblocksize);
+ ret = p54_download_eeprom(priv, (void *) (eeprom + offset),
+ offset, blocksize);
+ if (unlikely(ret))
+ goto free;
+
+ offset += blocksize;
+ eeprom_size -= blocksize;
+ }
+
+ ret = p54_parse_eeprom(dev, eeprom, offset);
+free:
+ kfree(eeprom);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(p54_read_eeprom);
diff --git a/drivers/net/wireless/p54/eeprom.h b/drivers/net/wireless/p54/eeprom.h
new file mode 100644
index 000000000000..9051aef11249
--- /dev/null
+++ b/drivers/net/wireless/p54/eeprom.h
@@ -0,0 +1,226 @@
+/*
+ * eeprom specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ * Copyright (C) 2007 Conexant Systems, Inc.
+ *
+ * - islmvc driver
+ * Copyright (C) 2001 Intersil Americas Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef EEPROM_H
+#define EEPROM_H
+
+/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
+
+struct pda_entry {
+ __le16 len; /* includes both code and data */
+ __le16 code;
+ u8 data[0];
+} __packed;
+
+struct eeprom_pda_wrap {
+ __le32 magic;
+ __le16 pad;
+ __le16 len;
+ __le32 arm_opcode;
+ u8 data[0];
+} __packed;
+
+struct p54_iq_autocal_entry {
+ __le16 iq_param[4];
+} __packed;
+
+struct pda_iq_autocal_entry {
+ __le16 freq;
+ struct p54_iq_autocal_entry params;
+} __packed;
+
+struct pda_channel_output_limit {
+ __le16 freq;
+ u8 val_bpsk;
+ u8 val_qpsk;
+ u8 val_16qam;
+ u8 val_64qam;
+ u8 rate_set_mask;
+ u8 rate_set_size;
+} __packed;
+
+struct pda_pa_curve_data_sample_rev0 {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 pcv;
+} __packed;
+
+struct pda_pa_curve_data_sample_rev1 {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 data_barker;
+ u8 data_bpsk;
+ u8 data_qpsk;
+ u8 data_16qam;
+ u8 data_64qam;
+} __packed;
+
+struct pda_pa_curve_data {
+ u8 cal_method_rev;
+ u8 channels;
+ u8 points_per_channel;
+ u8 padding;
+ u8 data[0];
+} __packed;
+
+struct pda_rssi_cal_entry {
+ __le16 mul;
+ __le16 add;
+} __packed;
+
+struct pda_country {
+ u8 regdomain;
+ u8 alpha2[2];
+ u8 flags;
+} __packed;
+
+struct pda_antenna_gain {
+ struct {
+ u8 gain_5GHz; /* 0.25 dBi units */
+ u8 gain_2GHz; /* 0.25 dBi units */
+ } __packed antenna[0];
+} __packed;
+
+struct pda_custom_wrapper {
+ __le16 entries;
+ __le16 entry_size;
+ __le16 offset;
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+/*
+ * this defines the PDR codes used to build PDAs as defined in document
+ * number 553155. The current implementation mirrors version 1.1 of the
+ * document and lists only PDRs supported by the ARM platform.
+ */
+
+/* common and choice range (0x0000 - 0x0fff) */
+#define PDR_END 0x0000
+#define PDR_MANUFACTURING_PART_NUMBER 0x0001
+#define PDR_PDA_VERSION 0x0002
+#define PDR_NIC_SERIAL_NUMBER 0x0003
+#define PDR_NIC_RAM_SIZE 0x0005
+#define PDR_RFMODEM_SUP_RANGE 0x0006
+#define PDR_PRISM_MAC_SUP_RANGE 0x0007
+#define PDR_NIC_ID 0x0008
+
+#define PDR_MAC_ADDRESS 0x0101
+#define PDR_REGULATORY_DOMAIN_LIST 0x0103 /* obsolete */
+#define PDR_ALLOWED_CHAN_SET 0x0104
+#define PDR_DEFAULT_CHAN 0x0105
+#define PDR_TEMPERATURE_TYPE 0x0107
+
+#define PDR_IFR_SETTING 0x0200
+#define PDR_RFR_SETTING 0x0201
+#define PDR_3861_BASELINE_REG_SETTINGS 0x0202
+#define PDR_3861_SHADOW_REG_SETTINGS 0x0203
+#define PDR_3861_IFRF_REG_SETTINGS 0x0204
+
+#define PDR_3861_CHAN_CALIB_SET_POINTS 0x0300
+#define PDR_3861_CHAN_CALIB_INTEGRATOR 0x0301
+
+#define PDR_3842_PRISM_II_NIC_CONFIG 0x0400
+#define PDR_PRISM_USB_ID 0x0401
+#define PDR_PRISM_PCI_ID 0x0402
+#define PDR_PRISM_PCI_IF_CONFIG 0x0403
+#define PDR_PRISM_PCI_PM_CONFIG 0x0404
+
+#define PDR_3861_MF_TEST_CHAN_SET_POINTS 0x0900
+#define PDR_3861_MF_TEST_CHAN_INTEGRATORS 0x0901
+
+/* ARM range (0x1000 - 0x1fff) */
+#define PDR_COUNTRY_INFORMATION 0x1000 /* obsolete */
+#define PDR_INTERFACE_LIST 0x1001
+#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002
+#define PDR_OEM_NAME 0x1003
+#define PDR_PRODUCT_NAME 0x1004
+#define PDR_UTF8_OEM_NAME 0x1005
+#define PDR_UTF8_PRODUCT_NAME 0x1006
+#define PDR_COUNTRY_LIST 0x1007
+#define PDR_DEFAULT_COUNTRY 0x1008
+
+#define PDR_ANTENNA_GAIN 0x1100
+
+#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901
+#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903
+#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904
+#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905
+#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906
+#define PDR_REGULATORY_POWER_LIMITS 0x1907
+#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
+#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909
+#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a
+
+/* reserved range (0x2000 - 0x7fff) */
+
+/* customer range (0x8000 - 0xffff) */
+#define PDR_BASEBAND_REGISTERS 0x8000
+#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001
+
+/* used by our modificated eeprom image */
+#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM 0xDEAD
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM 0xBEEF
+#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM 0xB05D
+
+/* Interface Definitions */
+#define PDR_INTERFACE_ROLE_SERVER 0x0000
+#define PDR_INTERFACE_ROLE_CLIENT 0x0001
+
+/* PDR definitions for default country & country list */
+#define PDR_COUNTRY_CERT_CODE 0x80
+#define PDR_COUNTRY_CERT_CODE_REAL 0x00
+#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80
+#define PDR_COUNTRY_CERT_BAND 0x40
+#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00
+#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40
+#define PDR_COUNTRY_CERT_IODOOR 0x30
+#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00
+#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
+#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30
+#define PDR_COUNTRY_CERT_INDEX 0x0f
+
+/* Specific LMAC FW/HW variant definitions */
+#define PDR_SYNTH_FRONTEND_MASK 0x0007
+#define PDR_SYNTH_FRONTEND_DUETTE3 0x0001
+#define PDR_SYNTH_FRONTEND_DUETTE2 0x0002
+#define PDR_SYNTH_FRONTEND_FRISBEE 0x0003
+#define PDR_SYNTH_FRONTEND_XBOW 0x0004
+#define PDR_SYNTH_FRONTEND_LONGBOW 0x0005
+#define PDR_SYNTH_IQ_CAL_MASK 0x0018
+#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000
+#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008
+#define PDR_SYNTH_IQ_CAL_ZIF 0x0010
+#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020
+#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0020
+#define PDR_SYNTH_24_GHZ_MASK 0x0040
+#define PDR_SYNTH_24_GHZ_DISABLED 0x0040
+#define PDR_SYNTH_5_GHZ_MASK 0x0080
+#define PDR_SYNTH_5_GHZ_DISABLED 0x0080
+#define PDR_SYNTH_RX_DIV_MASK 0x0100
+#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100
+#define PDR_SYNTH_TX_DIV_MASK 0x0200
+#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200
+#define PDR_SYNTH_ASM_MASK 0x0400
+#define PDR_SYNTH_ASM_XSWON 0x0400
+
+#endif /* EEPROM_H */
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
new file mode 100644
index 000000000000..e7b9e9cb39f5
--- /dev/null
+++ b/drivers/net/wireless/p54/fwio.c
@@ -0,0 +1,716 @@
+/*
+ * Firmware I/O code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "eeprom.h"
+#include "lmac.h"
+
+int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
+{
+ struct p54_common *priv = dev->priv;
+ struct exp_if *exp_if;
+ struct bootrec *bootrec;
+ u32 *data = (u32 *)fw->data;
+ u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
+ u8 *fw_version = NULL;
+ size_t len;
+ int i;
+ int maxlen;
+
+ if (priv->rx_start)
+ return 0;
+
+ while (data < end_data && *data)
+ data++;
+
+ while (data < end_data && !*data)
+ data++;
+
+ bootrec = (struct bootrec *) data;
+
+ while (bootrec->data <= end_data && (bootrec->data +
+ (len = le32_to_cpu(bootrec->len))) <= end_data) {
+ u32 code = le32_to_cpu(bootrec->code);
+ switch (code) {
+ case BR_CODE_COMPONENT_ID:
+ priv->fw_interface = be32_to_cpup((__be32 *)
+ bootrec->data);
+ switch (priv->fw_interface) {
+ case FW_LM86:
+ case FW_LM20:
+ case FW_LM87: {
+ char *iftype = (char *)bootrec->data;
+ printk(KERN_INFO "%s: p54 detected a LM%c%c "
+ "firmware\n",
+ wiphy_name(priv->hw->wiphy),
+ iftype[2], iftype[3]);
+ break;
+ }
+ case FW_FMAC:
+ default:
+ printk(KERN_ERR "%s: unsupported firmware\n",
+ wiphy_name(priv->hw->wiphy));
+ return -ENODEV;
+ }
+ break;
+ case BR_CODE_COMPONENT_VERSION:
+ /* 24 bytes should be enough for all firmwares */
+ if (strnlen((unsigned char *) bootrec->data, 24) < 24)
+ fw_version = (unsigned char *) bootrec->data;
+ break;
+ case BR_CODE_DESCR: {
+ struct bootrec_desc *desc =
+ (struct bootrec_desc *)bootrec->data;
+ priv->rx_start = le32_to_cpu(desc->rx_start);
+ /* FIXME add sanity checking */
+ priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
+ priv->headroom = desc->headroom;
+ priv->tailroom = desc->tailroom;
+ priv->privacy_caps = desc->privacy_caps;
+ priv->rx_keycache_size = desc->rx_keycache_size;
+ if (le32_to_cpu(bootrec->len) == 11)
+ priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
+ else
+ priv->rx_mtu = (size_t)
+ 0x620 - priv->tx_hdr_len;
+ maxlen = priv->tx_hdr_len + /* USB devices */
+ sizeof(struct p54_rx_data) +
+ 4 + /* rx alignment */
+ IEEE80211_MAX_FRAG_THRESHOLD;
+ if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
+ printk(KERN_INFO "p54: rx_mtu reduced from %d "
+ "to %d\n", priv->rx_mtu, maxlen);
+ priv->rx_mtu = maxlen;
+ }
+ break;
+ }
+ case BR_CODE_EXPOSED_IF:
+ exp_if = (struct exp_if *) bootrec->data;
+ for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
+ if (exp_if[i].if_id == cpu_to_le16(IF_ID_LMAC))
+ priv->fw_var = le16_to_cpu(exp_if[i].variant);
+ break;
+ case BR_CODE_DEPENDENT_IF:
+ break;
+ case BR_CODE_END_OF_BRA:
+ case LEGACY_BR_CODE_END_OF_BRA:
+ end_data = NULL;
+ break;
+ default:
+ break;
+ }
+ bootrec = (struct bootrec *)&bootrec->data[len];
+ }
+
+ if (fw_version)
+ printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
+ wiphy_name(priv->hw->wiphy), fw_version,
+ priv->fw_var >> 8, priv->fw_var & 0xff);
+
+ if (priv->fw_var < 0x500)
+ printk(KERN_INFO "%s: you are using an obsolete firmware. "
+ "visit http://wireless.kernel.org/en/users/Drivers/p54 "
+ "and grab one for \"kernel >= 2.6.28\"!\n",
+ wiphy_name(priv->hw->wiphy));
+
+ if (priv->fw_var >= 0x300) {
+ /* Firmware supports QoS, use it! */
+
+ if (priv->fw_var >= 0x500) {
+ priv->tx_stats[P54_QUEUE_AC_VO].limit = 16;
+ priv->tx_stats[P54_QUEUE_AC_VI].limit = 16;
+ priv->tx_stats[P54_QUEUE_AC_BE].limit = 16;
+ priv->tx_stats[P54_QUEUE_AC_BK].limit = 16;
+ } else {
+ priv->tx_stats[P54_QUEUE_AC_VO].limit = 3;
+ priv->tx_stats[P54_QUEUE_AC_VI].limit = 4;
+ priv->tx_stats[P54_QUEUE_AC_BE].limit = 3;
+ priv->tx_stats[P54_QUEUE_AC_BK].limit = 2;
+ }
+ priv->hw->queues = P54_QUEUE_AC_NUM;
+ }
+
+ printk(KERN_INFO "%s: cryptographic accelerator "
+ "WEP:%s, TKIP:%s, CCMP:%s\n", wiphy_name(priv->hw->wiphy),
+ (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
+ "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
+ BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
+ (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
+ "YES" : "no");
+
+ if (priv->rx_keycache_size) {
+ /*
+ * NOTE:
+ *
+ * The firmware provides at most 255 (0 - 254) slots
+ * for keys which are then used to offload decryption.
+ * As a result the 255 entry (aka 0xff) can be used
+ * safely by the driver to mark keys that didn't fit
+ * into the full cache. This trick saves us from
+ * keeping a extra list for uploaded keys.
+ */
+
+ priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
+ priv->rx_keycache_size), GFP_KERNEL);
+
+ if (!priv->used_rxkeys)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(p54_parse_firmware);
+
+static struct sk_buff *p54_alloc_skb(struct p54_common *priv, u16 hdr_flags,
+ u16 payload_len, u16 type, gfp_t memflags)
+{
+ struct p54_hdr *hdr;
+ struct sk_buff *skb;
+ size_t frame_len = sizeof(*hdr) + payload_len;
+
+ if (frame_len > P54_MAX_CTRL_FRAME_LEN)
+ return NULL;
+
+ if (unlikely(skb_queue_len(&priv->tx_pending) > 64))
+ return NULL;
+
+ skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags);
+ if (!skb)
+ return NULL;
+ skb_reserve(skb, priv->tx_hdr_len);
+
+ hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
+ hdr->flags = cpu_to_le16(hdr_flags);
+ hdr->len = cpu_to_le16(payload_len);
+ hdr->type = cpu_to_le16(type);
+ hdr->tries = hdr->rts_tries = 0;
+ return skb;
+}
+
+int p54_download_eeprom(struct p54_common *priv, void *buf,
+ u16 offset, u16 len)
+{
+ struct p54_eeprom_lm86 *eeprom_hdr;
+ struct sk_buff *skb;
+ size_t eeprom_hdr_size;
+ int ret = 0;
+
+ if (priv->fw_var >= 0x509)
+ eeprom_hdr_size = sizeof(*eeprom_hdr);
+ else
+ eeprom_hdr_size = 0x4;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, eeprom_hdr_size +
+ len, P54_CONTROL_TYPE_EEPROM_READBACK,
+ GFP_KERNEL);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ mutex_lock(&priv->eeprom_mutex);
+ priv->eeprom = buf;
+ eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
+ eeprom_hdr_size + len);
+
+ if (priv->fw_var < 0x509) {
+ eeprom_hdr->v1.offset = cpu_to_le16(offset);
+ eeprom_hdr->v1.len = cpu_to_le16(len);
+ } else {
+ eeprom_hdr->v2.offset = cpu_to_le32(offset);
+ eeprom_hdr->v2.len = cpu_to_le16(len);
+ eeprom_hdr->v2.magic2 = 0xf;
+ memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
+ }
+
+ p54_tx(priv, skb);
+
+ if (!wait_for_completion_interruptible_timeout(
+ &priv->eeprom_comp, HZ)) {
+ printk(KERN_ERR "%s: device does not respond!\n",
+ wiphy_name(priv->hw->wiphy));
+ ret = -EBUSY;
+ }
+ priv->eeprom = NULL;
+ mutex_unlock(&priv->eeprom_mutex);
+ return ret;
+}
+
+int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set)
+{
+ struct sk_buff *skb;
+ struct p54_tim *tim;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim),
+ P54_CONTROL_TYPE_TIM, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
+ tim->count = 1;
+ tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid);
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_sta_unlock(struct p54_common *priv, u8 *addr)
+{
+ struct sk_buff *skb;
+ struct p54_sta_unlock *sta;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta),
+ P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
+ memcpy(sta->addr, addr, ETH_ALEN);
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_tx_cancel(struct p54_common *priv, __le32 req_id)
+{
+ struct sk_buff *skb;
+ struct p54_txcancel *cancel;
+ u32 _req_id = le32_to_cpu(req_id);
+
+ if (unlikely(_req_id < priv->rx_start || _req_id > priv->rx_end))
+ return -EINVAL;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
+ P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
+ cancel->req_id = req_id;
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_setup_mac(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_setup_mac *setup;
+ u16 mode;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
+ P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
+ if (!(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) {
+ switch (priv->mode) {
+ case NL80211_IFTYPE_STATION:
+ mode = P54_FILTER_TYPE_STATION;
+ break;
+ case NL80211_IFTYPE_AP:
+ mode = P54_FILTER_TYPE_AP;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
+ mode = P54_FILTER_TYPE_IBSS;
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ mode = P54_FILTER_TYPE_PROMISCUOUS;
+ break;
+ default:
+ mode = P54_FILTER_TYPE_HIBERNATE;
+ break;
+ }
+
+ /*
+ * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
+ * STSW45X0C LMAC API - page 12
+ */
+ if (((priv->filter_flags & FIF_PROMISC_IN_BSS) ||
+ (priv->filter_flags & FIF_OTHER_BSS)) &&
+ (mode != P54_FILTER_TYPE_PROMISCUOUS))
+ mode |= P54_FILTER_TYPE_TRANSPARENT;
+ } else {
+ mode = P54_FILTER_TYPE_HIBERNATE;
+ }
+
+ setup->mac_mode = cpu_to_le16(mode);
+ memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
+ memcpy(setup->bssid, priv->bssid, ETH_ALEN);
+ setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
+ setup->rx_align = 0;
+ if (priv->fw_var < 0x500) {
+ setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ memset(setup->v1.rts_rates, 0, 8);
+ setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
+ setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
+ setup->v1.rxhw = cpu_to_le16(priv->rxhw);
+ setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
+ setup->v1.unalloc0 = cpu_to_le16(0);
+ } else {
+ setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
+ setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
+ setup->v2.rxhw = cpu_to_le16(priv->rxhw);
+ setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
+ setup->v2.truncate = cpu_to_le16(48896);
+ setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ setup->v2.sbss_offset = 0;
+ setup->v2.mcast_window = 0;
+ setup->v2.rx_rssi_threshold = 0;
+ setup->v2.rx_ed_threshold = 0;
+ setup->v2.ref_clock = cpu_to_le32(644245094);
+ setup->v2.lpf_bandwidth = cpu_to_le16(65535);
+ setup->v2.osc_start_delay = cpu_to_le16(65535);
+ }
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)
+{
+ struct sk_buff *skb;
+ struct p54_hdr *hdr;
+ struct p54_scan_head *head;
+ struct p54_iq_autocal_entry *iq_autocal;
+ union p54_scan_body_union *body;
+ struct p54_scan_tail_rate *rate;
+ struct pda_rssi_cal_entry *rssi;
+ unsigned int i;
+ void *entry;
+ int band = priv->hw->conf.channel->band;
+ __le16 freq = cpu_to_le16(priv->hw->conf.channel->center_freq);
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
+ 2 + sizeof(*iq_autocal) + sizeof(*body) +
+ sizeof(*rate) + 2 * sizeof(*rssi),
+ P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ head = (struct p54_scan_head *) skb_put(skb, sizeof(*head));
+ memset(head->scan_params, 0, sizeof(head->scan_params));
+ head->mode = cpu_to_le16(mode);
+ head->dwell = cpu_to_le16(dwell);
+ head->freq = freq;
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ __le16 *pa_power_points = (__le16 *) skb_put(skb, 2);
+ *pa_power_points = cpu_to_le16(0x0c);
+ }
+
+ iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal));
+ for (i = 0; i < priv->iq_autocal_len; i++) {
+ if (priv->iq_autocal[i].freq != freq)
+ continue;
+
+ memcpy(iq_autocal, &priv->iq_autocal[i].params,
+ sizeof(struct p54_iq_autocal_entry));
+ break;
+ }
+ if (i == priv->iq_autocal_len)
+ goto err;
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
+ body = (void *) skb_put(skb, sizeof(body->longbow));
+ else
+ body = (void *) skb_put(skb, sizeof(body->normal));
+
+ for (i = 0; i < priv->output_limit->entries; i++) {
+ __le16 *entry_freq = (void *) (priv->output_limit->data +
+ priv->output_limit->entry_size * i);
+
+ if (*entry_freq != freq)
+ continue;
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ memcpy(&body->longbow.power_limits,
+ (void *) entry_freq + sizeof(__le16),
+ priv->output_limit->entry_size);
+ } else {
+ struct pda_channel_output_limit *limits =
+ (void *) entry_freq;
+
+ body->normal.val_barker = 0x38;
+ body->normal.val_bpsk = body->normal.dup_bpsk =
+ limits->val_bpsk;
+ body->normal.val_qpsk = body->normal.dup_qpsk =
+ limits->val_qpsk;
+ body->normal.val_16qam = body->normal.dup_16qam =
+ limits->val_16qam;
+ body->normal.val_64qam = body->normal.dup_64qam =
+ limits->val_64qam;
+ }
+ break;
+ }
+ if (i == priv->output_limit->entries)
+ goto err;
+
+ entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
+ for (i = 0; i < priv->curve_data->entries; i++) {
+ if (*((__le16 *)entry) != freq) {
+ entry += priv->curve_data->entry_size;
+ continue;
+ }
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ memcpy(&body->longbow.curve_data,
+ (void *) entry + sizeof(__le16),
+ priv->curve_data->entry_size);
+ } else {
+ struct p54_scan_body *chan = &body->normal;
+ struct pda_pa_curve_data *curve_data =
+ (void *) priv->curve_data->data;
+
+ entry += sizeof(__le16);
+ chan->pa_points_per_curve = 8;
+ memset(chan->curve_data, 0, sizeof(*chan->curve_data));
+ memcpy(chan->curve_data, entry,
+ sizeof(struct p54_pa_curve_data_sample) *
+ min((u8)8, curve_data->points_per_channel));
+ }
+ break;
+ }
+ if (i == priv->curve_data->entries)
+ goto err;
+
+ if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
+ rate = (void *) skb_put(skb, sizeof(*rate));
+ rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ for (i = 0; i < sizeof(rate->rts_rates); i++)
+ rate->rts_rates[i] = i;
+ }
+
+ rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi));
+ rssi->mul = cpu_to_le16(priv->rssical_db[band].mul);
+ rssi->add = cpu_to_le16(priv->rssical_db[band].add);
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ /* Longbow frontend needs ever more */
+ rssi = (void *) skb_put(skb, sizeof(*rssi));
+ rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn);
+ rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2);
+ }
+
+ if (priv->fw_var >= 0x509) {
+ rate = (void *) skb_put(skb, sizeof(*rate));
+ rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ for (i = 0; i < sizeof(rate->rts_rates); i++)
+ rate->rts_rates[i] = i;
+ }
+
+ hdr = (struct p54_hdr *) skb->data;
+ hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));
+
+ p54_tx(priv, skb);
+ return 0;
+
+err:
+ printk(KERN_ERR "%s: frequency change to channel %d failed.\n",
+ wiphy_name(priv->hw->wiphy), ieee80211_frequency_to_channel(
+ priv->hw->conf.channel->center_freq));
+
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+}
+
+int p54_set_leds(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_led *led;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led),
+ P54_CONTROL_TYPE_LED, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ led = (struct p54_led *) skb_put(skb, sizeof(*led));
+ led->flags = cpu_to_le16(0x0003);
+ led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
+ led->delay[0] = cpu_to_le16(1);
+ led->delay[1] = cpu_to_le16(0);
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_set_edcf(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_edcf *edcf;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),
+ P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
+ if (priv->use_short_slot) {
+ edcf->slottime = 9;
+ edcf->sifs = 0x10;
+ edcf->eofpad = 0x00;
+ } else {
+ edcf->slottime = 20;
+ edcf->sifs = 0x0a;
+ edcf->eofpad = 0x06;
+ }
+ /* (see prism54/isl_oid.h for further details) */
+ edcf->frameburst = cpu_to_le16(0);
+ edcf->round_trip_delay = cpu_to_le16(0);
+ edcf->flags = 0;
+ memset(edcf->mapping, 0, sizeof(edcf->mapping));
+ memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_set_ps(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_psm *psm;
+ unsigned int i;
+ u16 mode;
+
+ if (priv->hw->conf.flags & IEEE80211_CONF_PS &&
+ !priv->powersave_override)
+ mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
+ P54_PSM_CHECKSUM | P54_PSM_MCBC;
+ else
+ mode = P54_PSM_CAM;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
+ P54_CONTROL_TYPE_PSM, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ psm = (struct p54_psm *)skb_put(skb, sizeof(*psm));
+ psm->mode = cpu_to_le16(mode);
+ psm->aid = cpu_to_le16(priv->aid);
+ for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) {
+ psm->intervals[i].interval =
+ cpu_to_le16(priv->hw->conf.listen_interval);
+ psm->intervals[i].periods = cpu_to_le16(1);
+ }
+
+ psm->beacon_rssi_skip_max = 200;
+ psm->rssi_delta_threshold = 0;
+ psm->nr = 1;
+ psm->exclude[0] = WLAN_EID_TIM;
+
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_init_xbow_synth(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_xbow_synth *xbow;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow),
+ P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
+ xbow->magic1 = cpu_to_le16(0x1);
+ xbow->magic2 = cpu_to_le16(0x2);
+ xbow->freq = cpu_to_le16(5390);
+ memset(xbow->padding, 0, sizeof(xbow->padding));
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len,
+ u8 *addr, u8* key)
+{
+ struct sk_buff *skb;
+ struct p54_keycache *rxkey;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
+ P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
+ rxkey->entry = slot;
+ rxkey->key_id = idx;
+ rxkey->key_type = algo;
+ if (addr)
+ memcpy(rxkey->mac, addr, ETH_ALEN);
+ else
+ memset(rxkey->mac, ~0, ETH_ALEN);
+
+ switch (algo) {
+ case P54_CRYPTO_WEP:
+ case P54_CRYPTO_AESCCMP:
+ rxkey->key_len = min_t(u8, 16, len);
+ memcpy(rxkey->key, key, rxkey->key_len);
+ break;
+
+ case P54_CRYPTO_TKIPMICHAEL:
+ rxkey->key_len = 24;
+ memcpy(rxkey->key, key, 16);
+ memcpy(&(rxkey->key[16]), &(key
+ [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
+ break;
+
+ case P54_CRYPTO_NONE:
+ rxkey->key_len = 0;
+ memset(rxkey->key, 0, sizeof(rxkey->key));
+ break;
+
+ default:
+ printk(KERN_ERR "%s: invalid cryptographic algorithm: %d\n",
+ wiphy_name(priv->hw->wiphy), algo);
+ dev_kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_fetch_statistics(struct p54_common *priv)
+{
+ struct ieee80211_tx_info *txinfo;
+ struct p54_tx_info *p54info;
+ struct sk_buff *skb;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL,
+ sizeof(struct p54_statistics),
+ P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ /*
+ * The statistic feedback causes some extra headaches here, if it
+ * is not to crash/corrupt the firmware data structures.
+ *
+ * Unlike all other Control Get OIDs we can not use helpers like
+ * skb_put to reserve the space for the data we're requesting.
+ * Instead the extra frame length -which will hold the results later-
+ * will only be told to the p54_assign_address, so that following
+ * frames won't be placed into the allegedly empty area.
+ */
+ txinfo = IEEE80211_SKB_CB(skb);
+ p54info = (void *) txinfo->rate_driver_data;
+ p54info->extra_len = sizeof(struct p54_statistics);
+
+ p54_tx(priv, skb);
+ return 0;
+}
diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c
new file mode 100644
index 000000000000..9575ac033630
--- /dev/null
+++ b/drivers/net/wireless/p54/led.c
@@ -0,0 +1,162 @@
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+#ifdef CONFIG_P54_LEDS
+#include <linux/leds.h>
+#endif /* CONFIG_P54_LEDS */
+
+#include "p54.h"
+#include "lmac.h"
+
+static void p54_update_leds(struct work_struct *work)
+{
+ struct p54_common *priv = container_of(work, struct p54_common,
+ led_work.work);
+ int err, i, tmp, blink_delay = 400;
+ bool rerun = false;
+
+ /* Don't toggle the LED, when the device is down. */
+ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ return ;
+
+ for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
+ if (priv->leds[i].toggled) {
+ priv->softled_state |= BIT(i);
+
+ tmp = 70 + 200 / (priv->leds[i].toggled);
+ if (tmp < blink_delay)
+ blink_delay = tmp;
+
+ if (priv->leds[i].led_dev.brightness == LED_OFF)
+ rerun = true;
+
+ priv->leds[i].toggled =
+ !!priv->leds[i].led_dev.brightness;
+ } else
+ priv->softled_state &= ~BIT(i);
+
+ err = p54_set_leds(priv);
+ if (err && net_ratelimit())
+ printk(KERN_ERR "%s: failed to update LEDs (%d).\n",
+ wiphy_name(priv->hw->wiphy), err);
+
+ if (rerun)
+ ieee80211_queue_delayed_work(priv->hw, &priv->led_work,
+ msecs_to_jiffies(blink_delay));
+}
+
+static void p54_led_brightness_set(struct led_classdev *led_dev,
+ enum led_brightness brightness)
+{
+ struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev,
+ led_dev);
+ struct ieee80211_hw *dev = led->hw_dev;
+ struct p54_common *priv = dev->priv;
+
+ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ return ;
+
+ if ((brightness) && (led->registered)) {
+ led->toggled++;
+ ieee80211_queue_delayed_work(priv->hw, &priv->led_work, HZ/10);
+ }
+}
+
+static int p54_register_led(struct p54_common *priv,
+ unsigned int led_index,
+ char *name, char *trigger)
+{
+ struct p54_led_dev *led = &priv->leds[led_index];
+ int err;
+
+ if (led->registered)
+ return -EEXIST;
+
+ snprintf(led->name, sizeof(led->name), "p54-%s::%s",
+ wiphy_name(priv->hw->wiphy), name);
+ led->hw_dev = priv->hw;
+ led->index = led_index;
+ led->led_dev.name = led->name;
+ led->led_dev.default_trigger = trigger;
+ led->led_dev.brightness_set = p54_led_brightness_set;
+
+ err = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_dev);
+ if (err)
+ printk(KERN_ERR "%s: Failed to register %s LED.\n",
+ wiphy_name(priv->hw->wiphy), name);
+ else
+ led->registered = 1;
+
+ return err;
+}
+
+int p54_init_leds(struct p54_common *priv)
+{
+ int err;
+
+ /*
+ * TODO:
+ * Figure out if the EEPROM contains some hints about the number
+ * of available/programmable LEDs of the device.
+ */
+
+ INIT_DELAYED_WORK(&priv->led_work, p54_update_leds);
+
+ err = p54_register_led(priv, 0, "assoc",
+ ieee80211_get_assoc_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_register_led(priv, 1, "tx",
+ ieee80211_get_tx_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_register_led(priv, 2, "rx",
+ ieee80211_get_rx_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_register_led(priv, 3, "radio",
+ ieee80211_get_radio_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_set_leds(priv);
+ return err;
+}
+
+void p54_unregister_leds(struct p54_common *priv)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(priv->leds); i++) {
+ if (priv->leds[i].registered) {
+ priv->leds[i].registered = false;
+ priv->leds[i].toggled = 0;
+ led_classdev_unregister(&priv->leds[i].led_dev);
+ }
+ }
+
+ cancel_delayed_work_sync(&priv->led_work);
+}
diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h
new file mode 100644
index 000000000000..04b63ec80fa4
--- /dev/null
+++ b/drivers/net/wireless/p54/lmac.h
@@ -0,0 +1,558 @@
+/*
+ * LMAC Interface specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007 - 2009, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ * Copyright (C) 2007 Conexant Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef LMAC_H
+#define LMAC_H
+
+enum p54_control_frame_types {
+ P54_CONTROL_TYPE_SETUP = 0,
+ P54_CONTROL_TYPE_SCAN,
+ P54_CONTROL_TYPE_TRAP,
+ P54_CONTROL_TYPE_DCFINIT,
+ P54_CONTROL_TYPE_RX_KEYCACHE,
+ P54_CONTROL_TYPE_TIM,
+ P54_CONTROL_TYPE_PSM,
+ P54_CONTROL_TYPE_TXCANCEL,
+ P54_CONTROL_TYPE_TXDONE,
+ P54_CONTROL_TYPE_BURST,
+ P54_CONTROL_TYPE_STAT_READBACK,
+ P54_CONTROL_TYPE_BBP,
+ P54_CONTROL_TYPE_EEPROM_READBACK,
+ P54_CONTROL_TYPE_LED,
+ P54_CONTROL_TYPE_GPIO,
+ P54_CONTROL_TYPE_TIMER,
+ P54_CONTROL_TYPE_MODULATION,
+ P54_CONTROL_TYPE_SYNTH_CONFIG,
+ P54_CONTROL_TYPE_DETECTOR_VALUE,
+ P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
+ P54_CONTROL_TYPE_CCE_QUIET,
+ P54_CONTROL_TYPE_PSM_STA_UNLOCK,
+ P54_CONTROL_TYPE_PCS,
+ P54_CONTROL_TYPE_BT_BALANCER = 28,
+ P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
+ P54_CONTROL_TYPE_ARPTABLE = 31,
+ P54_CONTROL_TYPE_BT_OPTIONS = 35,
+};
+
+#define P54_HDR_FLAG_CONTROL BIT(15)
+#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0))
+#define P54_HDR_FLAG_DATA_ALIGN BIT(14)
+
+#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0)
+#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
+#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2)
+#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3)
+#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4)
+#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5)
+#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6)
+#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7)
+#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8)
+#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9)
+#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10)
+#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11)
+
+#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0)
+#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1)
+#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2)
+#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3)
+#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4)
+#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5)
+#define P54_HDR_FLAG_DATA_IN_DATA BIT(6)
+#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7)
+#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8)
+#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9)
+
+struct p54_hdr {
+ __le16 flags;
+ __le16 len;
+ __le32 req_id;
+ __le16 type; /* enum p54_control_frame_types */
+ u8 rts_tries;
+ u8 tries;
+ u8 data[0];
+} __packed;
+
+#define GET_REQ_ID(skb) \
+ (((struct p54_hdr *) ((struct sk_buff *) skb)->data)->req_id) \
+
+#define FREE_AFTER_TX(skb) \
+ ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
+ flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+
+#define IS_DATA_FRAME(skb) \
+ (!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
+ flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL)))
+
+#define GET_HW_QUEUE(skb) \
+ (((struct p54_tx_data *)((struct p54_hdr *) \
+ skb->data)->data)->hw_queue)
+
+/*
+ * shared interface ID definitions
+ * The interface ID is a unique identification of a specific interface.
+ * The following values are reserved: 0x0000, 0x0002, 0x0012, 0x0014, 0x0015
+ */
+#define IF_ID_ISL36356A 0x0001 /* ISL36356A <-> Firmware */
+#define IF_ID_MVC 0x0003 /* MAC Virtual Coprocessor */
+#define IF_ID_DEBUG 0x0008 /* PolDebug Interface */
+#define IF_ID_PRODUCT 0x0009
+#define IF_ID_OEM 0x000a
+#define IF_ID_PCI3877 0x000b /* 3877 <-> Host PCI */
+#define IF_ID_ISL37704C 0x000c /* ISL37704C <-> Fw */
+#define IF_ID_ISL39000 0x000f /* ISL39000 <-> Fw */
+#define IF_ID_ISL39300A 0x0010 /* ISL39300A <-> Fw */
+#define IF_ID_ISL37700_UAP 0x0016 /* ISL37700 uAP Fw <-> Fw */
+#define IF_ID_ISL39000_UAP 0x0017 /* ISL39000 uAP Fw <-> Fw */
+#define IF_ID_LMAC 0x001a /* Interface exposed by LMAC */
+
+struct exp_if {
+ __le16 role;
+ __le16 if_id;
+ __le16 variant;
+ __le16 btm_compat;
+ __le16 top_compat;
+} __packed;
+
+struct dep_if {
+ __le16 role;
+ __le16 if_id;
+ __le16 variant;
+} __packed;
+
+/* driver <-> lmac definitions */
+struct p54_eeprom_lm86 {
+ union {
+ struct {
+ __le16 offset;
+ __le16 len;
+ u8 data[0];
+ } __packed v1;
+ struct {
+ __le32 offset;
+ __le16 len;
+ u8 magic2;
+ u8 pad;
+ u8 magic[4];
+ u8 data[0];
+ } __packed v2;
+ } __packed;
+} __packed;
+
+enum p54_rx_decrypt_status {
+ P54_DECRYPT_NONE = 0,
+ P54_DECRYPT_OK,
+ P54_DECRYPT_NOKEY,
+ P54_DECRYPT_NOMICHAEL,
+ P54_DECRYPT_NOCKIPMIC,
+ P54_DECRYPT_FAIL_WEP,
+ P54_DECRYPT_FAIL_TKIP,
+ P54_DECRYPT_FAIL_MICHAEL,
+ P54_DECRYPT_FAIL_CKIPKP,
+ P54_DECRYPT_FAIL_CKIPMIC,
+ P54_DECRYPT_FAIL_AESCCMP
+};
+
+struct p54_rx_data {
+ __le16 flags;
+ __le16 len;
+ __le16 freq;
+ u8 antenna;
+ u8 rate;
+ u8 rssi;
+ u8 quality;
+ u8 decrypt_status;
+ u8 rssi_raw;
+ __le32 tsf32;
+ __le32 unalloc0;
+ u8 align[0];
+} __packed;
+
+enum p54_trap_type {
+ P54_TRAP_SCAN = 0,
+ P54_TRAP_TIMER,
+ P54_TRAP_BEACON_TX,
+ P54_TRAP_FAA_RADIO_ON,
+ P54_TRAP_FAA_RADIO_OFF,
+ P54_TRAP_RADAR,
+ P54_TRAP_NO_BEACON,
+ P54_TRAP_TBTT,
+ P54_TRAP_SCO_ENTER,
+ P54_TRAP_SCO_EXIT
+};
+
+struct p54_trap {
+ __le16 event;
+ __le16 frequency;
+} __packed;
+
+enum p54_frame_sent_status {
+ P54_TX_OK = 0,
+ P54_TX_FAILED,
+ P54_TX_PSM,
+ P54_TX_PSM_CANCELLED = 4
+};
+
+struct p54_frame_sent {
+ u8 status;
+ u8 tries;
+ u8 ack_rssi;
+ u8 quality;
+ __le16 seq;
+ u8 antenna;
+ u8 padding;
+} __packed;
+
+enum p54_tx_data_crypt {
+ P54_CRYPTO_NONE = 0,
+ P54_CRYPTO_WEP,
+ P54_CRYPTO_TKIP,
+ P54_CRYPTO_TKIPMICHAEL,
+ P54_CRYPTO_CCX_WEPMIC,
+ P54_CRYPTO_CCX_KPMIC,
+ P54_CRYPTO_CCX_KP,
+ P54_CRYPTO_AESCCMP
+};
+
+enum p54_tx_data_queue {
+ P54_QUEUE_BEACON = 0,
+ P54_QUEUE_FWSCAN = 1,
+ P54_QUEUE_MGMT = 2,
+ P54_QUEUE_CAB = 3,
+ P54_QUEUE_DATA = 4,
+
+ P54_QUEUE_AC_NUM = 4,
+ P54_QUEUE_AC_VO = 4,
+ P54_QUEUE_AC_VI = 5,
+ P54_QUEUE_AC_BE = 6,
+ P54_QUEUE_AC_BK = 7,
+
+ /* keep last */
+ P54_QUEUE_NUM = 8,
+};
+
+#define IS_QOS_QUEUE(n) (n >= P54_QUEUE_DATA)
+
+struct p54_tx_data {
+ u8 rateset[8];
+ u8 rts_rate_idx;
+ u8 crypt_offset;
+ u8 key_type;
+ u8 key_len;
+ u8 key[16];
+ u8 hw_queue;
+ u8 backlog;
+ __le16 durations[4];
+ u8 tx_antenna;
+ union {
+ struct {
+ u8 cts_rate;
+ __le16 output_power;
+ } __packed longbow;
+ struct {
+ u8 output_power;
+ u8 cts_rate;
+ u8 unalloc;
+ } __packed normal;
+ } __packed;
+ u8 unalloc2[2];
+ u8 align[0];
+} __packed;
+
+/* unit is ms */
+#define P54_TX_FRAME_LIFETIME 2000
+#define P54_TX_TIMEOUT 4000
+#define P54_STATISTICS_UPDATE 5000
+
+#define P54_FILTER_TYPE_NONE 0
+#define P54_FILTER_TYPE_STATION BIT(0)
+#define P54_FILTER_TYPE_IBSS BIT(1)
+#define P54_FILTER_TYPE_AP BIT(2)
+#define P54_FILTER_TYPE_TRANSPARENT BIT(3)
+#define P54_FILTER_TYPE_PROMISCUOUS BIT(4)
+#define P54_FILTER_TYPE_HIBERNATE BIT(5)
+#define P54_FILTER_TYPE_NOACK BIT(6)
+#define P54_FILTER_TYPE_RX_DISABLED BIT(7)
+
+struct p54_setup_mac {
+ __le16 mac_mode;
+ u8 mac_addr[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ u8 rx_antenna;
+ u8 rx_align;
+ union {
+ struct {
+ __le32 basic_rate_mask;
+ u8 rts_rates[8];
+ __le32 rx_addr;
+ __le16 max_rx;
+ __le16 rxhw;
+ __le16 wakeup_timer;
+ __le16 unalloc0;
+ } __packed v1;
+ struct {
+ __le32 rx_addr;
+ __le16 max_rx;
+ __le16 rxhw;
+ __le16 timer;
+ __le16 truncate;
+ __le32 basic_rate_mask;
+ u8 sbss_offset;
+ u8 mcast_window;
+ u8 rx_rssi_threshold;
+ u8 rx_ed_threshold;
+ __le32 ref_clock;
+ __le16 lpf_bandwidth;
+ __le16 osc_start_delay;
+ } __packed v2;
+ } __packed;
+} __packed;
+
+#define P54_SETUP_V1_LEN 40
+#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
+
+#define P54_SCAN_EXIT BIT(0)
+#define P54_SCAN_TRAP BIT(1)
+#define P54_SCAN_ACTIVE BIT(2)
+#define P54_SCAN_FILTER BIT(3)
+
+struct p54_scan_head {
+ __le16 mode;
+ __le16 dwell;
+ u8 scan_params[20];
+ __le16 freq;
+} __packed;
+
+struct p54_pa_curve_data_sample {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 data_barker;
+ u8 data_bpsk;
+ u8 data_qpsk;
+ u8 data_16qam;
+ u8 data_64qam;
+ u8 padding;
+} __packed;
+
+struct p54_scan_body {
+ u8 pa_points_per_curve;
+ u8 val_barker;
+ u8 val_bpsk;
+ u8 val_qpsk;
+ u8 val_16qam;
+ u8 val_64qam;
+ struct p54_pa_curve_data_sample curve_data[8];
+ u8 dup_bpsk;
+ u8 dup_qpsk;
+ u8 dup_16qam;
+ u8 dup_64qam;
+} __packed;
+
+/*
+ * Warning: Longbow's structures are bogus.
+ */
+struct p54_channel_output_limit_longbow {
+ __le16 rf_power_points[12];
+} __packed;
+
+struct p54_pa_curve_data_sample_longbow {
+ __le16 rf_power;
+ __le16 pa_detector;
+ struct {
+ __le16 data[4];
+ } points[3] __packed;
+} __packed;
+
+struct p54_scan_body_longbow {
+ struct p54_channel_output_limit_longbow power_limits;
+ struct p54_pa_curve_data_sample_longbow curve_data[8];
+ __le16 unkn[6]; /* maybe more power_limits or rate_mask */
+} __packed;
+
+union p54_scan_body_union {
+ struct p54_scan_body normal;
+ struct p54_scan_body_longbow longbow;
+} __packed;
+
+struct p54_scan_tail_rate {
+ __le32 basic_rate_mask;
+ u8 rts_rates[8];
+} __packed;
+
+struct p54_led {
+ __le16 flags;
+ __le16 mask[2];
+ __le16 delay[2];
+} __packed;
+
+struct p54_edcf {
+ u8 flags;
+ u8 slottime;
+ u8 sifs;
+ u8 eofpad;
+ struct p54_edcf_queue_param queue[8];
+ u8 mapping[4];
+ __le16 frameburst;
+ __le16 round_trip_delay;
+} __packed;
+
+struct p54_statistics {
+ __le32 rx_success;
+ __le32 rx_bad_fcs;
+ __le32 rx_abort;
+ __le32 rx_abort_phy;
+ __le32 rts_success;
+ __le32 rts_fail;
+ __le32 tsf32;
+ __le32 airtime;
+ __le32 noise;
+ __le32 sample_noise[8];
+ __le32 sample_cca;
+ __le32 sample_tx;
+} __packed;
+
+struct p54_xbow_synth {
+ __le16 magic1;
+ __le16 magic2;
+ __le16 freq;
+ u32 padding[5];
+} __packed;
+
+struct p54_timer {
+ __le32 interval;
+} __packed;
+
+struct p54_keycache {
+ u8 entry;
+ u8 key_id;
+ u8 mac[ETH_ALEN];
+ u8 padding[2];
+ u8 key_type;
+ u8 key_len;
+ u8 key[24];
+} __packed;
+
+struct p54_burst {
+ u8 flags;
+ u8 queue;
+ u8 backlog;
+ u8 pad;
+ __le16 durations[32];
+} __packed;
+
+struct p54_psm_interval {
+ __le16 interval;
+ __le16 periods;
+} __packed;
+
+#define P54_PSM_CAM 0
+#define P54_PSM BIT(0)
+#define P54_PSM_DTIM BIT(1)
+#define P54_PSM_MCBC BIT(2)
+#define P54_PSM_CHECKSUM BIT(3)
+#define P54_PSM_SKIP_MORE_DATA BIT(4)
+#define P54_PSM_BEACON_TIMEOUT BIT(5)
+#define P54_PSM_HFOSLEEP BIT(6)
+#define P54_PSM_AUTOSWITCH_SLEEP BIT(7)
+#define P54_PSM_LPIT BIT(8)
+#define P54_PSM_BF_UCAST_SKIP BIT(9)
+#define P54_PSM_BF_MCAST_SKIP BIT(10)
+
+struct p54_psm {
+ __le16 mode;
+ __le16 aid;
+ struct p54_psm_interval intervals[4];
+ u8 beacon_rssi_skip_max;
+ u8 rssi_delta_threshold;
+ u8 nr;
+ u8 exclude[1];
+} __packed;
+
+#define MC_FILTER_ADDRESS_NUM 4
+
+struct p54_group_address_table {
+ __le16 filter_enable;
+ __le16 num_address;
+ u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
+} __packed;
+
+struct p54_txcancel {
+ __le32 req_id;
+} __packed;
+
+struct p54_sta_unlock {
+ u8 addr[ETH_ALEN];
+ u16 padding;
+} __packed;
+
+#define P54_TIM_CLEAR BIT(15)
+struct p54_tim {
+ u8 count;
+ u8 padding[3];
+ __le16 entry[8];
+} __packed;
+
+struct p54_cce_quiet {
+ __le32 period;
+} __packed;
+
+struct p54_bt_balancer {
+ __le16 prio_thresh;
+ __le16 acl_thresh;
+} __packed;
+
+struct p54_arp_table {
+ __le16 filter_enable;
+ u8 ipv4_addr[4];
+} __packed;
+
+/* LED control */
+int p54_set_leds(struct p54_common *priv);
+int p54_init_leds(struct p54_common *priv);
+void p54_unregister_leds(struct p54_common *priv);
+
+/* xmit functions */
+int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb);
+int p54_tx_cancel(struct p54_common *priv, __le32 req_id);
+void p54_tx(struct p54_common *priv, struct sk_buff *skb);
+
+/* synth/phy configuration */
+int p54_init_xbow_synth(struct p54_common *priv);
+int p54_scan(struct p54_common *priv, u16 mode, u16 dwell);
+
+/* MAC */
+int p54_sta_unlock(struct p54_common *priv, u8 *addr);
+int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set);
+int p54_setup_mac(struct p54_common *priv);
+int p54_set_ps(struct p54_common *priv);
+int p54_fetch_statistics(struct p54_common *priv);
+
+/* e/v DCF setup */
+int p54_set_edcf(struct p54_common *priv);
+
+/* cryptographic engine */
+int p54_upload_key(struct p54_common *priv, u8 algo, int slot,
+ u8 idx, u8 len, u8 *addr, u8* key);
+
+/* eeprom */
+int p54_download_eeprom(struct p54_common *priv, void *buf,
+ u16 offset, u16 len);
+
+/* utility */
+u8 *p54_find_ie(struct sk_buff *skb, u8 ie);
+
+#endif /* LMAC_H */
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
new file mode 100644
index 000000000000..4d486bf9f725
--- /dev/null
+++ b/drivers/net/wireless/p54/main.c
@@ -0,0 +1,648 @@
+/*
+ * mac80211 glue code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Softmac Prism54 common code");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54common");
+
+static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
+ enum sta_notify_cmd notify_cmd,
+ struct ieee80211_sta *sta)
+{
+ struct p54_common *priv = dev->priv;
+ switch (notify_cmd) {
+ case STA_NOTIFY_ADD:
+ case STA_NOTIFY_REMOVE:
+ /*
+ * Notify the firmware that we don't want or we don't
+ * need to buffer frames for this station anymore.
+ */
+
+ p54_sta_unlock(priv, sta->addr);
+ break;
+ case STA_NOTIFY_AWAKE:
+ /* update the firmware's filter table */
+ p54_sta_unlock(priv, sta->addr);
+ break;
+ default:
+ break;
+ }
+}
+
+static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
+ bool set)
+{
+ struct p54_common *priv = dev->priv;
+
+ return p54_update_beacon_tim(priv, sta->aid, set);
+}
+
+u8 *p54_find_ie(struct sk_buff *skb, u8 ie)
+{
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ u8 *pos, *end;
+
+ if (skb->len <= sizeof(mgmt))
+ return NULL;
+
+ pos = (u8 *)mgmt->u.beacon.variable;
+ end = skb->data + skb->len;
+ while (pos < end) {
+ if (pos + 2 + pos[1] > end)
+ return NULL;
+
+ if (pos[0] == ie)
+ return pos;
+
+ pos += 2 + pos[1];
+ }
+ return NULL;
+}
+
+static int p54_beacon_format_ie_tim(struct sk_buff *skb)
+{
+ /*
+ * the good excuse for this mess is ... the firmware.
+ * The dummy TIM MUST be at the end of the beacon frame,
+ * because it'll be overwritten!
+ */
+ u8 *tim;
+ u8 dtim_len;
+ u8 dtim_period;
+ u8 *next;
+
+ tim = p54_find_ie(skb, WLAN_EID_TIM);
+ if (!tim)
+ return 0;
+
+ dtim_len = tim[1];
+ dtim_period = tim[3];
+ next = tim + 2 + dtim_len;
+
+ if (dtim_len < 3)
+ return -EINVAL;
+
+ memmove(tim, next, skb_tail_pointer(skb) - next);
+ tim = skb_tail_pointer(skb) - (dtim_len + 2);
+
+ /* add the dummy at the end */
+ tim[0] = WLAN_EID_TIM;
+ tim[1] = 3;
+ tim[2] = 0;
+ tim[3] = dtim_period;
+ tim[4] = 0;
+
+ if (dtim_len > 3)
+ skb_trim(skb, skb->len - (dtim_len - 3));
+
+ return 0;
+}
+
+static int p54_beacon_update(struct p54_common *priv,
+ struct ieee80211_vif *vif)
+{
+ struct sk_buff *beacon;
+ int ret;
+
+ beacon = ieee80211_beacon_get(priv->hw, vif);
+ if (!beacon)
+ return -ENOMEM;
+ ret = p54_beacon_format_ie_tim(beacon);
+ if (ret)
+ return ret;
+
+ /*
+ * During operation, the firmware takes care of beaconing.
+ * The driver only needs to upload a new beacon template, once
+ * the template was changed by the stack or userspace.
+ *
+ * LMAC API 3.2.2 also specifies that the driver does not need
+ * to cancel the old beacon template by hand, instead the firmware
+ * will release the previous one through the feedback mechanism.
+ */
+ WARN_ON(p54_tx_80211(priv->hw, beacon));
+ priv->tsf_high32 = 0;
+ priv->tsf_low32 = 0;
+
+ return 0;
+}
+
+static int p54_start(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int err;
+
+ mutex_lock(&priv->conf_mutex);
+ err = priv->open(dev);
+ if (err)
+ goto out;
+ P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
+ P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
+ P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
+ P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
+ err = p54_set_edcf(priv);
+ if (err)
+ goto out;
+
+ memset(priv->bssid, ~0, ETH_ALEN);
+ priv->mode = NL80211_IFTYPE_MONITOR;
+ err = p54_setup_mac(priv);
+ if (err) {
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ goto out;
+ }
+
+ ieee80211_queue_delayed_work(dev, &priv->work, 0);
+
+ priv->softled_state = 0;
+ err = p54_set_leds(priv);
+
+out:
+ mutex_unlock(&priv->conf_mutex);
+ return err;
+}
+
+static void p54_stop(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int i;
+
+ mutex_lock(&priv->conf_mutex);
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->softled_state = 0;
+ p54_set_leds(priv);
+
+ cancel_delayed_work_sync(&priv->work);
+
+ priv->stop(dev);
+ skb_queue_purge(&priv->tx_pending);
+ skb_queue_purge(&priv->tx_queue);
+ for (i = 0; i < P54_QUEUE_NUM; i++) {
+ priv->tx_stats[i].count = 0;
+ priv->tx_stats[i].len = 0;
+ }
+
+ priv->beacon_req_id = cpu_to_le32(0);
+ priv->tsf_high32 = priv->tsf_low32 = 0;
+ mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_add_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ if (priv->mode != NL80211_IFTYPE_MONITOR) {
+ mutex_unlock(&priv->conf_mutex);
+ return -EOPNOTSUPP;
+ }
+
+ priv->vif = conf->vif;
+
+ switch (conf->type) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
+ priv->mode = conf->type;
+ break;
+ default:
+ mutex_unlock(&priv->conf_mutex);
+ return -EOPNOTSUPP;
+ }
+
+ memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+ p54_setup_mac(priv);
+ mutex_unlock(&priv->conf_mutex);
+ return 0;
+}
+
+static void p54_remove_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ priv->vif = NULL;
+
+ /*
+ * LMAC API 3.2.2 states that any active beacon template must be
+ * canceled by the driver before attempting a mode transition.
+ */
+ if (le32_to_cpu(priv->beacon_req_id) != 0) {
+ p54_tx_cancel(priv, priv->beacon_req_id);
+ wait_for_completion_interruptible_timeout(&priv->beacon_comp, HZ);
+ }
+ priv->mode = NL80211_IFTYPE_MONITOR;
+ memset(priv->mac_addr, 0, ETH_ALEN);
+ memset(priv->bssid, 0, ETH_ALEN);
+ p54_setup_mac(priv);
+ mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_config(struct ieee80211_hw *dev, u32 changed)
+{
+ int ret = 0;
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_conf *conf = &dev->conf;
+
+ mutex_lock(&priv->conf_mutex);
+ if (changed & IEEE80211_CONF_CHANGE_POWER)
+ priv->output_power = conf->power_level << 2;
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ ret = p54_scan(priv, P54_SCAN_EXIT, 0);
+ if (ret)
+ goto out;
+ }
+ if (changed & IEEE80211_CONF_CHANGE_PS) {
+ ret = p54_set_ps(priv);
+ if (ret)
+ goto out;
+ }
+ if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+ ret = p54_setup_mac(priv);
+ if (ret)
+ goto out;
+ }
+
+out:
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
+}
+
+static void p54_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ u64 multicast)
+{
+ struct p54_common *priv = dev->priv;
+
+ *total_flags &= FIF_PROMISC_IN_BSS |
+ FIF_OTHER_BSS;
+
+ priv->filter_flags = *total_flags;
+
+ if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
+ p54_setup_mac(priv);
+}
+
+static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct p54_common *priv = dev->priv;
+ int ret;
+
+ mutex_lock(&priv->conf_mutex);
+ if (queue < dev->queues) {
+ P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
+ params->cw_min, params->cw_max, params->txop);
+ ret = p54_set_edcf(priv);
+ } else
+ ret = -EINVAL;
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
+}
+
+static void p54_work(struct work_struct *work)
+{
+ struct p54_common *priv = container_of(work, struct p54_common,
+ work.work);
+
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
+
+ /*
+ * TODO: walk through tx_queue and do the following tasks
+ * 1. initiate bursts.
+ * 2. cancel stuck frames / reset the device if necessary.
+ */
+
+ p54_fetch_statistics(priv);
+}
+
+static int p54_get_stats(struct ieee80211_hw *dev,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct p54_common *priv = dev->priv;
+
+ memcpy(stats, &priv->stats, sizeof(*stats));
+ return 0;
+}
+
+static int p54_get_tx_stats(struct ieee80211_hw *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct p54_common *priv = dev->priv;
+
+ memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA],
+ sizeof(stats[0]) * dev->queues);
+ return 0;
+}
+
+static void p54_bss_info_changed(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed)
+{
+ struct p54_common *priv = dev->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ if (changed & BSS_CHANGED_BSSID) {
+ memcpy(priv->bssid, info->bssid, ETH_ALEN);
+ p54_setup_mac(priv);
+ }
+
+ if (changed & BSS_CHANGED_BEACON) {
+ p54_scan(priv, P54_SCAN_EXIT, 0);
+ p54_setup_mac(priv);
+ p54_beacon_update(priv, vif);
+ p54_set_edcf(priv);
+ }
+
+ if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) {
+ priv->use_short_slot = info->use_short_slot;
+ p54_set_edcf(priv);
+ }
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
+ priv->basic_rate_mask = (info->basic_rates << 4);
+ else
+ priv->basic_rate_mask = info->basic_rates;
+ p54_setup_mac(priv);
+ if (priv->fw_var >= 0x500)
+ p54_scan(priv, P54_SCAN_EXIT, 0);
+ }
+ if (changed & BSS_CHANGED_ASSOC) {
+ if (info->assoc) {
+ priv->aid = info->aid;
+ priv->wakeup_timer = info->beacon_int *
+ info->dtim_period * 5;
+ p54_setup_mac(priv);
+ } else {
+ priv->wakeup_timer = 500;
+ priv->aid = 0;
+ }
+ }
+
+ mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct p54_common *priv = dev->priv;
+ int slot, ret = 0;
+ u8 algo = 0;
+ u8 *addr = NULL;
+
+ if (modparam_nohwcrypt)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&priv->conf_mutex);
+ if (cmd == SET_KEY) {
+ switch (key->alg) {
+ case ALG_TKIP:
+ if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
+ BR_DESC_PRIV_CAP_TKIP))) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_TKIPMICHAEL;
+ break;
+ case ALG_WEP:
+ if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_WEP;
+ break;
+ case ALG_CCMP:
+ if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_AESCCMP;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ slot = bitmap_find_free_region(priv->used_rxkeys,
+ priv->rx_keycache_size, 0);
+
+ if (slot < 0) {
+ /*
+ * The device supports the choosen algorithm, but the
+ * firmware does not provide enough key slots to store
+ * all of them.
+ * But encryption offload for outgoing frames is always
+ * possible, so we just pretend that the upload was
+ * successful and do the decryption in software.
+ */
+
+ /* mark the key as invalid. */
+ key->hw_key_idx = 0xff;
+ goto out_unlock;
+ }
+ } else {
+ slot = key->hw_key_idx;
+
+ if (slot == 0xff) {
+ /* This key was not uploaded into the rx key cache. */
+
+ goto out_unlock;
+ }
+
+ bitmap_release_region(priv->used_rxkeys, slot, 0);
+ algo = 0;
+ }
+
+ if (sta)
+ addr = sta->addr;
+
+ ret = p54_upload_key(priv, algo, slot, key->keyidx,
+ key->keylen, addr, key->key);
+ if (ret) {
+ bitmap_release_region(priv->used_rxkeys, slot, 0);
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+
+ key->hw_key_idx = slot;
+
+out_unlock:
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
+}
+
+static const struct ieee80211_ops p54_ops = {
+ .tx = p54_tx_80211,
+ .start = p54_start,
+ .stop = p54_stop,
+ .add_interface = p54_add_interface,
+ .remove_interface = p54_remove_interface,
+ .set_tim = p54_set_tim,
+ .sta_notify = p54_sta_notify,
+ .set_key = p54_set_key,
+ .config = p54_config,
+ .bss_info_changed = p54_bss_info_changed,
+ .configure_filter = p54_configure_filter,
+ .conf_tx = p54_conf_tx,
+ .get_stats = p54_get_stats,
+ .get_tx_stats = p54_get_tx_stats
+};
+
+struct ieee80211_hw *p54_init_common(size_t priv_data_len)
+{
+ struct ieee80211_hw *dev;
+ struct p54_common *priv;
+
+ dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
+ if (!dev)
+ return NULL;
+
+ priv = dev->priv;
+ priv->hw = dev;
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->basic_rate_mask = 0x15f;
+ spin_lock_init(&priv->tx_stats_lock);
+ skb_queue_head_init(&priv->tx_queue);
+ skb_queue_head_init(&priv->tx_pending);
+ dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK |
+ IEEE80211_HW_BEACON_FILTER |
+ IEEE80211_HW_NOISE_DBM;
+
+ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MESH_POINT);
+
+ dev->channel_change_time = 1000; /* TODO: find actual value */
+ priv->beacon_req_id = cpu_to_le32(0);
+ priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
+ priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
+ priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
+ priv->tx_stats[P54_QUEUE_CAB].limit = 3;
+ priv->tx_stats[P54_QUEUE_DATA].limit = 5;
+ dev->queues = 1;
+ priv->noise = -94;
+ /*
+ * We support at most 8 tries no matter which rate they're at,
+ * we cannot support max_rates * max_rate_tries as we set it
+ * here, but setting it correctly to 4/2 or so would limit us
+ * artificially if the RC algorithm wants just two rates, so
+ * let's say 4/7, we'll redistribute it at TX time, see the
+ * comments there.
+ */
+ dev->max_rates = 4;
+ dev->max_rate_tries = 7;
+ dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
+ sizeof(struct p54_tx_data);
+
+ /*
+ * For now, disable PS by default because it affects
+ * link stability significantly.
+ */
+ dev->wiphy->ps_default = false;
+
+ mutex_init(&priv->conf_mutex);
+ mutex_init(&priv->eeprom_mutex);
+ init_completion(&priv->eeprom_comp);
+ init_completion(&priv->beacon_comp);
+ INIT_DELAYED_WORK(&priv->work, p54_work);
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(p54_init_common);
+
+int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
+{
+ struct p54_common *priv = dev->priv;
+ int err;
+
+ err = ieee80211_register_hw(dev);
+ if (err) {
+ dev_err(pdev, "Cannot register device (%d).\n", err);
+ return err;
+ }
+
+#ifdef CONFIG_P54_LEDS
+ err = p54_init_leds(priv);
+ if (err)
+ return err;
+#endif /* CONFIG_P54_LEDS */
+
+ dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy));
+ return 0;
+}
+EXPORT_SYMBOL_GPL(p54_register_common);
+
+void p54_free_common(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ unsigned int i;
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+ kfree(priv->band_table[i]);
+
+ kfree(priv->iq_autocal);
+ kfree(priv->output_limit);
+ kfree(priv->curve_data);
+ kfree(priv->used_rxkeys);
+ priv->iq_autocal = NULL;
+ priv->output_limit = NULL;
+ priv->curve_data = NULL;
+ priv->used_rxkeys = NULL;
+ ieee80211_free_hw(dev);
+}
+EXPORT_SYMBOL_GPL(p54_free_common);
+
+void p54_unregister_common(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+
+#ifdef CONFIG_P54_LEDS
+ p54_unregister_leds(priv);
+#endif /* CONFIG_P54_LEDS */
+
+ ieee80211_unregister_hw(dev);
+ mutex_destroy(&priv->conf_mutex);
+ mutex_destroy(&priv->eeprom_mutex);
+}
+EXPORT_SYMBOL_GPL(p54_unregister_common);
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index db3df947d8ed..1afc39410e85 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -1,6 +1,3 @@
-#ifndef P54_H
-#define P54_H
-
/*
* Shared defines for all mac80211 Prism54 code
*
@@ -14,39 +11,78 @@
* published by the Free Software Foundation.
*/
+#ifndef P54_H
+#define P54_H
+
#ifdef CONFIG_P54_LEDS
#include <linux/leds.h>
#endif /* CONFIG_P54_LEDS */
-enum p54_control_frame_types {
- P54_CONTROL_TYPE_SETUP = 0,
- P54_CONTROL_TYPE_SCAN,
- P54_CONTROL_TYPE_TRAP,
- P54_CONTROL_TYPE_DCFINIT,
- P54_CONTROL_TYPE_RX_KEYCACHE,
- P54_CONTROL_TYPE_TIM,
- P54_CONTROL_TYPE_PSM,
- P54_CONTROL_TYPE_TXCANCEL,
- P54_CONTROL_TYPE_TXDONE,
- P54_CONTROL_TYPE_BURST,
- P54_CONTROL_TYPE_STAT_READBACK,
- P54_CONTROL_TYPE_BBP,
- P54_CONTROL_TYPE_EEPROM_READBACK,
- P54_CONTROL_TYPE_LED,
- P54_CONTROL_TYPE_GPIO,
- P54_CONTROL_TYPE_TIMER,
- P54_CONTROL_TYPE_MODULATION,
- P54_CONTROL_TYPE_SYNTH_CONFIG,
- P54_CONTROL_TYPE_DETECTOR_VALUE,
- P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
- P54_CONTROL_TYPE_CCE_QUIET,
- P54_CONTROL_TYPE_PSM_STA_UNLOCK,
- P54_CONTROL_TYPE_PCS,
- P54_CONTROL_TYPE_BT_BALANCER = 28,
- P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
- P54_CONTROL_TYPE_ARPTABLE = 31,
- P54_CONTROL_TYPE_BT_OPTIONS = 35
-};
+#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
+
+#define BR_CODE_MIN 0x80000000
+#define BR_CODE_COMPONENT_ID 0x80000001
+#define BR_CODE_COMPONENT_VERSION 0x80000002
+#define BR_CODE_DEPENDENT_IF 0x80000003
+#define BR_CODE_EXPOSED_IF 0x80000004
+#define BR_CODE_DESCR 0x80000101
+#define BR_CODE_MAX 0x8FFFFFFF
+#define BR_CODE_END_OF_BRA 0xFF0000FF
+#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
+
+struct bootrec {
+ __le32 code;
+ __le32 len;
+ u32 data[10];
+} __packed;
+
+/* Interface role definitions */
+#define BR_INTERFACE_ROLE_SERVER 0x0000
+#define BR_INTERFACE_ROLE_CLIENT 0x8000
+
+#define BR_DESC_PRIV_CAP_WEP BIT(0)
+#define BR_DESC_PRIV_CAP_TKIP BIT(1)
+#define BR_DESC_PRIV_CAP_MICHAEL BIT(2)
+#define BR_DESC_PRIV_CAP_CCX_CP BIT(3)
+#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4)
+#define BR_DESC_PRIV_CAP_AESCCMP BIT(5)
+
+struct bootrec_desc {
+ __le16 modes;
+ __le16 flags;
+ __le32 rx_start;
+ __le32 rx_end;
+ u8 headroom;
+ u8 tailroom;
+ u8 tx_queues;
+ u8 tx_depth;
+ u8 privacy_caps;
+ u8 rx_keycache_size;
+ u8 time_size;
+ u8 padding;
+ u8 rates[16];
+ u8 padding2[4];
+ __le16 rx_mtu;
+} __packed;
+
+#define FW_FMAC 0x464d4143
+#define FW_LM86 0x4c4d3836
+#define FW_LM87 0x4c4d3837
+#define FW_LM20 0x4c4d3230
+
+struct bootrec_comp_id {
+ __le32 fw_variant;
+} __packed;
+
+struct bootrec_comp_ver {
+ char fw_version[24];
+} __packed;
+
+struct bootrec_end {
+ __le16 crc;
+ u8 padding[2];
+ u8 md5[16];
+} __packed;
/* provide 16 bytes for the transport back-end */
#define P54_TX_INFO_DATA_SIZE 16
@@ -55,34 +91,30 @@ enum p54_control_frame_types {
struct p54_tx_info {
u32 start_addr;
u32 end_addr;
- void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)];
+ union {
+ void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)];
+ struct {
+ u32 extra_len;
+ };
+ };
};
#define P54_MAX_CTRL_FRAME_LEN 0x1000
-#define P54_HDR_FLAG_CONTROL BIT(15)
-#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0))
-
-struct p54_hdr {
- __le16 flags;
- __le16 len;
- __le32 req_id;
- __le16 type; /* enum p54_control_frame_types */
- u8 rts_tries;
- u8 tries;
- u8 data[0];
-} __attribute__ ((packed));
-
-#define FREE_AFTER_TX(skb) \
- ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
- flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \
+do { \
+ queue.aifs = cpu_to_le16(ai_fs); \
+ queue.cwmin = cpu_to_le16(cw_min); \
+ queue.cwmax = cpu_to_le16(cw_max); \
+ queue.txop = cpu_to_le16(_txop); \
+} while (0)
struct p54_edcf_queue_param {
__le16 aifs;
__le16 cwmin;
__le16 cwmax;
__le16 txop;
-} __attribute__ ((packed));
+} __packed;
struct p54_rssi_linear_approximation {
s16 mul;
@@ -101,13 +133,6 @@ struct p54_cal_database {
#define EEPROM_READBACK_LEN 0x3fc
-#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
-
-#define FW_FMAC 0x464d4143
-#define FW_LM86 0x4c4d3836
-#define FW_LM87 0x4c4d3837
-#define FW_LM20 0x4c4d3230
-
enum fw_state {
FW_STATE_OFF,
FW_STATE_BOOTING,
@@ -138,6 +163,7 @@ struct p54_common {
void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb);
int (*open)(struct ieee80211_hw *dev);
void (*stop)(struct ieee80211_hw *dev);
+ struct sk_buff_head tx_pending;
struct sk_buff_head tx_queue;
struct mutex conf_mutex;
@@ -156,6 +182,7 @@ struct p54_common {
/* (e)DCF / QOS state */
bool use_short_slot;
+ spinlock_t tx_stats_lock;
struct ieee80211_tx_queue_stats tx_stats[8];
struct p54_edcf_queue_param qos_params[8];
@@ -171,6 +198,7 @@ struct p54_common {
struct p54_cal_database *curve_data;
struct p54_cal_database *output_limit;
struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS];
+ struct ieee80211_supported_band *band_table[IEEE80211_NUM_BANDS];
/* BBP/MAC state */
u8 mac_addr[ETH_ALEN];
@@ -181,7 +209,9 @@ struct p54_common {
u32 tsf_low32, tsf_high32;
u32 basic_rate_mask;
u16 aid;
- struct sk_buff *cached_beacon;
+ bool powersave_override;
+ __le32 beacon_req_id;
+ struct completion beacon_comp;
/* cryptographic engine information */
u8 privacy_caps;
@@ -202,15 +232,20 @@ struct p54_common {
/* eeprom handling */
void *eeprom;
struct completion eeprom_comp;
+ struct mutex eeprom_mutex;
};
+/* interfaces for the drivers */
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb);
int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
int p54_read_eeprom(struct ieee80211_hw *dev);
+
struct ieee80211_hw *p54_init_common(size_t priv_data_len);
int p54_register_common(struct ieee80211_hw *dev, struct device *pdev);
void p54_free_common(struct ieee80211_hw *dev);
+void p54_unregister_common(struct ieee80211_hw *dev);
+
#endif /* P54_H */
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
deleted file mode 100644
index 22ca122bd798..000000000000
--- a/drivers/net/wireless/p54/p54common.c
+++ /dev/null
@@ -1,2688 +0,0 @@
-/*
- * Common code for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- * - stlc45xx driver
- * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/firmware.h>
-#include <linux/etherdevice.h>
-
-#include <net/mac80211.h>
-#ifdef CONFIG_P54_LEDS
-#include <linux/leds.h>
-#endif /* CONFIG_P54_LEDS */
-
-#include "p54.h"
-#include "p54common.h"
-
-static int modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
-MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
-MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
-MODULE_DESCRIPTION("Softmac Prism54 common code");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("prism54common");
-
-static struct ieee80211_rate p54_bgrates[] = {
- { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 60, .hw_value = 4, },
- { .bitrate = 90, .hw_value = 5, },
- { .bitrate = 120, .hw_value = 6, },
- { .bitrate = 180, .hw_value = 7, },
- { .bitrate = 240, .hw_value = 8, },
- { .bitrate = 360, .hw_value = 9, },
- { .bitrate = 480, .hw_value = 10, },
- { .bitrate = 540, .hw_value = 11, },
-};
-
-static struct ieee80211_channel p54_bgchannels[] = {
- { .center_freq = 2412, .hw_value = 1, },
- { .center_freq = 2417, .hw_value = 2, },
- { .center_freq = 2422, .hw_value = 3, },
- { .center_freq = 2427, .hw_value = 4, },
- { .center_freq = 2432, .hw_value = 5, },
- { .center_freq = 2437, .hw_value = 6, },
- { .center_freq = 2442, .hw_value = 7, },
- { .center_freq = 2447, .hw_value = 8, },
- { .center_freq = 2452, .hw_value = 9, },
- { .center_freq = 2457, .hw_value = 10, },
- { .center_freq = 2462, .hw_value = 11, },
- { .center_freq = 2467, .hw_value = 12, },
- { .center_freq = 2472, .hw_value = 13, },
- { .center_freq = 2484, .hw_value = 14, },
-};
-
-static struct ieee80211_supported_band band_2GHz = {
- .channels = p54_bgchannels,
- .n_channels = ARRAY_SIZE(p54_bgchannels),
- .bitrates = p54_bgrates,
- .n_bitrates = ARRAY_SIZE(p54_bgrates),
-};
-
-static struct ieee80211_rate p54_arates[] = {
- { .bitrate = 60, .hw_value = 4, },
- { .bitrate = 90, .hw_value = 5, },
- { .bitrate = 120, .hw_value = 6, },
- { .bitrate = 180, .hw_value = 7, },
- { .bitrate = 240, .hw_value = 8, },
- { .bitrate = 360, .hw_value = 9, },
- { .bitrate = 480, .hw_value = 10, },
- { .bitrate = 540, .hw_value = 11, },
-};
-
-static struct ieee80211_channel p54_achannels[] = {
- { .center_freq = 4920 },
- { .center_freq = 4940 },
- { .center_freq = 4960 },
- { .center_freq = 4980 },
- { .center_freq = 5040 },
- { .center_freq = 5060 },
- { .center_freq = 5080 },
- { .center_freq = 5170 },
- { .center_freq = 5180 },
- { .center_freq = 5190 },
- { .center_freq = 5200 },
- { .center_freq = 5210 },
- { .center_freq = 5220 },
- { .center_freq = 5230 },
- { .center_freq = 5240 },
- { .center_freq = 5260 },
- { .center_freq = 5280 },
- { .center_freq = 5300 },
- { .center_freq = 5320 },
- { .center_freq = 5500 },
- { .center_freq = 5520 },
- { .center_freq = 5540 },
- { .center_freq = 5560 },
- { .center_freq = 5580 },
- { .center_freq = 5600 },
- { .center_freq = 5620 },
- { .center_freq = 5640 },
- { .center_freq = 5660 },
- { .center_freq = 5680 },
- { .center_freq = 5700 },
- { .center_freq = 5745 },
- { .center_freq = 5765 },
- { .center_freq = 5785 },
- { .center_freq = 5805 },
- { .center_freq = 5825 },
-};
-
-static struct ieee80211_supported_band band_5GHz = {
- .channels = p54_achannels,
- .n_channels = ARRAY_SIZE(p54_achannels),
- .bitrates = p54_arates,
- .n_bitrates = ARRAY_SIZE(p54_arates),
-};
-
-int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
-{
- struct p54_common *priv = dev->priv;
- struct bootrec_exp_if *exp_if;
- struct bootrec *bootrec;
- u32 *data = (u32 *)fw->data;
- u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
- u8 *fw_version = NULL;
- size_t len;
- int i;
- int maxlen;
-
- if (priv->rx_start)
- return 0;
-
- while (data < end_data && *data)
- data++;
-
- while (data < end_data && !*data)
- data++;
-
- bootrec = (struct bootrec *) data;
-
- while (bootrec->data <= end_data &&
- (bootrec->data + (len = le32_to_cpu(bootrec->len))) <= end_data) {
- u32 code = le32_to_cpu(bootrec->code);
- switch (code) {
- case BR_CODE_COMPONENT_ID:
- priv->fw_interface = be32_to_cpup((__be32 *)
- bootrec->data);
- switch (priv->fw_interface) {
- case FW_LM86:
- case FW_LM20:
- case FW_LM87: {
- char *iftype = (char *)bootrec->data;
- printk(KERN_INFO "%s: p54 detected a LM%c%c "
- "firmware\n",
- wiphy_name(dev->wiphy),
- iftype[2], iftype[3]);
- break;
- }
- case FW_FMAC:
- default:
- printk(KERN_ERR "%s: unsupported firmware\n",
- wiphy_name(dev->wiphy));
- return -ENODEV;
- }
- break;
- case BR_CODE_COMPONENT_VERSION:
- /* 24 bytes should be enough for all firmwares */
- if (strnlen((unsigned char*)bootrec->data, 24) < 24)
- fw_version = (unsigned char*)bootrec->data;
- break;
- case BR_CODE_DESCR: {
- struct bootrec_desc *desc =
- (struct bootrec_desc *)bootrec->data;
- priv->rx_start = le32_to_cpu(desc->rx_start);
- /* FIXME add sanity checking */
- priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
- priv->headroom = desc->headroom;
- priv->tailroom = desc->tailroom;
- priv->privacy_caps = desc->privacy_caps;
- priv->rx_keycache_size = desc->rx_keycache_size;
- if (le32_to_cpu(bootrec->len) == 11)
- priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
- else
- priv->rx_mtu = (size_t)
- 0x620 - priv->tx_hdr_len;
- maxlen = priv->tx_hdr_len + /* USB devices */
- sizeof(struct p54_rx_data) +
- 4 + /* rx alignment */
- IEEE80211_MAX_FRAG_THRESHOLD;
- if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
- printk(KERN_INFO "p54: rx_mtu reduced from %d "
- "to %d\n", priv->rx_mtu,
- maxlen);
- priv->rx_mtu = maxlen;
- }
- break;
- }
- case BR_CODE_EXPOSED_IF:
- exp_if = (struct bootrec_exp_if *) bootrec->data;
- for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
- if (exp_if[i].if_id == cpu_to_le16(0x1a))
- priv->fw_var = le16_to_cpu(exp_if[i].variant);
- break;
- case BR_CODE_DEPENDENT_IF:
- break;
- case BR_CODE_END_OF_BRA:
- case LEGACY_BR_CODE_END_OF_BRA:
- end_data = NULL;
- break;
- default:
- break;
- }
- bootrec = (struct bootrec *)&bootrec->data[len];
- }
-
- if (fw_version)
- printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
- wiphy_name(dev->wiphy), fw_version,
- priv->fw_var >> 8, priv->fw_var & 0xff);
-
- if (priv->fw_var < 0x500)
- printk(KERN_INFO "%s: you are using an obsolete firmware. "
- "visit http://wireless.kernel.org/en/users/Drivers/p54 "
- "and grab one for \"kernel >= 2.6.28\"!\n",
- wiphy_name(dev->wiphy));
-
- if (priv->fw_var >= 0x300) {
- /* Firmware supports QoS, use it! */
- priv->tx_stats[P54_QUEUE_AC_VO].limit = 3;
- priv->tx_stats[P54_QUEUE_AC_VI].limit = 4;
- priv->tx_stats[P54_QUEUE_AC_BE].limit = 3;
- priv->tx_stats[P54_QUEUE_AC_BK].limit = 2;
- dev->queues = P54_QUEUE_AC_NUM;
- }
-
- if (!modparam_nohwcrypt) {
- printk(KERN_INFO "%s: cryptographic accelerator "
- "WEP:%s, TKIP:%s, CCMP:%s\n",
- wiphy_name(dev->wiphy),
- (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
- "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
- BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
- (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
- "YES" : "no");
-
- if (priv->rx_keycache_size) {
- /*
- * NOTE:
- *
- * The firmware provides at most 255 (0 - 254) slots
- * for keys which are then used to offload decryption.
- * As a result the 255 entry (aka 0xff) can be used
- * safely by the driver to mark keys that didn't fit
- * into the full cache. This trick saves us from
- * keeping a extra list for uploaded keys.
- */
-
- priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
- priv->rx_keycache_size), GFP_KERNEL);
-
- if (!priv->used_rxkeys)
- return -ENOMEM;
- }
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(p54_parse_firmware);
-
-static int p54_convert_rev0(struct ieee80211_hw *dev,
- struct pda_pa_curve_data *curve_data)
-{
- struct p54_common *priv = dev->priv;
- struct p54_pa_curve_data_sample *dst;
- struct pda_pa_curve_data_sample_rev0 *src;
- size_t cd_len = sizeof(*curve_data) +
- (curve_data->points_per_channel*sizeof(*dst) + 2) *
- curve_data->channels;
- unsigned int i, j;
- void *source, *target;
-
- priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
- GFP_KERNEL);
- if (!priv->curve_data)
- return -ENOMEM;
-
- priv->curve_data->entries = curve_data->channels;
- priv->curve_data->entry_size = sizeof(__le16) +
- sizeof(*dst) * curve_data->points_per_channel;
- priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
- priv->curve_data->len = cd_len;
- memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
- source = curve_data->data;
- target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
- for (i = 0; i < curve_data->channels; i++) {
- __le16 *freq = source;
- source += sizeof(__le16);
- *((__le16 *)target) = *freq;
- target += sizeof(__le16);
- for (j = 0; j < curve_data->points_per_channel; j++) {
- dst = target;
- src = source;
-
- dst->rf_power = src->rf_power;
- dst->pa_detector = src->pa_detector;
- dst->data_64qam = src->pcv;
- /* "invent" the points for the other modulations */
-#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y)
- dst->data_16qam = SUB(src->pcv, 12);
- dst->data_qpsk = SUB(dst->data_16qam, 12);
- dst->data_bpsk = SUB(dst->data_qpsk, 12);
- dst->data_barker = SUB(dst->data_bpsk, 14);
-#undef SUB
- target += sizeof(*dst);
- source += sizeof(*src);
- }
- }
-
- return 0;
-}
-
-static int p54_convert_rev1(struct ieee80211_hw *dev,
- struct pda_pa_curve_data *curve_data)
-{
- struct p54_common *priv = dev->priv;
- struct p54_pa_curve_data_sample *dst;
- struct pda_pa_curve_data_sample_rev1 *src;
- size_t cd_len = sizeof(*curve_data) +
- (curve_data->points_per_channel*sizeof(*dst) + 2) *
- curve_data->channels;
- unsigned int i, j;
- void *source, *target;
-
- priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
- GFP_KERNEL);
- if (!priv->curve_data)
- return -ENOMEM;
-
- priv->curve_data->entries = curve_data->channels;
- priv->curve_data->entry_size = sizeof(__le16) +
- sizeof(*dst) * curve_data->points_per_channel;
- priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
- priv->curve_data->len = cd_len;
- memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
- source = curve_data->data;
- target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
- for (i = 0; i < curve_data->channels; i++) {
- __le16 *freq = source;
- source += sizeof(__le16);
- *((__le16 *)target) = *freq;
- target += sizeof(__le16);
- for (j = 0; j < curve_data->points_per_channel; j++) {
- memcpy(target, source, sizeof(*src));
-
- target += sizeof(*dst);
- source += sizeof(*src);
- }
- source++;
- }
-
- return 0;
-}
-
-static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2",
- "Frisbee", "Xbow", "Longbow", "NULL", "NULL" };
-static int p54_init_xbow_synth(struct ieee80211_hw *dev);
-
-static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
- u16 type)
-{
- struct p54_common *priv = dev->priv;
- int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
- int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
- int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
- int i;
-
- if (len != (entry_size * num_entries)) {
- printk(KERN_ERR "%s: unknown rssi calibration data packing "
- " type:(%x) len:%d.\n",
- wiphy_name(dev->wiphy), type, len);
-
- print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
- data, len);
-
- printk(KERN_ERR "%s: please report this issue.\n",
- wiphy_name(dev->wiphy));
- return;
- }
-
- for (i = 0; i < num_entries; i++) {
- struct pda_rssi_cal_entry *cal = data +
- (offset + i * entry_size);
- priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
- priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
- }
-}
-
-static void p54_parse_default_country(struct ieee80211_hw *dev,
- void *data, int len)
-{
- struct pda_country *country;
-
- if (len != sizeof(*country)) {
- printk(KERN_ERR "%s: found possible invalid default country "
- "eeprom entry. (entry size: %d)\n",
- wiphy_name(dev->wiphy), len);
-
- print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
- data, len);
-
- printk(KERN_ERR "%s: please report this issue.\n",
- wiphy_name(dev->wiphy));
- return;
- }
-
- country = (struct pda_country *) data;
- if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
- regulatory_hint(dev->wiphy, country->alpha2);
- else {
- /* TODO:
- * write a shared/common function that converts
- * "Regulatory domain codes" (802.11-2007 14.8.2.2)
- * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
- */
- }
-}
-
-static int p54_convert_output_limits(struct ieee80211_hw *dev,
- u8 *data, size_t len)
-{
- struct p54_common *priv = dev->priv;
-
- if (len < 2)
- return -EINVAL;
-
- if (data[0] != 0) {
- printk(KERN_ERR "%s: unknown output power db revision:%x\n",
- wiphy_name(dev->wiphy), data[0]);
- return -EINVAL;
- }
-
- if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
- return -EINVAL;
-
- priv->output_limit = kmalloc(data[1] *
- sizeof(struct pda_channel_output_limit) +
- sizeof(*priv->output_limit), GFP_KERNEL);
-
- if (!priv->output_limit)
- return -ENOMEM;
-
- priv->output_limit->offset = 0;
- priv->output_limit->entries = data[1];
- priv->output_limit->entry_size =
- sizeof(struct pda_channel_output_limit);
- priv->output_limit->len = priv->output_limit->entry_size *
- priv->output_limit->entries +
- priv->output_limit->offset;
-
- memcpy(priv->output_limit->data, &data[2],
- data[1] * sizeof(struct pda_channel_output_limit));
-
- return 0;
-}
-
-static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
- size_t total_len)
-{
- struct p54_cal_database *dst;
- size_t payload_len, entries, entry_size, offset;
-
- payload_len = le16_to_cpu(src->len);
- entries = le16_to_cpu(src->entries);
- entry_size = le16_to_cpu(src->entry_size);
- offset = le16_to_cpu(src->offset);
- if (((entries * entry_size + offset) != payload_len) ||
- (payload_len + sizeof(*src) != total_len))
- return NULL;
-
- dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
- if (!dst)
- return NULL;
-
- dst->entries = entries;
- dst->entry_size = entry_size;
- dst->offset = offset;
- dst->len = payload_len;
-
- memcpy(dst->data, src->data, payload_len);
- return dst;
-}
-
-int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
-{
- struct p54_common *priv = dev->priv;
- struct eeprom_pda_wrap *wrap = NULL;
- struct pda_entry *entry;
- unsigned int data_len, entry_len;
- void *tmp;
- int err;
- u8 *end = (u8 *)eeprom + len;
- u16 synth = 0;
-
- wrap = (struct eeprom_pda_wrap *) eeprom;
- entry = (void *)wrap->data + le16_to_cpu(wrap->len);
-
- /* verify that at least the entry length/code fits */
- while ((u8 *)entry <= end - sizeof(*entry)) {
- entry_len = le16_to_cpu(entry->len);
- data_len = ((entry_len - 1) << 1);
-
- /* abort if entry exceeds whole structure */
- if ((u8 *)entry + sizeof(*entry) + data_len > end)
- break;
-
- switch (le16_to_cpu(entry->code)) {
- case PDR_MAC_ADDRESS:
- if (data_len != ETH_ALEN)
- break;
- SET_IEEE80211_PERM_ADDR(dev, entry->data);
- break;
- case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
- if (priv->output_limit)
- break;
- err = p54_convert_output_limits(dev, entry->data,
- data_len);
- if (err)
- goto err;
- break;
- case PDR_PRISM_PA_CAL_CURVE_DATA: {
- struct pda_pa_curve_data *curve_data =
- (struct pda_pa_curve_data *)entry->data;
- if (data_len < sizeof(*curve_data)) {
- err = -EINVAL;
- goto err;
- }
-
- switch (curve_data->cal_method_rev) {
- case 0:
- err = p54_convert_rev0(dev, curve_data);
- break;
- case 1:
- err = p54_convert_rev1(dev, curve_data);
- break;
- default:
- printk(KERN_ERR "%s: unknown curve data "
- "revision %d\n",
- wiphy_name(dev->wiphy),
- curve_data->cal_method_rev);
- err = -ENODEV;
- break;
- }
- if (err)
- goto err;
- }
- break;
- case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
- priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
- if (!priv->iq_autocal) {
- err = -ENOMEM;
- goto err;
- }
-
- memcpy(priv->iq_autocal, entry->data, data_len);
- priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
- break;
- case PDR_DEFAULT_COUNTRY:
- p54_parse_default_country(dev, entry->data, data_len);
- break;
- case PDR_INTERFACE_LIST:
- tmp = entry->data;
- while ((u8 *)tmp < entry->data + data_len) {
- struct bootrec_exp_if *exp_if = tmp;
- if (le16_to_cpu(exp_if->if_id) == 0xf)
- synth = le16_to_cpu(exp_if->variant);
- tmp += sizeof(struct bootrec_exp_if);
- }
- break;
- case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
- if (data_len < 2)
- break;
- priv->version = *(u8 *)(entry->data + 1);
- break;
- case PDR_RSSI_LINEAR_APPROXIMATION:
- case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
- case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
- p54_parse_rssical(dev, entry->data, data_len,
- le16_to_cpu(entry->code));
- break;
- case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: {
- __le16 *src = (void *) entry->data;
- s16 *dst = (void *) &priv->rssical_db;
- int i;
-
- if (data_len != sizeof(priv->rssical_db)) {
- err = -EINVAL;
- goto err;
- }
- for (i = 0; i < sizeof(priv->rssical_db) /
- sizeof(*src); i++)
- *(dst++) = (s16) le16_to_cpu(*(src++));
- }
- break;
- case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
- struct pda_custom_wrapper *pda = (void *) entry->data;
- if (priv->output_limit || data_len < sizeof(*pda))
- break;
- priv->output_limit = p54_convert_db(pda, data_len);
- }
- break;
- case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
- struct pda_custom_wrapper *pda = (void *) entry->data;
- if (priv->curve_data || data_len < sizeof(*pda))
- break;
- priv->curve_data = p54_convert_db(pda, data_len);
- }
- break;
- case PDR_END:
- /* make it overrun */
- entry_len = len;
- break;
- case PDR_MANUFACTURING_PART_NUMBER:
- case PDR_PDA_VERSION:
- case PDR_NIC_SERIAL_NUMBER:
- case PDR_REGULATORY_DOMAIN_LIST:
- case PDR_TEMPERATURE_TYPE:
- case PDR_PRISM_PCI_IDENTIFIER:
- case PDR_COUNTRY_INFORMATION:
- case PDR_OEM_NAME:
- case PDR_PRODUCT_NAME:
- case PDR_UTF8_OEM_NAME:
- case PDR_UTF8_PRODUCT_NAME:
- case PDR_COUNTRY_LIST:
- case PDR_ANTENNA_GAIN:
- case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA:
- case PDR_REGULATORY_POWER_LIMITS:
- case PDR_RADIATED_TRANSMISSION_CORRECTION:
- case PDR_PRISM_TX_IQ_CALIBRATION:
- case PDR_BASEBAND_REGISTERS:
- case PDR_PER_CHANNEL_BASEBAND_REGISTERS:
- break;
- default:
- printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n",
- wiphy_name(dev->wiphy),
- le16_to_cpu(entry->code));
- break;
- }
-
- entry = (void *)entry + (entry_len + 1)*2;
- }
-
- if (!synth || !priv->iq_autocal || !priv->output_limit ||
- !priv->curve_data) {
- printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
- wiphy_name(dev->wiphy));
- err = -EINVAL;
- goto err;
- }
-
- priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
- if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
- p54_init_xbow_synth(dev);
- if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
- dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
- if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
- dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
- if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
- priv->rx_diversity_mask = 3;
- if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
- priv->tx_diversity_mask = 3;
-
- if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
- u8 perm_addr[ETH_ALEN];
-
- printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
- wiphy_name(dev->wiphy));
- random_ether_addr(perm_addr);
- SET_IEEE80211_PERM_ADDR(dev, perm_addr);
- }
-
- printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
- wiphy_name(dev->wiphy),
- dev->wiphy->perm_addr,
- priv->version, p54_rf_chips[priv->rxhw]);
-
- return 0;
-
- err:
- if (priv->iq_autocal) {
- kfree(priv->iq_autocal);
- priv->iq_autocal = NULL;
- }
-
- if (priv->output_limit) {
- kfree(priv->output_limit);
- priv->output_limit = NULL;
- }
-
- if (priv->curve_data) {
- kfree(priv->curve_data);
- priv->curve_data = NULL;
- }
-
- printk(KERN_ERR "%s: eeprom parse failed!\n",
- wiphy_name(dev->wiphy));
- return err;
-}
-EXPORT_SYMBOL_GPL(p54_parse_eeprom);
-
-static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
-{
- struct p54_common *priv = dev->priv;
- int band = dev->conf.channel->band;
-
- if (priv->rxhw != PDR_SYNTH_FRONTEND_LONGBOW)
- return ((rssi * priv->rssical_db[band].mul) / 64 +
- priv->rssical_db[band].add) / 4;
- else
- /*
- * TODO: find the correct formula
- */
- return ((rssi * priv->rssical_db[band].mul) / 64 +
- priv->rssical_db[band].add) / 4;
-}
-
-static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
- struct ieee80211_rx_status rx_status = {0};
- u16 freq = le16_to_cpu(hdr->freq);
- size_t header_len = sizeof(*hdr);
- u32 tsf32;
- u8 rate = hdr->rate & 0xf;
-
- /*
- * If the device is in a unspecified state we have to
- * ignore all data frames. Else we could end up with a
- * nasty crash.
- */
- if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
- return 0;
-
- if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) {
- return 0;
- }
-
- if (hdr->decrypt_status == P54_DECRYPT_OK)
- rx_status.flag |= RX_FLAG_DECRYPTED;
- if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
- (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
- rx_status.flag |= RX_FLAG_MMIC_ERROR;
-
- rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi);
- rx_status.noise = priv->noise;
- if (hdr->rate & 0x10)
- rx_status.flag |= RX_FLAG_SHORTPRE;
- if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
- rx_status.rate_idx = (rate < 4) ? 0 : rate - 4;
- else
- rx_status.rate_idx = rate;
-
- rx_status.freq = freq;
- rx_status.band = dev->conf.channel->band;
- rx_status.antenna = hdr->antenna;
-
- tsf32 = le32_to_cpu(hdr->tsf32);
- if (tsf32 < priv->tsf_low32)
- priv->tsf_high32++;
- rx_status.mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
- priv->tsf_low32 = tsf32;
-
- rx_status.flag |= RX_FLAG_TSFT;
-
- if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
- header_len += hdr->align[0];
-
- skb_pull(skb, header_len);
- skb_trim(skb, le16_to_cpu(hdr->len));
-
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
-
- queue_delayed_work(dev->workqueue, &priv->work,
- msecs_to_jiffies(P54_STATISTICS_UPDATE));
-
- return -1;
-}
-
-static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int i;
-
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
- return ;
-
- for (i = 0; i < dev->queues; i++)
- if (priv->tx_stats[i + P54_QUEUE_DATA].len <
- priv->tx_stats[i + P54_QUEUE_DATA].limit)
- ieee80211_wake_queue(dev, i);
-}
-
-void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct ieee80211_tx_info *info;
- struct p54_tx_info *range;
- unsigned long flags;
-
- if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
- return;
-
- /*
- * don't try to free an already unlinked skb
- */
- if (unlikely((!skb->next) || (!skb->prev)))
- return;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
- info = IEEE80211_SKB_CB(skb);
- range = (void *)info->rate_driver_data;
- if (skb->prev != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *ni;
- struct p54_tx_info *mr;
-
- ni = IEEE80211_SKB_CB(skb->prev);
- mr = (struct p54_tx_info *)ni->rate_driver_data;
- }
- if (skb->next != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *ni;
- struct p54_tx_info *mr;
-
- ni = IEEE80211_SKB_CB(skb->next);
- mr = (struct p54_tx_info *)ni->rate_driver_data;
- }
- __skb_unlink(skb, &priv->tx_queue);
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- dev_kfree_skb_any(skb);
- p54_wake_free_queues(dev);
-}
-EXPORT_SYMBOL_GPL(p54_free_skb);
-
-static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
- __le32 req_id)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *entry;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
- entry = priv->tx_queue.next;
- while (entry != (struct sk_buff *)&priv->tx_queue) {
- struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
-
- if (hdr->req_id == req_id) {
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- return entry;
- }
- entry = entry->next;
- }
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- return NULL;
-}
-
-static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
- struct sk_buff *entry;
- u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom;
- struct p54_tx_info *range = NULL;
- unsigned long flags;
- int count, idx;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
- entry = (struct sk_buff *) priv->tx_queue.next;
- while (entry != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
- struct p54_hdr *entry_hdr;
- struct p54_tx_data *entry_data;
- unsigned int pad = 0, frame_len;
-
- range = (void *)info->rate_driver_data;
- if (range->start_addr != addr) {
- entry = entry->next;
- continue;
- }
-
- if (entry->next != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *ni;
- struct p54_tx_info *mr;
-
- ni = IEEE80211_SKB_CB(entry->next);
- mr = (struct p54_tx_info *)ni->rate_driver_data;
- }
-
- __skb_unlink(entry, &priv->tx_queue);
-
- frame_len = entry->len;
- entry_hdr = (struct p54_hdr *) entry->data;
- entry_data = (struct p54_tx_data *) entry_hdr->data;
- if (priv->tx_stats[entry_data->hw_queue].len)
- priv->tx_stats[entry_data->hw_queue].len--;
- priv->stats.dot11ACKFailureCount += payload->tries - 1;
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
- /*
- * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
- * generated by the driver. Therefore tx_status is bogus
- * and we don't want to confuse the mac80211 stack.
- */
- if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
- if (entry_data->hw_queue == P54_QUEUE_BEACON)
- priv->cached_beacon = NULL;
-
- kfree_skb(entry);
- goto out;
- }
-
- /*
- * Clear manually, ieee80211_tx_info_clear_status would
- * clear the counts too and we need them.
- */
- memset(&info->status.ampdu_ack_len, 0,
- sizeof(struct ieee80211_tx_info) -
- offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
- BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
- status.ampdu_ack_len) != 23);
-
- if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
- pad = entry_data->align[0];
-
- /* walk through the rates array and adjust the counts */
- count = payload->tries;
- for (idx = 0; idx < 4; idx++) {
- if (count >= info->status.rates[idx].count) {
- count -= info->status.rates[idx].count;
- } else if (count > 0) {
- info->status.rates[idx].count = count;
- count = 0;
- } else {
- info->status.rates[idx].idx = -1;
- info->status.rates[idx].count = 0;
- }
- }
-
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
- (!payload->status))
- info->flags |= IEEE80211_TX_STAT_ACK;
- if (payload->status & P54_TX_PSM_CANCELLED)
- info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
- info->status.ack_signal = p54_rssi_to_dbm(dev,
- (int)payload->ack_rssi);
-
- /* Undo all changes to the frame. */
- switch (entry_data->key_type) {
- case P54_CRYPTO_TKIPMICHAEL: {
- u8 *iv = (u8 *)(entry_data->align + pad +
- entry_data->crypt_offset);
-
- /* Restore the original TKIP IV. */
- iv[2] = iv[0];
- iv[0] = iv[1];
- iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */
-
- frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */
- break;
- }
- case P54_CRYPTO_AESCCMP:
- frame_len -= 8; /* remove CCMP_MIC */
- break;
- case P54_CRYPTO_WEP:
- frame_len -= 4; /* remove WEP_ICV */
- break;
- }
- skb_trim(entry, frame_len);
- skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
- ieee80211_tx_status_irqsafe(dev, entry);
- goto out;
- }
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
-out:
- p54_wake_free_queues(dev);
-}
-
-static void p54_rx_eeprom_readback(struct ieee80211_hw *dev,
- struct sk_buff *skb)
-{
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
- struct p54_common *priv = dev->priv;
-
- if (!priv->eeprom)
- return ;
-
- if (priv->fw_var >= 0x509) {
- memcpy(priv->eeprom, eeprom->v2.data,
- le16_to_cpu(eeprom->v2.len));
- } else {
- memcpy(priv->eeprom, eeprom->v1.data,
- le16_to_cpu(eeprom->v1.len));
- }
-
- complete(&priv->eeprom_comp);
-}
-
-static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
- u32 tsf32;
-
- if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
- return ;
-
- tsf32 = le32_to_cpu(stats->tsf32);
- if (tsf32 < priv->tsf_low32)
- priv->tsf_high32++;
- priv->tsf_low32 = tsf32;
-
- priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
- priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
- priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
-
- priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise));
-
- p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id));
-}
-
-static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_trap *trap = (struct p54_trap *) hdr->data;
- u16 event = le16_to_cpu(trap->event);
- u16 freq = le16_to_cpu(trap->frequency);
-
- switch (event) {
- case P54_TRAP_BEACON_TX:
- break;
- case P54_TRAP_RADAR:
- printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
- wiphy_name(dev->wiphy), freq);
- break;
- case P54_TRAP_NO_BEACON:
- if (priv->vif)
- ieee80211_beacon_loss(priv->vif);
- break;
- case P54_TRAP_SCAN:
- break;
- case P54_TRAP_TBTT:
- break;
- case P54_TRAP_TIMER:
- break;
- default:
- printk(KERN_INFO "%s: received event:%x freq:%d\n",
- wiphy_name(dev->wiphy), event, freq);
- break;
- }
-}
-
-static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-
- switch (le16_to_cpu(hdr->type)) {
- case P54_CONTROL_TYPE_TXDONE:
- p54_rx_frame_sent(dev, skb);
- break;
- case P54_CONTROL_TYPE_TRAP:
- p54_rx_trap(dev, skb);
- break;
- case P54_CONTROL_TYPE_BBP:
- break;
- case P54_CONTROL_TYPE_STAT_READBACK:
- p54_rx_stats(dev, skb);
- break;
- case P54_CONTROL_TYPE_EEPROM_READBACK:
- p54_rx_eeprom_readback(dev, skb);
- break;
- default:
- printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
- wiphy_name(dev->wiphy), le16_to_cpu(hdr->type));
- break;
- }
-
- return 0;
-}
-
-/* returns zero if skb can be reused */
-int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- u16 type = le16_to_cpu(*((__le16 *)skb->data));
-
- if (type & P54_HDR_FLAG_CONTROL)
- return p54_rx_control(dev, skb);
- else
- return p54_rx_data(dev, skb);
-}
-EXPORT_SYMBOL_GPL(p54_rx);
-
-/*
- * So, the firmware is somewhat stupid and doesn't know what places in its
- * memory incoming data should go to. By poking around in the firmware, we
- * can find some unused memory to upload our packets to. However, data that we
- * want the card to TX needs to stay intact until the card has told us that
- * it is done with it. This function finds empty places we can upload to and
- * marks allocated areas as reserved if necessary. p54_rx_frame_sent or
- * p54_free_skb frees allocated areas.
- */
-static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct p54_hdr *data, u32 len)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *entry;
- struct sk_buff *target_skb = NULL;
- struct ieee80211_tx_info *info;
- struct p54_tx_info *range;
- u32 last_addr = priv->rx_start;
- u32 largest_hole = 0;
- u32 target_addr = priv->rx_start;
- unsigned long flags;
- unsigned int left;
- len = (len + priv->headroom + priv->tailroom + 3) & ~0x3;
-
- if (!skb)
- return -EINVAL;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
-
- left = skb_queue_len(&priv->tx_queue);
- if (unlikely(left >= 28)) {
- /*
- * The tx_queue is nearly full!
- * We have throttle normal data traffic, because we must
- * have a few spare slots for control frames left.
- */
- ieee80211_stop_queues(dev);
- queue_delayed_work(dev->workqueue, &priv->work,
- msecs_to_jiffies(P54_TX_TIMEOUT));
-
- if (unlikely(left == 32)) {
- /*
- * The tx_queue is now really full.
- *
- * TODO: check if the device has crashed and reset it.
- */
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- return -ENOSPC;
- }
- }
-
- entry = priv->tx_queue.next;
- while (left--) {
- u32 hole_size;
- info = IEEE80211_SKB_CB(entry);
- range = (void *)info->rate_driver_data;
- hole_size = range->start_addr - last_addr;
- if (!target_skb && hole_size >= len) {
- target_skb = entry->prev;
- hole_size -= len;
- target_addr = last_addr;
- }
- largest_hole = max(largest_hole, hole_size);
- last_addr = range->end_addr;
- entry = entry->next;
- }
- if (!target_skb && priv->rx_end - last_addr >= len) {
- target_skb = priv->tx_queue.prev;
- largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
- if (!skb_queue_empty(&priv->tx_queue)) {
- info = IEEE80211_SKB_CB(target_skb);
- range = (void *)info->rate_driver_data;
- target_addr = range->end_addr;
- }
- } else
- largest_hole = max(largest_hole, priv->rx_end - last_addr);
-
- if (!target_skb) {
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- ieee80211_stop_queues(dev);
- return -ENOSPC;
- }
-
- info = IEEE80211_SKB_CB(skb);
- range = (void *)info->rate_driver_data;
- range->start_addr = target_addr;
- range->end_addr = target_addr + len;
- __skb_queue_after(&priv->tx_queue, target_skb, skb);
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
- if (largest_hole < priv->headroom + sizeof(struct p54_hdr) +
- 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
- ieee80211_stop_queues(dev);
-
- data->req_id = cpu_to_le32(target_addr + priv->headroom);
- return 0;
-}
-
-static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, u16 hdr_flags,
- u16 payload_len, u16 type, gfp_t memflags)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr;
- struct sk_buff *skb;
- size_t frame_len = sizeof(*hdr) + payload_len;
-
- if (frame_len > P54_MAX_CTRL_FRAME_LEN)
- return NULL;
-
- skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags);
- if (!skb)
- return NULL;
- skb_reserve(skb, priv->tx_hdr_len);
-
- hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
- hdr->flags = cpu_to_le16(hdr_flags);
- hdr->len = cpu_to_le16(payload_len);
- hdr->type = cpu_to_le16(type);
- hdr->tries = hdr->rts_tries = 0;
-
- if (p54_assign_address(dev, skb, hdr, frame_len)) {
- kfree_skb(skb);
- return NULL;
- }
- return skb;
-}
-
-int p54_read_eeprom(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct p54_eeprom_lm86 *eeprom_hdr;
- struct sk_buff *skb;
- size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
- int ret = -ENOMEM;
- void *eeprom = NULL;
-
- maxblocksize = EEPROM_READBACK_LEN;
- if (priv->fw_var >= 0x509)
- maxblocksize -= 0xc;
- else
- maxblocksize -= 0x4;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*eeprom_hdr) +
- maxblocksize, P54_CONTROL_TYPE_EEPROM_READBACK,
- GFP_KERNEL);
- if (!skb)
- goto free;
- priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL);
- if (!priv->eeprom)
- goto free;
- eeprom = kzalloc(eeprom_size, GFP_KERNEL);
- if (!eeprom)
- goto free;
-
- eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
- sizeof(*eeprom_hdr) + maxblocksize);
-
- while (eeprom_size) {
- blocksize = min(eeprom_size, maxblocksize);
- if (priv->fw_var < 0x509) {
- eeprom_hdr->v1.offset = cpu_to_le16(offset);
- eeprom_hdr->v1.len = cpu_to_le16(blocksize);
- } else {
- eeprom_hdr->v2.offset = cpu_to_le32(offset);
- eeprom_hdr->v2.len = cpu_to_le16(blocksize);
- eeprom_hdr->v2.magic2 = 0xf;
- memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
- }
- priv->tx(dev, skb);
-
- if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
- printk(KERN_ERR "%s: device does not respond!\n",
- wiphy_name(dev->wiphy));
- ret = -EBUSY;
- goto free;
- }
-
- memcpy(eeprom + offset, priv->eeprom, blocksize);
- offset += blocksize;
- eeprom_size -= blocksize;
- }
-
- ret = p54_parse_eeprom(dev, eeprom, offset);
-free:
- kfree(priv->eeprom);
- priv->eeprom = NULL;
- p54_free_skb(dev, skb);
- kfree(eeprom);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(p54_read_eeprom);
-
-static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
- bool set)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_tim *tim;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim),
- P54_CONTROL_TYPE_TIM, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
- tim->count = 1;
- tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_sta_unlock *sta;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta),
- P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
- memcpy(sta->addr, addr, ETH_ALEN);
- priv->tx(dev, skb);
- return 0;
-}
-
-static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
- enum sta_notify_cmd notify_cmd,
- struct ieee80211_sta *sta)
-{
- switch (notify_cmd) {
- case STA_NOTIFY_ADD:
- case STA_NOTIFY_REMOVE:
- /*
- * Notify the firmware that we don't want or we don't
- * need to buffer frames for this station anymore.
- */
-
- p54_sta_unlock(dev, sta->addr);
- break;
- case STA_NOTIFY_AWAKE:
- /* update the firmware's filter table */
- p54_sta_unlock(dev, sta->addr);
- break;
- default:
- break;
- }
-}
-
-static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_hdr *hdr;
- struct p54_txcancel *cancel;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
- P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- hdr = (void *)entry->data;
- cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
- cancel->req_id = hdr->req_id;
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len,
- u16 *flags, u16 *aid)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct p54_common *priv = dev->priv;
- int ret = 1;
-
- switch (priv->mode) {
- case NL80211_IFTYPE_MONITOR:
- /*
- * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for
- * every frame in promiscuous/monitor mode.
- * see STSW45x0C LMAC API - page 12.
- */
- *aid = 0;
- *flags = P54_HDR_FLAG_DATA_OUT_PROMISC;
- *queue += P54_QUEUE_DATA;
- break;
- case NL80211_IFTYPE_STATION:
- *aid = 1;
- if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
- *queue = P54_QUEUE_MGMT;
- ret = 0;
- } else
- *queue += P54_QUEUE_DATA;
- break;
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_MESH_POINT:
- if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
- *aid = 0;
- *queue = P54_QUEUE_CAB;
- return 0;
- }
-
- if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
- if (ieee80211_is_probe_resp(hdr->frame_control)) {
- *aid = 0;
- *queue = P54_QUEUE_MGMT;
- *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
- P54_HDR_FLAG_DATA_OUT_NOCANCEL;
- return 0;
- } else if (ieee80211_is_beacon(hdr->frame_control)) {
- *aid = 0;
-
- if (info->flags & IEEE80211_TX_CTL_INJECTED) {
- /*
- * Injecting beacons on top of a AP is
- * not a good idea... nevertheless,
- * it should be doable.
- */
-
- *queue += P54_QUEUE_DATA;
- return 1;
- }
-
- *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
- *queue = P54_QUEUE_BEACON;
- *extra_len = IEEE80211_MAX_TIM_LEN;
- return 0;
- } else {
- *queue = P54_QUEUE_MGMT;
- ret = 0;
- }
- } else
- *queue += P54_QUEUE_DATA;
-
- if (info->control.sta)
- *aid = info->control.sta->aid;
-
- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
- *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
- break;
- }
- return ret;
-}
-
-static u8 p54_convert_algo(enum ieee80211_key_alg alg)
-{
- switch (alg) {
- case ALG_WEP:
- return P54_CRYPTO_WEP;
- case ALG_TKIP:
- return P54_CRYPTO_TKIPMICHAEL;
- case ALG_CCMP:
- return P54_CRYPTO_AESCCMP;
- default:
- return 0;
- }
-}
-
-static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_tx_queue_stats *current_queue;
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr;
- struct p54_tx_data *txhdr;
- size_t padding, len, tim_len = 0;
- int i, j, ridx, ret;
- u16 hdr_flags = 0, aid = 0;
- u8 rate, queue, crypt_offset = 0;
- u8 cts_rate = 0x20;
- u8 rc_flags;
- u8 calculated_tries[4];
- u8 nrates = 0, nremaining = 8;
-
- queue = skb_get_queue_mapping(skb);
-
- ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid);
- current_queue = &priv->tx_stats[queue];
- if (unlikely((current_queue->len > current_queue->limit) && ret))
- return NETDEV_TX_BUSY;
- current_queue->len++;
- current_queue->count++;
- if ((current_queue->len == current_queue->limit) && ret)
- ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
-
- padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
- len = skb->len;
-
- if (info->control.hw_key) {
- crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
- if (info->control.hw_key->alg == ALG_TKIP) {
- u8 *iv = (u8 *)(skb->data + crypt_offset);
- /*
- * The firmware excepts that the IV has to have
- * this special format
- */
- iv[1] = iv[0];
- iv[0] = iv[2];
- iv[2] = 0;
- }
- }
-
- txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
- hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
-
- if (padding)
- hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
- hdr->type = cpu_to_le16(aid);
- hdr->rts_tries = info->control.rates[0].count;
-
- /*
- * we register the rates in perfect order, and
- * RTS/CTS won't happen on 5 GHz
- */
- cts_rate = info->control.rts_cts_rate_idx;
-
- memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
-
- /* see how many rates got used */
- for (i = 0; i < 4; i++) {
- if (info->control.rates[i].idx < 0)
- break;
- nrates++;
- }
-
- /* limit tries to 8/nrates per rate */
- for (i = 0; i < nrates; i++) {
- /*
- * The magic expression here is equivalent to 8/nrates for
- * all values that matter, but avoids division and jumps.
- * Note that nrates can only take the values 1 through 4.
- */
- calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
- info->control.rates[i].count);
- nremaining -= calculated_tries[i];
- }
-
- /* if there are tries left, distribute from back to front */
- for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
- int tmp = info->control.rates[i].count - calculated_tries[i];
-
- if (tmp <= 0)
- continue;
- /* RC requested more tries at this rate */
-
- tmp = min_t(int, tmp, nremaining);
- calculated_tries[i] += tmp;
- nremaining -= tmp;
- }
-
- ridx = 0;
- for (i = 0; i < nrates && ridx < 8; i++) {
- /* we register the rates in perfect order */
- rate = info->control.rates[i].idx;
- if (info->band == IEEE80211_BAND_5GHZ)
- rate += 4;
-
- /* store the count we actually calculated for TX status */
- info->control.rates[i].count = calculated_tries[i];
-
- rc_flags = info->control.rates[i].flags;
- if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
- rate |= 0x10;
- cts_rate |= 0x10;
- }
- if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
- rate |= 0x40;
- else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
- rate |= 0x20;
- for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
- txhdr->rateset[ridx] = rate;
- ridx++;
- }
- }
-
- if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
- hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
-
- /* TODO: enable bursting */
- hdr->flags = cpu_to_le16(hdr_flags);
- hdr->tries = ridx;
- txhdr->rts_rate_idx = 0;
- if (info->control.hw_key) {
- txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
- txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
- memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
- if (info->control.hw_key->alg == ALG_TKIP) {
- if (unlikely(skb_tailroom(skb) < 12))
- goto err;
- /* reserve space for the MIC key */
- len += 8;
- memcpy(skb_put(skb, 8), &(info->control.hw_key->key
- [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
- }
- /* reserve some space for ICV */
- len += info->control.hw_key->icv_len;
- memset(skb_put(skb, info->control.hw_key->icv_len), 0,
- info->control.hw_key->icv_len);
- } else {
- txhdr->key_type = 0;
- txhdr->key_len = 0;
- }
- txhdr->crypt_offset = crypt_offset;
- txhdr->hw_queue = queue;
- txhdr->backlog = current_queue->len;
- memset(txhdr->durations, 0, sizeof(txhdr->durations));
- txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ?
- 2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask;
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- txhdr->longbow.cts_rate = cts_rate;
- txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
- } else {
- txhdr->normal.output_power = priv->output_power;
- txhdr->normal.cts_rate = cts_rate;
- }
- if (padding)
- txhdr->align[0] = padding;
-
- hdr->len = cpu_to_le16(len);
- /* modifies skb->cb and with it info, so must be last! */
- if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len)))
- goto err;
- priv->tx(dev, skb);
-
- queue_delayed_work(dev->workqueue, &priv->work,
- msecs_to_jiffies(P54_TX_FRAME_LIFETIME));
-
- return NETDEV_TX_OK;
-
- err:
- skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding);
- current_queue->len--;
- current_queue->count--;
- return NETDEV_TX_BUSY;
-}
-
-static int p54_setup_mac(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_setup_mac *setup;
- u16 mode;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
- P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
- if (dev->conf.radio_enabled) {
- switch (priv->mode) {
- case NL80211_IFTYPE_STATION:
- mode = P54_FILTER_TYPE_STATION;
- break;
- case NL80211_IFTYPE_AP:
- mode = P54_FILTER_TYPE_AP;
- break;
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_MESH_POINT:
- mode = P54_FILTER_TYPE_IBSS;
- break;
- case NL80211_IFTYPE_MONITOR:
- mode = P54_FILTER_TYPE_PROMISCUOUS;
- break;
- default:
- mode = P54_FILTER_TYPE_HIBERNATE;
- break;
- }
-
- /*
- * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
- * STSW45X0C LMAC API - page 12
- */
- if (((priv->filter_flags & FIF_PROMISC_IN_BSS) ||
- (priv->filter_flags & FIF_OTHER_BSS)) &&
- (mode != P54_FILTER_TYPE_PROMISCUOUS))
- mode |= P54_FILTER_TYPE_TRANSPARENT;
- } else
- mode = P54_FILTER_TYPE_HIBERNATE;
-
- setup->mac_mode = cpu_to_le16(mode);
- memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
- memcpy(setup->bssid, priv->bssid, ETH_ALEN);
- setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
- setup->rx_align = 0;
- if (priv->fw_var < 0x500) {
- setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- memset(setup->v1.rts_rates, 0, 8);
- setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
- setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
- setup->v1.rxhw = cpu_to_le16(priv->rxhw);
- setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
- setup->v1.unalloc0 = cpu_to_le16(0);
- } else {
- setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
- setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
- setup->v2.rxhw = cpu_to_le16(priv->rxhw);
- setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
- setup->v2.truncate = cpu_to_le16(48896);
- setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- setup->v2.sbss_offset = 0;
- setup->v2.mcast_window = 0;
- setup->v2.rx_rssi_threshold = 0;
- setup->v2.rx_ed_threshold = 0;
- setup->v2.ref_clock = cpu_to_le32(644245094);
- setup->v2.lpf_bandwidth = cpu_to_le16(65535);
- setup->v2.osc_start_delay = cpu_to_le16(65535);
- }
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_hdr *hdr;
- struct p54_scan_head *head;
- struct p54_iq_autocal_entry *iq_autocal;
- union p54_scan_body_union *body;
- struct p54_scan_tail_rate *rate;
- struct pda_rssi_cal_entry *rssi;
- unsigned int i;
- void *entry;
- int band = dev->conf.channel->band;
- __le16 freq = cpu_to_le16(dev->conf.channel->center_freq);
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
- 2 + sizeof(*iq_autocal) + sizeof(*body) +
- sizeof(*rate) + 2 * sizeof(*rssi),
- P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- head = (struct p54_scan_head *) skb_put(skb, sizeof(*head));
- memset(head->scan_params, 0, sizeof(head->scan_params));
- head->mode = cpu_to_le16(mode);
- head->dwell = cpu_to_le16(dwell);
- head->freq = freq;
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- __le16 *pa_power_points = (__le16 *) skb_put(skb, 2);
- *pa_power_points = cpu_to_le16(0x0c);
- }
-
- iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal));
- for (i = 0; i < priv->iq_autocal_len; i++) {
- if (priv->iq_autocal[i].freq != freq)
- continue;
-
- memcpy(iq_autocal, &priv->iq_autocal[i].params,
- sizeof(struct p54_iq_autocal_entry));
- break;
- }
- if (i == priv->iq_autocal_len)
- goto err;
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
- body = (void *) skb_put(skb, sizeof(body->longbow));
- else
- body = (void *) skb_put(skb, sizeof(body->normal));
-
- for (i = 0; i < priv->output_limit->entries; i++) {
- __le16 *entry_freq = (void *) (priv->output_limit->data +
- priv->output_limit->entry_size * i);
-
- if (*entry_freq != freq)
- continue;
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- memcpy(&body->longbow.power_limits,
- (void *) entry_freq + sizeof(__le16),
- priv->output_limit->entry_size);
- } else {
- struct pda_channel_output_limit *limits =
- (void *) entry_freq;
-
- body->normal.val_barker = 0x38;
- body->normal.val_bpsk = body->normal.dup_bpsk =
- limits->val_bpsk;
- body->normal.val_qpsk = body->normal.dup_qpsk =
- limits->val_qpsk;
- body->normal.val_16qam = body->normal.dup_16qam =
- limits->val_16qam;
- body->normal.val_64qam = body->normal.dup_64qam =
- limits->val_64qam;
- }
- break;
- }
- if (i == priv->output_limit->entries)
- goto err;
-
- entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
- for (i = 0; i < priv->curve_data->entries; i++) {
- if (*((__le16 *)entry) != freq) {
- entry += priv->curve_data->entry_size;
- continue;
- }
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- memcpy(&body->longbow.curve_data,
- (void *) entry + sizeof(__le16),
- priv->curve_data->entry_size);
- } else {
- struct p54_scan_body *chan = &body->normal;
- struct pda_pa_curve_data *curve_data =
- (void *) priv->curve_data->data;
-
- entry += sizeof(__le16);
- chan->pa_points_per_curve = 8;
- memset(chan->curve_data, 0, sizeof(*chan->curve_data));
- memcpy(chan->curve_data, entry,
- sizeof(struct p54_pa_curve_data_sample) *
- min((u8)8, curve_data->points_per_channel));
- }
- break;
- }
- if (i == priv->curve_data->entries)
- goto err;
-
- if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
- rate = (void *) skb_put(skb, sizeof(*rate));
- rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- for (i = 0; i < sizeof(rate->rts_rates); i++)
- rate->rts_rates[i] = i;
- }
-
- rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi));
- rssi->mul = cpu_to_le16(priv->rssical_db[band].mul);
- rssi->add = cpu_to_le16(priv->rssical_db[band].add);
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- /* Longbow frontend needs ever more */
- rssi = (void *) skb_put(skb, sizeof(*rssi));
- rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn);
- rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2);
- }
-
- if (priv->fw_var >= 0x509) {
- rate = (void *) skb_put(skb, sizeof(*rate));
- rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- for (i = 0; i < sizeof(rate->rts_rates); i++)
- rate->rts_rates[i] = i;
- }
-
- hdr = (struct p54_hdr *) skb->data;
- hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));
-
- priv->tx(dev, skb);
- return 0;
-
- err:
- printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy));
- p54_free_skb(dev, skb);
- return -EINVAL;
-}
-
-static int p54_set_leds(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_led *led;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led),
- P54_CONTROL_TYPE_LED, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- led = (struct p54_led *) skb_put(skb, sizeof(*led));
- led->flags = cpu_to_le16(0x0003);
- led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
- led->delay[0] = cpu_to_le16(1);
- led->delay[1] = cpu_to_le16(0);
- priv->tx(dev, skb);
- return 0;
-}
-
-#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \
-do { \
- queue.aifs = cpu_to_le16(ai_fs); \
- queue.cwmin = cpu_to_le16(cw_min); \
- queue.cwmax = cpu_to_le16(cw_max); \
- queue.txop = cpu_to_le16(_txop); \
-} while(0)
-
-static int p54_set_edcf(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_edcf *edcf;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),
- P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
- if (priv->use_short_slot) {
- edcf->slottime = 9;
- edcf->sifs = 0x10;
- edcf->eofpad = 0x00;
- } else {
- edcf->slottime = 20;
- edcf->sifs = 0x0a;
- edcf->eofpad = 0x06;
- }
- /* (see prism54/isl_oid.h for further details) */
- edcf->frameburst = cpu_to_le16(0);
- edcf->round_trip_delay = cpu_to_le16(0);
- edcf->flags = 0;
- memset(edcf->mapping, 0, sizeof(edcf->mapping));
- memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_set_ps(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_psm *psm;
- u16 mode;
- int i;
-
- if (dev->conf.flags & IEEE80211_CONF_PS)
- mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
- P54_PSM_CHECKSUM | P54_PSM_MCBC;
- else
- mode = P54_PSM_CAM;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
- P54_CONTROL_TYPE_PSM, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- psm = (struct p54_psm *)skb_put(skb, sizeof(*psm));
- psm->mode = cpu_to_le16(mode);
- psm->aid = cpu_to_le16(priv->aid);
- for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) {
- psm->intervals[i].interval =
- cpu_to_le16(dev->conf.listen_interval);
- psm->intervals[i].periods = cpu_to_le16(1);
- }
-
- psm->beacon_rssi_skip_max = 200;
- psm->rssi_delta_threshold = 0;
- psm->nr = 10;
- psm->exclude[0] = 0;
-
- priv->tx(dev, skb);
-
- return 0;
-}
-
-static int p54_beacon_tim(struct sk_buff *skb)
-{
- /*
- * the good excuse for this mess is ... the firmware.
- * The dummy TIM MUST be at the end of the beacon frame,
- * because it'll be overwritten!
- */
-
- struct ieee80211_mgmt *mgmt = (void *)skb->data;
- u8 *pos, *end;
-
- if (skb->len <= sizeof(mgmt))
- return -EINVAL;
-
- pos = (u8 *)mgmt->u.beacon.variable;
- end = skb->data + skb->len;
- while (pos < end) {
- if (pos + 2 + pos[1] > end)
- return -EINVAL;
-
- if (pos[0] == WLAN_EID_TIM) {
- u8 dtim_len = pos[1];
- u8 dtim_period = pos[3];
- u8 *next = pos + 2 + dtim_len;
-
- if (dtim_len < 3)
- return -EINVAL;
-
- memmove(pos, next, end - next);
-
- if (dtim_len > 3)
- skb_trim(skb, skb->len - (dtim_len - 3));
-
- pos = end - (dtim_len + 2);
-
- /* add the dummy at the end */
- pos[0] = WLAN_EID_TIM;
- pos[1] = 3;
- pos[2] = 0;
- pos[3] = dtim_period;
- pos[4] = 0;
- return 0;
- }
- pos += 2 + pos[1];
- }
- return 0;
-}
-
-static int p54_beacon_update(struct ieee80211_hw *dev,
- struct ieee80211_vif *vif)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *beacon;
- int ret;
-
- if (priv->cached_beacon) {
- p54_tx_cancel(dev, priv->cached_beacon);
- /* wait for the last beacon the be freed */
- msleep(10);
- }
-
- beacon = ieee80211_beacon_get(dev, vif);
- if (!beacon)
- return -ENOMEM;
- ret = p54_beacon_tim(beacon);
- if (ret)
- return ret;
- ret = p54_tx(dev, beacon);
- if (ret)
- return ret;
- priv->cached_beacon = beacon;
- priv->tsf_high32 = 0;
- priv->tsf_low32 = 0;
-
- return 0;
-}
-
-static int p54_start(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int err;
-
- mutex_lock(&priv->conf_mutex);
- err = priv->open(dev);
- if (err)
- goto out;
- P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
- P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
- P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
- P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
- err = p54_set_edcf(dev);
- if (err)
- goto out;
-
- memset(priv->bssid, ~0, ETH_ALEN);
- priv->mode = NL80211_IFTYPE_MONITOR;
- err = p54_setup_mac(dev);
- if (err) {
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
- goto out;
- }
-
- queue_delayed_work(dev->workqueue, &priv->work, 0);
-
- priv->softled_state = 0;
- err = p54_set_leds(dev);
-
-out:
- mutex_unlock(&priv->conf_mutex);
- return err;
-}
-
-static void p54_stop(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
-
- mutex_lock(&priv->conf_mutex);
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
- priv->softled_state = 0;
- p54_set_leds(dev);
-
-#ifdef CONFIG_P54_LEDS
- cancel_delayed_work_sync(&priv->led_work);
-#endif /* CONFIG_P54_LEDS */
- cancel_delayed_work_sync(&priv->work);
- if (priv->cached_beacon)
- p54_tx_cancel(dev, priv->cached_beacon);
-
- priv->stop(dev);
- while ((skb = skb_dequeue(&priv->tx_queue)))
- kfree_skb(skb);
- priv->cached_beacon = NULL;
- priv->tsf_high32 = priv->tsf_low32 = 0;
- mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_add_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
-{
- struct p54_common *priv = dev->priv;
-
- mutex_lock(&priv->conf_mutex);
- if (priv->mode != NL80211_IFTYPE_MONITOR) {
- mutex_unlock(&priv->conf_mutex);
- return -EOPNOTSUPP;
- }
-
- priv->vif = conf->vif;
-
- switch (conf->type) {
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_MESH_POINT:
- priv->mode = conf->type;
- break;
- default:
- mutex_unlock(&priv->conf_mutex);
- return -EOPNOTSUPP;
- }
-
- memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
- p54_setup_mac(dev);
- mutex_unlock(&priv->conf_mutex);
- return 0;
-}
-
-static void p54_remove_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
-{
- struct p54_common *priv = dev->priv;
-
- mutex_lock(&priv->conf_mutex);
- priv->vif = NULL;
- if (priv->cached_beacon)
- p54_tx_cancel(dev, priv->cached_beacon);
- priv->mode = NL80211_IFTYPE_MONITOR;
- memset(priv->mac_addr, 0, ETH_ALEN);
- memset(priv->bssid, 0, ETH_ALEN);
- p54_setup_mac(dev);
- mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_config(struct ieee80211_hw *dev, u32 changed)
-{
- int ret = 0;
- struct p54_common *priv = dev->priv;
- struct ieee80211_conf *conf = &dev->conf;
-
- mutex_lock(&priv->conf_mutex);
- if (changed & IEEE80211_CONF_CHANGE_POWER)
- priv->output_power = conf->power_level << 2;
- if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
- ret = p54_setup_mac(dev);
- if (ret)
- goto out;
- }
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- ret = p54_scan(dev, P54_SCAN_EXIT, 0);
- if (ret)
- goto out;
- }
- if (changed & IEEE80211_CONF_CHANGE_PS) {
- ret = p54_set_ps(dev);
- if (ret)
- goto out;
- }
-
-out:
- mutex_unlock(&priv->conf_mutex);
- return ret;
-}
-
-static void p54_configure_filter(struct ieee80211_hw *dev,
- unsigned int changed_flags,
- unsigned int *total_flags,
- int mc_count, struct dev_mc_list *mclist)
-{
- struct p54_common *priv = dev->priv;
-
- *total_flags &= FIF_PROMISC_IN_BSS |
- FIF_OTHER_BSS;
-
- priv->filter_flags = *total_flags;
-
- if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
- p54_setup_mac(dev);
-}
-
-static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
- const struct ieee80211_tx_queue_params *params)
-{
- struct p54_common *priv = dev->priv;
- int ret;
-
- mutex_lock(&priv->conf_mutex);
- if ((params) && !(queue > 4)) {
- P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
- params->cw_min, params->cw_max, params->txop);
- ret = p54_set_edcf(dev);
- } else
- ret = -EINVAL;
- mutex_unlock(&priv->conf_mutex);
- return ret;
-}
-
-static int p54_init_xbow_synth(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_xbow_synth *xbow;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow),
- P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
-
- xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
- xbow->magic1 = cpu_to_le16(0x1);
- xbow->magic2 = cpu_to_le16(0x2);
- xbow->freq = cpu_to_le16(5390);
- memset(xbow->padding, 0, sizeof(xbow->padding));
- priv->tx(dev, skb);
- return 0;
-}
-
-static void p54_work(struct work_struct *work)
-{
- struct p54_common *priv = container_of(work, struct p54_common,
- work.work);
- struct ieee80211_hw *dev = priv->hw;
- struct sk_buff *skb;
-
- if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
- return ;
-
- /*
- * TODO: walk through tx_queue and do the following tasks
- * 1. initiate bursts.
- * 2. cancel stuck frames / reset the device if necessary.
- */
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL,
- sizeof(struct p54_statistics),
- P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
- if (!skb)
- return ;
-
- priv->tx(dev, skb);
-}
-
-static int p54_get_stats(struct ieee80211_hw *dev,
- struct ieee80211_low_level_stats *stats)
-{
- struct p54_common *priv = dev->priv;
-
- memcpy(stats, &priv->stats, sizeof(*stats));
- return 0;
-}
-
-static int p54_get_tx_stats(struct ieee80211_hw *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct p54_common *priv = dev->priv;
-
- memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA],
- sizeof(stats[0]) * dev->queues);
- return 0;
-}
-
-static void p54_bss_info_changed(struct ieee80211_hw *dev,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info,
- u32 changed)
-{
- struct p54_common *priv = dev->priv;
- int ret;
-
- mutex_lock(&priv->conf_mutex);
- if (changed & BSS_CHANGED_BSSID) {
- memcpy(priv->bssid, info->bssid, ETH_ALEN);
- ret = p54_setup_mac(dev);
- if (ret)
- goto out;
- }
-
- if (changed & BSS_CHANGED_BEACON) {
- ret = p54_scan(dev, P54_SCAN_EXIT, 0);
- if (ret)
- goto out;
- ret = p54_setup_mac(dev);
- if (ret)
- goto out;
- ret = p54_beacon_update(dev, vif);
- if (ret)
- goto out;
- }
- /* XXX: this mimics having two callbacks... clean up */
- out:
- mutex_unlock(&priv->conf_mutex);
-
- if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) {
- priv->use_short_slot = info->use_short_slot;
- p54_set_edcf(dev);
- }
- if (changed & BSS_CHANGED_BASIC_RATES) {
- if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
- priv->basic_rate_mask = (info->basic_rates << 4);
- else
- priv->basic_rate_mask = info->basic_rates;
- p54_setup_mac(dev);
- if (priv->fw_var >= 0x500)
- p54_scan(dev, P54_SCAN_EXIT, 0);
- }
- if (changed & BSS_CHANGED_ASSOC) {
- if (info->assoc) {
- priv->aid = info->aid;
- priv->wakeup_timer = info->beacon_int *
- info->dtim_period * 5;
- p54_setup_mac(dev);
- }
- }
-}
-
-static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_keycache *rxkey;
- int slot, ret = 0;
- u8 algo = 0;
-
- if (modparam_nohwcrypt)
- return -EOPNOTSUPP;
-
- mutex_lock(&priv->conf_mutex);
- if (cmd == SET_KEY) {
- switch (key->alg) {
- case ALG_TKIP:
- if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
- BR_DESC_PRIV_CAP_TKIP))) {
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- algo = P54_CRYPTO_TKIPMICHAEL;
- break;
- case ALG_WEP:
- if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- algo = P54_CRYPTO_WEP;
- break;
- case ALG_CCMP:
- if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- algo = P54_CRYPTO_AESCCMP;
- break;
- default:
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- slot = bitmap_find_free_region(priv->used_rxkeys,
- priv->rx_keycache_size, 0);
-
- if (slot < 0) {
- /*
- * The device supports the choosen algorithm, but the
- * firmware does not provide enough key slots to store
- * all of them.
- * But encryption offload for outgoing frames is always
- * possible, so we just pretend that the upload was
- * successful and do the decryption in software.
- */
-
- /* mark the key as invalid. */
- key->hw_key_idx = 0xff;
- goto out_unlock;
- }
- } else {
- slot = key->hw_key_idx;
-
- if (slot == 0xff) {
- /* This key was not uploaded into the rx key cache. */
-
- goto out_unlock;
- }
-
- bitmap_release_region(priv->used_rxkeys, slot, 0);
- algo = 0;
- }
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
- P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
- if (!skb) {
- bitmap_release_region(priv->used_rxkeys, slot, 0);
- ret = -ENOSPC;
- goto out_unlock;
- }
-
- rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
- rxkey->entry = slot;
- rxkey->key_id = key->keyidx;
- rxkey->key_type = algo;
- if (sta)
- memcpy(rxkey->mac, sta->addr, ETH_ALEN);
- else
- memset(rxkey->mac, ~0, ETH_ALEN);
- if (key->alg != ALG_TKIP) {
- rxkey->key_len = min((u8)16, key->keylen);
- memcpy(rxkey->key, key->key, rxkey->key_len);
- } else {
- rxkey->key_len = 24;
- memcpy(rxkey->key, key->key, 16);
- memcpy(&(rxkey->key[16]), &(key->key
- [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
- }
-
- priv->tx(dev, skb);
- key->hw_key_idx = slot;
-
-out_unlock:
- mutex_unlock(&priv->conf_mutex);
- return ret;
-}
-
-#ifdef CONFIG_P54_LEDS
-static void p54_update_leds(struct work_struct *work)
-{
- struct p54_common *priv = container_of(work, struct p54_common,
- led_work.work);
- int err, i, tmp, blink_delay = 400;
- bool rerun = false;
-
- /* Don't toggle the LED, when the device is down. */
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
- return ;
-
- for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
- if (priv->leds[i].toggled) {
- priv->softled_state |= BIT(i);
-
- tmp = 70 + 200 / (priv->leds[i].toggled);
- if (tmp < blink_delay)
- blink_delay = tmp;
-
- if (priv->leds[i].led_dev.brightness == LED_OFF)
- rerun = true;
-
- priv->leds[i].toggled =
- !!priv->leds[i].led_dev.brightness;
- } else
- priv->softled_state &= ~BIT(i);
-
- err = p54_set_leds(priv->hw);
- if (err && net_ratelimit())
- printk(KERN_ERR "%s: failed to update LEDs.\n",
- wiphy_name(priv->hw->wiphy));
-
- if (rerun)
- queue_delayed_work(priv->hw->workqueue, &priv->led_work,
- msecs_to_jiffies(blink_delay));
-}
-
-static void p54_led_brightness_set(struct led_classdev *led_dev,
- enum led_brightness brightness)
-{
- struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev,
- led_dev);
- struct ieee80211_hw *dev = led->hw_dev;
- struct p54_common *priv = dev->priv;
-
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
- return ;
-
- if (brightness) {
- led->toggled++;
- queue_delayed_work(priv->hw->workqueue, &priv->led_work,
- HZ/10);
- }
-}
-
-static int p54_register_led(struct ieee80211_hw *dev,
- unsigned int led_index,
- char *name, char *trigger)
-{
- struct p54_common *priv = dev->priv;
- struct p54_led_dev *led = &priv->leds[led_index];
- int err;
-
- if (led->registered)
- return -EEXIST;
-
- snprintf(led->name, sizeof(led->name), "p54-%s::%s",
- wiphy_name(dev->wiphy), name);
- led->hw_dev = dev;
- led->index = led_index;
- led->led_dev.name = led->name;
- led->led_dev.default_trigger = trigger;
- led->led_dev.brightness_set = p54_led_brightness_set;
-
- err = led_classdev_register(wiphy_dev(dev->wiphy), &led->led_dev);
- if (err)
- printk(KERN_ERR "%s: Failed to register %s LED.\n",
- wiphy_name(dev->wiphy), name);
- else
- led->registered = 1;
-
- return err;
-}
-
-static int p54_init_leds(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int err;
-
- /*
- * TODO:
- * Figure out if the EEPROM contains some hints about the number
- * of available/programmable LEDs of the device.
- */
-
- INIT_DELAYED_WORK(&priv->led_work, p54_update_leds);
-
- err = p54_register_led(dev, 0, "assoc",
- ieee80211_get_assoc_led_name(dev));
- if (err)
- return err;
-
- err = p54_register_led(dev, 1, "tx",
- ieee80211_get_tx_led_name(dev));
- if (err)
- return err;
-
- err = p54_register_led(dev, 2, "rx",
- ieee80211_get_rx_led_name(dev));
- if (err)
- return err;
-
- err = p54_register_led(dev, 3, "radio",
- ieee80211_get_radio_led_name(dev));
- if (err)
- return err;
-
- err = p54_set_leds(dev);
- return err;
-}
-
-static void p54_unregister_leds(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
- if (priv->leds[i].registered)
- led_classdev_unregister(&priv->leds[i].led_dev);
-}
-#endif /* CONFIG_P54_LEDS */
-
-static const struct ieee80211_ops p54_ops = {
- .tx = p54_tx,
- .start = p54_start,
- .stop = p54_stop,
- .add_interface = p54_add_interface,
- .remove_interface = p54_remove_interface,
- .set_tim = p54_set_tim,
- .sta_notify = p54_sta_notify,
- .set_key = p54_set_key,
- .config = p54_config,
- .bss_info_changed = p54_bss_info_changed,
- .configure_filter = p54_configure_filter,
- .conf_tx = p54_conf_tx,
- .get_stats = p54_get_stats,
- .get_tx_stats = p54_get_tx_stats
-};
-
-struct ieee80211_hw *p54_init_common(size_t priv_data_len)
-{
- struct ieee80211_hw *dev;
- struct p54_common *priv;
-
- dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
- if (!dev)
- return NULL;
-
- priv = dev->priv;
- priv->hw = dev;
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
- priv->basic_rate_mask = 0x15f;
- skb_queue_head_init(&priv->tx_queue);
- dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_NOISE_DBM;
-
- dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_MESH_POINT);
-
- dev->channel_change_time = 1000; /* TODO: find actual value */
- priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
- priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
- priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
- priv->tx_stats[P54_QUEUE_CAB].limit = 3;
- priv->tx_stats[P54_QUEUE_DATA].limit = 5;
- dev->queues = 1;
- priv->noise = -94;
- /*
- * We support at most 8 tries no matter which rate they're at,
- * we cannot support max_rates * max_rate_tries as we set it
- * here, but setting it correctly to 4/2 or so would limit us
- * artificially if the RC algorithm wants just two rates, so
- * let's say 4/7, we'll redistribute it at TX time, see the
- * comments there.
- */
- dev->max_rates = 4;
- dev->max_rate_tries = 7;
- dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
- sizeof(struct p54_tx_data);
-
- mutex_init(&priv->conf_mutex);
- init_completion(&priv->eeprom_comp);
- INIT_DELAYED_WORK(&priv->work, p54_work);
-
- return dev;
-}
-EXPORT_SYMBOL_GPL(p54_init_common);
-
-int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
-{
- int err;
-
- err = ieee80211_register_hw(dev);
- if (err) {
- dev_err(pdev, "Cannot register device (%d).\n", err);
- return err;
- }
-
-#ifdef CONFIG_P54_LEDS
- err = p54_init_leds(dev);
- if (err)
- return err;
-#endif /* CONFIG_P54_LEDS */
-
- dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy));
- return 0;
-}
-EXPORT_SYMBOL_GPL(p54_register_common);
-
-void p54_free_common(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- kfree(priv->iq_autocal);
- kfree(priv->output_limit);
- kfree(priv->curve_data);
- kfree(priv->used_rxkeys);
-
-#ifdef CONFIG_P54_LEDS
- p54_unregister_leds(dev);
-#endif /* CONFIG_P54_LEDS */
-}
-EXPORT_SYMBOL_GPL(p54_free_common);
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
deleted file mode 100644
index 75ead7a150fc..000000000000
--- a/drivers/net/wireless/p54/p54common.h
+++ /dev/null
@@ -1,644 +0,0 @@
-#ifndef P54COMMON_H
-#define P54COMMON_H
-
-/*
- * Common code specific definitions for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
- * Copyright (C) 2007 Conexant Systems, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-struct bootrec {
- __le32 code;
- __le32 len;
- u32 data[10];
-} __attribute__((packed));
-
-#define PDR_SYNTH_FRONTEND_MASK 0x0007
-#define PDR_SYNTH_FRONTEND_DUETTE3 0x0001
-#define PDR_SYNTH_FRONTEND_DUETTE2 0x0002
-#define PDR_SYNTH_FRONTEND_FRISBEE 0x0003
-#define PDR_SYNTH_FRONTEND_XBOW 0x0004
-#define PDR_SYNTH_FRONTEND_LONGBOW 0x0005
-#define PDR_SYNTH_IQ_CAL_MASK 0x0018
-#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000
-#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008
-#define PDR_SYNTH_IQ_CAL_ZIF 0x0010
-#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020
-#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0020
-#define PDR_SYNTH_24_GHZ_MASK 0x0040
-#define PDR_SYNTH_24_GHZ_DISABLED 0x0040
-#define PDR_SYNTH_5_GHZ_MASK 0x0080
-#define PDR_SYNTH_5_GHZ_DISABLED 0x0080
-#define PDR_SYNTH_RX_DIV_MASK 0x0100
-#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100
-#define PDR_SYNTH_TX_DIV_MASK 0x0200
-#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200
-
-struct bootrec_exp_if {
- __le16 role;
- __le16 if_id;
- __le16 variant;
- __le16 btm_compat;
- __le16 top_compat;
-} __attribute__((packed));
-
-#define BR_DESC_PRIV_CAP_WEP BIT(0)
-#define BR_DESC_PRIV_CAP_TKIP BIT(1)
-#define BR_DESC_PRIV_CAP_MICHAEL BIT(2)
-#define BR_DESC_PRIV_CAP_CCX_CP BIT(3)
-#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4)
-#define BR_DESC_PRIV_CAP_AESCCMP BIT(5)
-
-struct bootrec_desc {
- __le16 modes;
- __le16 flags;
- __le32 rx_start;
- __le32 rx_end;
- u8 headroom;
- u8 tailroom;
- u8 tx_queues;
- u8 tx_depth;
- u8 privacy_caps;
- u8 rx_keycache_size;
- u8 time_size;
- u8 padding;
- u8 rates[16];
- u8 padding2[4];
- __le16 rx_mtu;
-} __attribute__((packed));
-
-#define BR_CODE_MIN 0x80000000
-#define BR_CODE_COMPONENT_ID 0x80000001
-#define BR_CODE_COMPONENT_VERSION 0x80000002
-#define BR_CODE_DEPENDENT_IF 0x80000003
-#define BR_CODE_EXPOSED_IF 0x80000004
-#define BR_CODE_DESCR 0x80000101
-#define BR_CODE_MAX 0x8FFFFFFF
-#define BR_CODE_END_OF_BRA 0xFF0000FF
-#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
-
-#define P54_HDR_FLAG_DATA_ALIGN BIT(14)
-#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0)
-#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
-#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2)
-#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3)
-#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4)
-#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5)
-#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6)
-#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7)
-#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8)
-#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9)
-#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10)
-#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11)
-
-#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0)
-#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1)
-#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2)
-#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3)
-#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4)
-#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5)
-#define P54_HDR_FLAG_DATA_IN_DATA BIT(6)
-#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7)
-#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8)
-#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9)
-
-/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
-
-struct pda_entry {
- __le16 len; /* includes both code and data */
- __le16 code;
- u8 data[0];
-} __attribute__ ((packed));
-
-struct eeprom_pda_wrap {
- __le32 magic;
- __le16 pad;
- __le16 len;
- __le32 arm_opcode;
- u8 data[0];
-} __attribute__ ((packed));
-
-struct p54_iq_autocal_entry {
- __le16 iq_param[4];
-} __attribute__ ((packed));
-
-struct pda_iq_autocal_entry {
- __le16 freq;
- struct p54_iq_autocal_entry params;
-} __attribute__ ((packed));
-
-struct pda_channel_output_limit {
- __le16 freq;
- u8 val_bpsk;
- u8 val_qpsk;
- u8 val_16qam;
- u8 val_64qam;
- u8 rate_set_mask;
- u8 rate_set_size;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data_sample_rev0 {
- u8 rf_power;
- u8 pa_detector;
- u8 pcv;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data_sample_rev1 {
- u8 rf_power;
- u8 pa_detector;
- u8 data_barker;
- u8 data_bpsk;
- u8 data_qpsk;
- u8 data_16qam;
- u8 data_64qam;
-} __attribute__ ((packed));
-
-struct p54_pa_curve_data_sample {
- u8 rf_power;
- u8 pa_detector;
- u8 data_barker;
- u8 data_bpsk;
- u8 data_qpsk;
- u8 data_16qam;
- u8 data_64qam;
- u8 padding;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data {
- u8 cal_method_rev;
- u8 channels;
- u8 points_per_channel;
- u8 padding;
- u8 data[0];
-} __attribute__ ((packed));
-
-struct pda_rssi_cal_entry {
- __le16 mul;
- __le16 add;
-} __attribute__ ((packed));
-
-struct pda_country {
- u8 regdomain;
- u8 alpha2[2];
- u8 flags;
-} __attribute__ ((packed));
-
-/*
- * Warning: Longbow's structures are bogus.
- */
-struct p54_channel_output_limit_longbow {
- __le16 rf_power_points[12];
-} __attribute__ ((packed));
-
-struct p54_pa_curve_data_sample_longbow {
- __le16 rf_power;
- __le16 pa_detector;
- struct {
- __le16 data[4];
- } points[3] __attribute__ ((packed));
-} __attribute__ ((packed));
-
-struct pda_custom_wrapper {
- __le16 entries;
- __le16 entry_size;
- __le16 offset;
- __le16 len;
- u8 data[0];
-} __attribute__ ((packed));
-
-/*
- * this defines the PDR codes used to build PDAs as defined in document
- * number 553155. The current implementation mirrors version 1.1 of the
- * document and lists only PDRs supported by the ARM platform.
- */
-
-/* common and choice range (0x0000 - 0x0fff) */
-#define PDR_END 0x0000
-#define PDR_MANUFACTURING_PART_NUMBER 0x0001
-#define PDR_PDA_VERSION 0x0002
-#define PDR_NIC_SERIAL_NUMBER 0x0003
-
-#define PDR_MAC_ADDRESS 0x0101
-#define PDR_REGULATORY_DOMAIN_LIST 0x0103
-#define PDR_TEMPERATURE_TYPE 0x0107
-
-#define PDR_PRISM_PCI_IDENTIFIER 0x0402
-
-/* ARM range (0x1000 - 0x1fff) */
-#define PDR_COUNTRY_INFORMATION 0x1000
-#define PDR_INTERFACE_LIST 0x1001
-#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002
-#define PDR_OEM_NAME 0x1003
-#define PDR_PRODUCT_NAME 0x1004
-#define PDR_UTF8_OEM_NAME 0x1005
-#define PDR_UTF8_PRODUCT_NAME 0x1006
-#define PDR_COUNTRY_LIST 0x1007
-#define PDR_DEFAULT_COUNTRY 0x1008
-
-#define PDR_ANTENNA_GAIN 0x1100
-
-#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901
-#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902
-#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903
-#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904
-#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905
-#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906
-#define PDR_REGULATORY_POWER_LIMITS 0x1907
-#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
-#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909
-#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a
-
-/* reserved range (0x2000 - 0x7fff) */
-
-/* customer range (0x8000 - 0xffff) */
-#define PDR_BASEBAND_REGISTERS 0x8000
-#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001
-
-/* used by our modificated eeprom image */
-#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM 0xDEAD
-#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM 0xBEEF
-#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM 0xB05D
-
-/* PDR definitions for default country & country list */
-#define PDR_COUNTRY_CERT_CODE 0x80
-#define PDR_COUNTRY_CERT_CODE_REAL 0x00
-#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80
-#define PDR_COUNTRY_CERT_BAND 0x40
-#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00
-#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40
-#define PDR_COUNTRY_CERT_IODOOR 0x30
-#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00
-#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
-#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30
-#define PDR_COUNTRY_CERT_INDEX 0x0F
-
-struct p54_eeprom_lm86 {
- union {
- struct {
- __le16 offset;
- __le16 len;
- u8 data[0];
- } v1;
- struct {
- __le32 offset;
- __le16 len;
- u8 magic2;
- u8 pad;
- u8 magic[4];
- u8 data[0];
- } v2;
- } __attribute__ ((packed));
-} __attribute__ ((packed));
-
-enum p54_rx_decrypt_status {
- P54_DECRYPT_NONE = 0,
- P54_DECRYPT_OK,
- P54_DECRYPT_NOKEY,
- P54_DECRYPT_NOMICHAEL,
- P54_DECRYPT_NOCKIPMIC,
- P54_DECRYPT_FAIL_WEP,
- P54_DECRYPT_FAIL_TKIP,
- P54_DECRYPT_FAIL_MICHAEL,
- P54_DECRYPT_FAIL_CKIPKP,
- P54_DECRYPT_FAIL_CKIPMIC,
- P54_DECRYPT_FAIL_AESCCMP
-};
-
-struct p54_rx_data {
- __le16 flags;
- __le16 len;
- __le16 freq;
- u8 antenna;
- u8 rate;
- u8 rssi;
- u8 quality;
- u8 decrypt_status;
- u8 rssi_raw;
- __le32 tsf32;
- __le32 unalloc0;
- u8 align[0];
-} __attribute__ ((packed));
-
-enum p54_trap_type {
- P54_TRAP_SCAN = 0,
- P54_TRAP_TIMER,
- P54_TRAP_BEACON_TX,
- P54_TRAP_FAA_RADIO_ON,
- P54_TRAP_FAA_RADIO_OFF,
- P54_TRAP_RADAR,
- P54_TRAP_NO_BEACON,
- P54_TRAP_TBTT,
- P54_TRAP_SCO_ENTER,
- P54_TRAP_SCO_EXIT
-};
-
-struct p54_trap {
- __le16 event;
- __le16 frequency;
-} __attribute__ ((packed));
-
-enum p54_frame_sent_status {
- P54_TX_OK = 0,
- P54_TX_FAILED,
- P54_TX_PSM,
- P54_TX_PSM_CANCELLED = 4
-};
-
-struct p54_frame_sent {
- u8 status;
- u8 tries;
- u8 ack_rssi;
- u8 quality;
- __le16 seq;
- u8 antenna;
- u8 padding;
-} __attribute__ ((packed));
-
-enum p54_tx_data_crypt {
- P54_CRYPTO_NONE = 0,
- P54_CRYPTO_WEP,
- P54_CRYPTO_TKIP,
- P54_CRYPTO_TKIPMICHAEL,
- P54_CRYPTO_CCX_WEPMIC,
- P54_CRYPTO_CCX_KPMIC,
- P54_CRYPTO_CCX_KP,
- P54_CRYPTO_AESCCMP
-};
-
-enum p54_tx_data_queue {
- P54_QUEUE_BEACON = 0,
- P54_QUEUE_FWSCAN = 1,
- P54_QUEUE_MGMT = 2,
- P54_QUEUE_CAB = 3,
- P54_QUEUE_DATA = 4,
-
- P54_QUEUE_AC_NUM = 4,
- P54_QUEUE_AC_VO = 4,
- P54_QUEUE_AC_VI = 5,
- P54_QUEUE_AC_BE = 6,
- P54_QUEUE_AC_BK = 7,
-
- /* keep last */
- P54_QUEUE_NUM = 8,
-};
-
-struct p54_tx_data {
- u8 rateset[8];
- u8 rts_rate_idx;
- u8 crypt_offset;
- u8 key_type;
- u8 key_len;
- u8 key[16];
- u8 hw_queue;
- u8 backlog;
- __le16 durations[4];
- u8 tx_antenna;
- union {
- struct {
- u8 cts_rate;
- __le16 output_power;
- } __attribute__((packed)) longbow;
- struct {
- u8 output_power;
- u8 cts_rate;
- u8 unalloc;
- } __attribute__ ((packed)) normal;
- } __attribute__ ((packed));
- u8 unalloc2[2];
- u8 align[0];
-} __attribute__ ((packed));
-
-/* unit is ms */
-#define P54_TX_FRAME_LIFETIME 2000
-#define P54_TX_TIMEOUT 4000
-#define P54_STATISTICS_UPDATE 5000
-
-#define P54_FILTER_TYPE_NONE 0
-#define P54_FILTER_TYPE_STATION BIT(0)
-#define P54_FILTER_TYPE_IBSS BIT(1)
-#define P54_FILTER_TYPE_AP BIT(2)
-#define P54_FILTER_TYPE_TRANSPARENT BIT(3)
-#define P54_FILTER_TYPE_PROMISCUOUS BIT(4)
-#define P54_FILTER_TYPE_HIBERNATE BIT(5)
-#define P54_FILTER_TYPE_NOACK BIT(6)
-#define P54_FILTER_TYPE_RX_DISABLED BIT(7)
-
-struct p54_setup_mac {
- __le16 mac_mode;
- u8 mac_addr[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- u8 rx_antenna;
- u8 rx_align;
- union {
- struct {
- __le32 basic_rate_mask;
- u8 rts_rates[8];
- __le32 rx_addr;
- __le16 max_rx;
- __le16 rxhw;
- __le16 wakeup_timer;
- __le16 unalloc0;
- } v1 __attribute__ ((packed));
- struct {
- __le32 rx_addr;
- __le16 max_rx;
- __le16 rxhw;
- __le16 timer;
- __le16 truncate;
- __le32 basic_rate_mask;
- u8 sbss_offset;
- u8 mcast_window;
- u8 rx_rssi_threshold;
- u8 rx_ed_threshold;
- __le32 ref_clock;
- __le16 lpf_bandwidth;
- __le16 osc_start_delay;
- } v2 __attribute__ ((packed));
- } __attribute__ ((packed));
-} __attribute__ ((packed));
-
-#define P54_SETUP_V1_LEN 40
-#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
-
-#define P54_SCAN_EXIT BIT(0)
-#define P54_SCAN_TRAP BIT(1)
-#define P54_SCAN_ACTIVE BIT(2)
-#define P54_SCAN_FILTER BIT(3)
-
-struct p54_scan_head {
- __le16 mode;
- __le16 dwell;
- u8 scan_params[20];
- __le16 freq;
-} __attribute__ ((packed));
-
-struct p54_scan_body {
- u8 pa_points_per_curve;
- u8 val_barker;
- u8 val_bpsk;
- u8 val_qpsk;
- u8 val_16qam;
- u8 val_64qam;
- struct p54_pa_curve_data_sample curve_data[8];
- u8 dup_bpsk;
- u8 dup_qpsk;
- u8 dup_16qam;
- u8 dup_64qam;
-} __attribute__ ((packed));
-
-struct p54_scan_body_longbow {
- struct p54_channel_output_limit_longbow power_limits;
- struct p54_pa_curve_data_sample_longbow curve_data[8];
- __le16 unkn[6]; /* maybe more power_limits or rate_mask */
-} __attribute__ ((packed));
-
-union p54_scan_body_union {
- struct p54_scan_body normal;
- struct p54_scan_body_longbow longbow;
-} __attribute__ ((packed));
-
-struct p54_scan_tail_rate {
- __le32 basic_rate_mask;
- u8 rts_rates[8];
-} __attribute__ ((packed));
-
-struct p54_led {
- __le16 flags;
- __le16 mask[2];
- __le16 delay[2];
-} __attribute__ ((packed));
-
-struct p54_edcf {
- u8 flags;
- u8 slottime;
- u8 sifs;
- u8 eofpad;
- struct p54_edcf_queue_param queue[8];
- u8 mapping[4];
- __le16 frameburst;
- __le16 round_trip_delay;
-} __attribute__ ((packed));
-
-struct p54_statistics {
- __le32 rx_success;
- __le32 rx_bad_fcs;
- __le32 rx_abort;
- __le32 rx_abort_phy;
- __le32 rts_success;
- __le32 rts_fail;
- __le32 tsf32;
- __le32 airtime;
- __le32 noise;
- __le32 sample_noise[8];
- __le32 sample_cca;
- __le32 sample_tx;
-} __attribute__ ((packed));
-
-struct p54_xbow_synth {
- __le16 magic1;
- __le16 magic2;
- __le16 freq;
- u32 padding[5];
-} __attribute__ ((packed));
-
-struct p54_timer {
- __le32 interval;
-} __attribute__ ((packed));
-
-struct p54_keycache {
- u8 entry;
- u8 key_id;
- u8 mac[ETH_ALEN];
- u8 padding[2];
- u8 key_type;
- u8 key_len;
- u8 key[24];
-} __attribute__ ((packed));
-
-struct p54_burst {
- u8 flags;
- u8 queue;
- u8 backlog;
- u8 pad;
- __le16 durations[32];
-} __attribute__ ((packed));
-
-struct p54_psm_interval {
- __le16 interval;
- __le16 periods;
-} __attribute__ ((packed));
-
-#define P54_PSM_CAM 0
-#define P54_PSM BIT(0)
-#define P54_PSM_DTIM BIT(1)
-#define P54_PSM_MCBC BIT(2)
-#define P54_PSM_CHECKSUM BIT(3)
-#define P54_PSM_SKIP_MORE_DATA BIT(4)
-#define P54_PSM_BEACON_TIMEOUT BIT(5)
-#define P54_PSM_HFOSLEEP BIT(6)
-#define P54_PSM_AUTOSWITCH_SLEEP BIT(7)
-#define P54_PSM_LPIT BIT(8)
-#define P54_PSM_BF_UCAST_SKIP BIT(9)
-#define P54_PSM_BF_MCAST_SKIP BIT(10)
-
-struct p54_psm {
- __le16 mode;
- __le16 aid;
- struct p54_psm_interval intervals[4];
- u8 beacon_rssi_skip_max;
- u8 rssi_delta_threshold;
- u8 nr;
- u8 exclude[1];
-} __attribute__ ((packed));
-
-#define MC_FILTER_ADDRESS_NUM 4
-
-struct p54_group_address_table {
- __le16 filter_enable;
- __le16 num_address;
- u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
-} __attribute__ ((packed));
-
-struct p54_txcancel {
- __le32 req_id;
-} __attribute__ ((packed));
-
-struct p54_sta_unlock {
- u8 addr[ETH_ALEN];
- u16 padding;
-} __attribute__ ((packed));
-
-#define P54_TIM_CLEAR BIT(15)
-struct p54_tim {
- u8 count;
- u8 padding[3];
- __le16 entry[8];
-} __attribute__ ((packed));
-
-struct p54_cce_quiet {
- __le32 period;
-} __attribute__ ((packed));
-
-struct p54_bt_balancer {
- __le16 prio_thresh;
- __le16 acl_thresh;
-} __attribute__ ((packed));
-
-struct p54_arp_table {
- __le16 filter_enable;
- u8 ipv4_addr[4];
-} __attribute__ ((packed));
-
-#endif /* P54COMMON_H */
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index b1610ea4bb3d..d348c265e867 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -22,6 +22,7 @@
#include <net/mac80211.h>
#include "p54.h"
+#include "lmac.h"
#include "p54pci.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
@@ -564,7 +565,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
err_free_common:
release_firmware(priv->firmware);
- p54_free_common(dev);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
@@ -573,7 +573,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
err_free_dev:
pci_set_drvdata(pdev, NULL);
- ieee80211_free_hw(dev);
+ p54_free_common(dev);
err_free_reg:
pci_release_regions(pdev);
@@ -590,16 +590,15 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
if (!dev)
return;
- ieee80211_unregister_hw(dev);
+ p54_unregister_common(dev);
priv = dev->priv;
release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
- p54_free_common(dev);
iounmap(priv->map);
pci_release_regions(pdev);
pci_disable_device(pdev);
- ieee80211_free_hw(dev);
+ p54_free_common(dev);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index 72c7dbd39d0a..05458d9249ce 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -34,7 +34,7 @@
#include "p54spi_eeprom.h"
#include "p54.h"
-#include "p54common.h"
+#include "lmac.h"
MODULE_FIRMWARE("3826.arm");
MODULE_ALIAS("stlc45xx");
@@ -111,15 +111,6 @@ static void p54spi_spi_write(struct p54s_priv *priv, u8 address,
spi_sync(priv->spi, &m);
}
-static u16 p54spi_read16(struct p54s_priv *priv, u8 addr)
-{
- __le16 val;
-
- p54spi_spi_read(priv, addr, &val, sizeof(val));
-
- return le16_to_cpu(val);
-}
-
static u32 p54spi_read32(struct p54s_priv *priv, u8 addr)
{
__le32 val;
@@ -139,37 +130,12 @@ static inline void p54spi_write32(struct p54s_priv *priv, u8 addr, __le32 val)
p54spi_spi_write(priv, addr, &val, sizeof(val));
}
-struct p54spi_spi_reg {
- u16 address; /* __le16 ? */
- u16 length;
- char *name;
-};
-
-static const struct p54spi_spi_reg p54spi_registers_array[] =
-{
- { SPI_ADRS_ARM_INTERRUPTS, 32, "ARM_INT " },
- { SPI_ADRS_ARM_INT_EN, 32, "ARM_INT_ENA " },
- { SPI_ADRS_HOST_INTERRUPTS, 32, "HOST_INT " },
- { SPI_ADRS_HOST_INT_EN, 32, "HOST_INT_ENA" },
- { SPI_ADRS_HOST_INT_ACK, 32, "HOST_INT_ACK" },
- { SPI_ADRS_GEN_PURP_1, 32, "GP1_COMM " },
- { SPI_ADRS_GEN_PURP_2, 32, "GP2_COMM " },
- { SPI_ADRS_DEV_CTRL_STAT, 32, "DEV_CTRL_STA" },
- { SPI_ADRS_DMA_DATA, 16, "DMA_DATA " },
- { SPI_ADRS_DMA_WRITE_CTRL, 16, "DMA_WR_CTRL " },
- { SPI_ADRS_DMA_WRITE_LEN, 16, "DMA_WR_LEN " },
- { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_WR_BASE " },
- { SPI_ADRS_DMA_READ_CTRL, 16, "DMA_RD_CTRL " },
- { SPI_ADRS_DMA_READ_LEN, 16, "DMA_RD_LEN " },
- { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_RD_BASE " }
-};
-
-static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
+static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, u32 bits)
{
int i;
for (i = 0; i < 2000; i++) {
- __le32 buffer = p54spi_read32(priv, reg);
+ u32 buffer = p54spi_read32(priv, reg);
if ((buffer & bits) == bits)
return 1;
}
@@ -179,8 +145,7 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base,
const void *buf, size_t len)
{
- if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL,
- cpu_to_le32(HOST_ALLOWED))) {
+ if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, HOST_ALLOWED)) {
dev_err(&priv->spi->dev, "spi_write_dma not allowed "
"to DMA write.\n");
return -EAGAIN;
@@ -333,7 +298,7 @@ static int p54spi_wakeup(struct p54s_priv *priv)
/* And wait for the READY interrupt */
if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
- cpu_to_le32(SPI_HOST_INT_READY))) {
+ SPI_HOST_INT_READY)) {
dev_err(&priv->spi->dev, "INT_READY timeout\n");
return -EBUSY;
}
@@ -426,7 +391,7 @@ static irqreturn_t p54spi_interrupt(int irq, void *config)
struct spi_device *spi = config;
struct p54s_priv *priv = dev_get_drvdata(&spi->dev);
- queue_work(priv->hw->workqueue, &priv->work);
+ ieee80211_queue_work(priv->hw, &priv->work);
return IRQ_HANDLED;
}
@@ -444,7 +409,7 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb)
goto out;
if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
- cpu_to_le32(SPI_HOST_INT_WR_READY))) {
+ SPI_HOST_INT_WR_READY)) {
dev_err(&priv->spi->dev, "WR_READY timeout\n");
ret = -EAGAIN;
goto out;
@@ -514,7 +479,7 @@ static void p54spi_op_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
list_add_tail(&di->tx_list, &priv->tx_pending);
spin_unlock_irqrestore(&priv->tx_lock, flags);
- queue_work(priv->hw->workqueue, &priv->work);
+ ieee80211_queue_work(priv->hw, &priv->work);
}
static void p54spi_work(struct work_struct *work)
@@ -713,7 +678,7 @@ static int __devexit p54spi_remove(struct spi_device *spi)
{
struct p54s_priv *priv = dev_get_drvdata(&spi->dev);
- ieee80211_unregister_hw(priv->hw);
+ p54_unregister_common(priv->hw);
free_irq(gpio_to_irq(p54spi_gpio_irq), spi);
@@ -724,7 +689,6 @@ static int __devexit p54spi_remove(struct spi_device *spi)
mutex_destroy(&priv->mutex);
p54_free_common(priv->hw);
- ieee80211_free_hw(priv->hw);
return 0;
}
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 0e877a104a89..e44460ff149c 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -22,6 +22,7 @@
#include <net/mac80211.h>
#include "p54.h"
+#include "lmac.h"
#include "p54usb.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
@@ -245,8 +246,10 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
data_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!data_urb)
+ if (!data_urb) {
+ p54_free_skb(dev, skb);
return;
+ }
hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
@@ -268,27 +271,22 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct p54u_priv *priv = dev->priv;
- struct urb *int_urb, *data_urb;
+ struct urb *int_urb = NULL, *data_urb = NULL;
struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
- struct net2280_reg_write *reg;
- int err = 0;
+ struct net2280_reg_write *reg = NULL;
+ int err = -ENOMEM;
reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
if (!reg)
- return;
+ goto out;
int_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!int_urb) {
- kfree(reg);
- return;
- }
+ if (!int_urb)
+ goto out;
data_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!data_urb) {
- kfree(reg);
- usb_free_urb(int_urb);
- return;
- }
+ if (!data_urb)
+ goto out;
reg->port = cpu_to_le16(NET2280_DEV_U32);
reg->addr = cpu_to_le32(P54U_DEV_BASE);
@@ -303,11 +301,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
p54u_tx_dummy_cb, dev);
/*
- * This flag triggers a code path in the USB subsystem that will
- * free what's inside the transfer_buffer after the callback routine
- * has completed.
+ * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
+ * free what is inside the transfer_buffer after the last reference to
+ * the int_urb is dropped.
*/
int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
+ reg = NULL;
usb_fill_bulk_urb(data_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
@@ -328,12 +327,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
usb_unanchor_urb(data_urb);
goto out;
}
- out:
+out:
usb_free_urb(int_urb);
usb_free_urb(data_urb);
if (err) {
- skb_pull(skb, sizeof(*hdr));
+ kfree(reg);
p54_free_skb(dev, skb);
}
}
@@ -961,7 +960,7 @@ err_free_fw:
release_firmware(priv->fw);
err_free_dev:
- ieee80211_free_hw(dev);
+ p54_free_common(dev);
usb_set_intfdata(intf, NULL);
usb_put_dev(udev);
return err;
@@ -975,13 +974,12 @@ static void __devexit p54u_disconnect(struct usb_interface *intf)
if (!dev)
return;
- ieee80211_unregister_hw(dev);
+ p54_unregister_common(dev);
priv = dev->priv;
usb_put_dev(interface_to_usbdev(intf));
release_firmware(priv->fw);
p54_free_common(dev);
- ieee80211_free_hw(dev);
}
static int p54u_pre_reset(struct usb_interface *intf)
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
new file mode 100644
index 000000000000..b6dda2b27fb5
--- /dev/null
+++ b/drivers/net/wireless/p54/txrx.c
@@ -0,0 +1,869 @@
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+
+#ifdef P54_MM_DEBUG
+static void p54_dump_tx_queue(struct p54_common *priv)
+{
+ unsigned long flags;
+ struct ieee80211_tx_info *info;
+ struct p54_tx_info *range;
+ struct sk_buff *skb;
+ struct p54_hdr *hdr;
+ unsigned int i = 0;
+ u32 prev_addr;
+ u32 largest_hole = 0, free;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ printk(KERN_DEBUG "%s: / --- tx queue dump (%d entries) --- \n",
+ wiphy_name(priv->hw->wiphy), skb_queue_len(&priv->tx_queue));
+
+ prev_addr = priv->rx_start;
+ skb_queue_walk(&priv->tx_queue, skb) {
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *) info->rate_driver_data;
+ hdr = (void *) skb->data;
+
+ free = range->start_addr - prev_addr;
+ printk(KERN_DEBUG "%s: | [%02d] => [skb:%p skb_len:0x%04x "
+ "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} "
+ "mem:{start:%04x end:%04x, free:%d}]\n",
+ wiphy_name(priv->hw->wiphy), i++, skb, skb->len,
+ le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len),
+ le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type),
+ range->start_addr, range->end_addr, free);
+
+ prev_addr = range->end_addr;
+ largest_hole = max(largest_hole, free);
+ }
+ free = priv->rx_end - prev_addr;
+ largest_hole = max(largest_hole, free);
+ printk(KERN_DEBUG "%s: \\ --- [free: %d], largest free block: %d ---\n",
+ wiphy_name(priv->hw->wiphy), free, largest_hole);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+}
+#endif /* P54_MM_DEBUG */
+
+/*
+ * So, the firmware is somewhat stupid and doesn't know what places in its
+ * memory incoming data should go to. By poking around in the firmware, we
+ * can find some unused memory to upload our packets to. However, data that we
+ * want the card to TX needs to stay intact until the card has told us that
+ * it is done with it. This function finds empty places we can upload to and
+ * marks allocated areas as reserved if necessary. p54_find_and_unlink_skb or
+ * p54_free_skb frees allocated areas.
+ */
+static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct sk_buff *entry, *target_skb = NULL;
+ struct ieee80211_tx_info *info;
+ struct p54_tx_info *range;
+ struct p54_hdr *data = (void *) skb->data;
+ unsigned long flags;
+ u32 last_addr = priv->rx_start;
+ u32 target_addr = priv->rx_start;
+ u16 len = priv->headroom + skb->len + priv->tailroom + 3;
+
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *) info->rate_driver_data;
+ len = (range->extra_len + len) & ~0x3;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ if (unlikely(skb_queue_len(&priv->tx_queue) == 32)) {
+ /*
+ * The tx_queue is now really full.
+ *
+ * TODO: check if the device has crashed and reset it.
+ */
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return -EBUSY;
+ }
+
+ skb_queue_walk(&priv->tx_queue, entry) {
+ u32 hole_size;
+ info = IEEE80211_SKB_CB(entry);
+ range = (void *) info->rate_driver_data;
+ hole_size = range->start_addr - last_addr;
+
+ if (!target_skb && hole_size >= len) {
+ target_skb = entry->prev;
+ hole_size -= len;
+ target_addr = last_addr;
+ break;
+ }
+ last_addr = range->end_addr;
+ }
+ if (unlikely(!target_skb)) {
+ if (priv->rx_end - last_addr >= len) {
+ target_skb = priv->tx_queue.prev;
+ if (!skb_queue_empty(&priv->tx_queue)) {
+ info = IEEE80211_SKB_CB(target_skb);
+ range = (void *)info->rate_driver_data;
+ target_addr = range->end_addr;
+ }
+ } else {
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return -ENOSPC;
+ }
+ }
+
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *) info->rate_driver_data;
+ range->start_addr = target_addr;
+ range->end_addr = target_addr + len;
+ data->req_id = cpu_to_le32(target_addr + priv->headroom);
+ if (IS_DATA_FRAME(skb) &&
+ unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON))
+ priv->beacon_req_id = data->req_id;
+
+ __skb_queue_after(&priv->tx_queue, target_skb, skb);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return 0;
+}
+
+static void p54_tx_pending(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ skb = skb_dequeue(&priv->tx_pending);
+ if (unlikely(!skb))
+ return ;
+
+ ret = p54_assign_address(priv, skb);
+ if (unlikely(ret))
+ skb_queue_head(&priv->tx_pending, skb);
+ else
+ priv->tx(priv->hw, skb);
+}
+
+static void p54_wake_queues(struct p54_common *priv)
+{
+ unsigned long flags;
+ unsigned int i;
+
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
+
+ p54_tx_pending(priv);
+
+ spin_lock_irqsave(&priv->tx_stats_lock, flags);
+ for (i = 0; i < priv->hw->queues; i++) {
+ if (priv->tx_stats[i + P54_QUEUE_DATA].len <
+ priv->tx_stats[i + P54_QUEUE_DATA].limit)
+ ieee80211_wake_queue(priv->hw, i);
+ }
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+}
+
+static int p54_tx_qos_accounting_alloc(struct p54_common *priv,
+ struct sk_buff *skb,
+ const u16 p54_queue)
+{
+ struct ieee80211_tx_queue_stats *queue;
+ unsigned long flags;
+
+ if (WARN_ON(p54_queue > P54_QUEUE_NUM))
+ return -EINVAL;
+
+ queue = &priv->tx_stats[p54_queue];
+
+ spin_lock_irqsave(&priv->tx_stats_lock, flags);
+ if (unlikely(queue->len >= queue->limit && IS_QOS_QUEUE(p54_queue))) {
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+ return -ENOSPC;
+ }
+
+ queue->len++;
+ queue->count++;
+
+ if (unlikely(queue->len == queue->limit && IS_QOS_QUEUE(p54_queue))) {
+ u16 ac_queue = p54_queue - P54_QUEUE_DATA;
+ ieee80211_stop_queue(priv->hw, ac_queue);
+ }
+
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+ return 0;
+}
+
+static void p54_tx_qos_accounting_free(struct p54_common *priv,
+ struct sk_buff *skb)
+{
+ if (IS_DATA_FRAME(skb)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_stats_lock, flags);
+ priv->tx_stats[GET_HW_QUEUE(skb)].len--;
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+
+ if (unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) {
+ if (priv->beacon_req_id == GET_REQ_ID(skb)) {
+ /* this is the active beacon set anymore */
+ priv->beacon_req_id = 0;
+ }
+ complete(&priv->beacon_comp);
+ }
+ }
+ p54_wake_queues(priv);
+}
+
+void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ if (unlikely(!skb))
+ return ;
+
+ skb_unlink(skb, &priv->tx_queue);
+ p54_tx_qos_accounting_free(priv, skb);
+ dev_kfree_skb_any(skb);
+}
+EXPORT_SYMBOL_GPL(p54_free_skb);
+
+static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv,
+ const __le32 req_id)
+{
+ struct sk_buff *entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ skb_queue_walk(&priv->tx_queue, entry) {
+ struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
+
+ if (hdr->req_id == req_id) {
+ __skb_unlink(entry, &priv->tx_queue);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ p54_tx_qos_accounting_free(priv, entry);
+ return entry;
+ }
+ }
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return NULL;
+}
+
+void p54_tx(struct p54_common *priv, struct sk_buff *skb)
+{
+ skb_queue_tail(&priv->tx_pending, skb);
+ p54_tx_pending(priv);
+}
+
+static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
+{
+ int band = priv->hw->conf.channel->band;
+
+ if (priv->rxhw != 5)
+ return ((rssi * priv->rssical_db[band].mul) / 64 +
+ priv->rssical_db[band].add) / 4;
+ else
+ /*
+ * TODO: find the correct formula
+ */
+ return ((rssi * priv->rssical_db[band].mul) / 64 +
+ priv->rssical_db[band].add) / 4;
+}
+
+/*
+ * Even if the firmware is capable of dealing with incoming traffic,
+ * while dozing, we have to prepared in case mac80211 uses PS-POLL
+ * to retrieve outstanding frames from our AP.
+ * (see comment in net/mac80211/mlme.c @ line 1993)
+ */
+static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (void *) skb->data;
+ struct ieee80211_tim_ie *tim_ie;
+ u8 *tim;
+ u8 tim_len;
+ bool new_psm;
+
+ /* only beacons have a TIM IE */
+ if (!ieee80211_is_beacon(hdr->frame_control))
+ return;
+
+ if (!priv->aid)
+ return;
+
+ /* only consider beacons from the associated BSSID */
+ if (compare_ether_addr(hdr->addr3, priv->bssid))
+ return;
+
+ tim = p54_find_ie(skb, WLAN_EID_TIM);
+ if (!tim)
+ return;
+
+ tim_len = tim[1];
+ tim_ie = (struct ieee80211_tim_ie *) &tim[2];
+
+ new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid);
+ if (new_psm != priv->powersave_override) {
+ priv->powersave_override = new_psm;
+ p54_set_ps(priv);
+ }
+}
+
+static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
+ struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+ u16 freq = le16_to_cpu(hdr->freq);
+ size_t header_len = sizeof(*hdr);
+ u32 tsf32;
+ u8 rate = hdr->rate & 0xf;
+
+ /*
+ * If the device is in a unspecified state we have to
+ * ignore all data frames. Else we could end up with a
+ * nasty crash.
+ */
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return 0;
+
+ if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD)))
+ return 0;
+
+ if (hdr->decrypt_status == P54_DECRYPT_OK)
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+ if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
+ (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
+ rx_status->flag |= RX_FLAG_MMIC_ERROR;
+
+ rx_status->signal = p54_rssi_to_dbm(priv, hdr->rssi);
+ rx_status->noise = priv->noise;
+ if (hdr->rate & 0x10)
+ rx_status->flag |= RX_FLAG_SHORTPRE;
+ if (priv->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
+ rx_status->rate_idx = (rate < 4) ? 0 : rate - 4;
+ else
+ rx_status->rate_idx = rate;
+
+ rx_status->freq = freq;
+ rx_status->band = priv->hw->conf.channel->band;
+ rx_status->antenna = hdr->antenna;
+
+ tsf32 = le32_to_cpu(hdr->tsf32);
+ if (tsf32 < priv->tsf_low32)
+ priv->tsf_high32++;
+ rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
+ priv->tsf_low32 = tsf32;
+
+ rx_status->flag |= RX_FLAG_TSFT;
+
+ if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+ header_len += hdr->align[0];
+
+ skb_pull(skb, header_len);
+ skb_trim(skb, le16_to_cpu(hdr->len));
+ if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
+ p54_pspoll_workaround(priv, skb);
+
+ ieee80211_rx_irqsafe(priv->hw, skb);
+
+ ieee80211_queue_delayed_work(priv->hw, &priv->work,
+ msecs_to_jiffies(P54_STATISTICS_UPDATE));
+
+ return -1;
+}
+
+static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
+ struct ieee80211_tx_info *info;
+ struct p54_hdr *entry_hdr;
+ struct p54_tx_data *entry_data;
+ struct sk_buff *entry;
+ unsigned int pad = 0, frame_len;
+ int count, idx;
+
+ entry = p54_find_and_unlink_skb(priv, hdr->req_id);
+ if (unlikely(!entry))
+ return ;
+
+ frame_len = entry->len;
+ info = IEEE80211_SKB_CB(entry);
+ entry_hdr = (struct p54_hdr *) entry->data;
+ entry_data = (struct p54_tx_data *) entry_hdr->data;
+ priv->stats.dot11ACKFailureCount += payload->tries - 1;
+
+ /*
+ * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
+ * generated by the driver. Therefore tx_status is bogus
+ * and we don't want to confuse the mac80211 stack.
+ */
+ if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
+ dev_kfree_skb_any(entry);
+ return ;
+ }
+
+ /*
+ * Clear manually, ieee80211_tx_info_clear_status would
+ * clear the counts too and we need them.
+ */
+ memset(&info->status.ampdu_ack_len, 0,
+ sizeof(struct ieee80211_tx_info) -
+ offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
+ BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
+ status.ampdu_ack_len) != 23);
+
+ if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+ pad = entry_data->align[0];
+
+ /* walk through the rates array and adjust the counts */
+ count = payload->tries;
+ for (idx = 0; idx < 4; idx++) {
+ if (count >= info->status.rates[idx].count) {
+ count -= info->status.rates[idx].count;
+ } else if (count > 0) {
+ info->status.rates[idx].count = count;
+ count = 0;
+ } else {
+ info->status.rates[idx].idx = -1;
+ info->status.rates[idx].count = 0;
+ }
+ }
+
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+ (!payload->status))
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ if (payload->status & P54_TX_PSM_CANCELLED)
+ info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+ info->status.ack_signal = p54_rssi_to_dbm(priv,
+ (int)payload->ack_rssi);
+
+ /* Undo all changes to the frame. */
+ switch (entry_data->key_type) {
+ case P54_CRYPTO_TKIPMICHAEL: {
+ u8 *iv = (u8 *)(entry_data->align + pad +
+ entry_data->crypt_offset);
+
+ /* Restore the original TKIP IV. */
+ iv[2] = iv[0];
+ iv[0] = iv[1];
+ iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */
+
+ frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */
+ break;
+ }
+ case P54_CRYPTO_AESCCMP:
+ frame_len -= 8; /* remove CCMP_MIC */
+ break;
+ case P54_CRYPTO_WEP:
+ frame_len -= 4; /* remove WEP_ICV */
+ break;
+ }
+
+ skb_trim(entry, frame_len);
+ skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
+ ieee80211_tx_status_irqsafe(priv->hw, entry);
+}
+
+static void p54_rx_eeprom_readback(struct p54_common *priv,
+ struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
+ struct sk_buff *tmp;
+
+ if (!priv->eeprom)
+ return ;
+
+ if (priv->fw_var >= 0x509) {
+ memcpy(priv->eeprom, eeprom->v2.data,
+ le16_to_cpu(eeprom->v2.len));
+ } else {
+ memcpy(priv->eeprom, eeprom->v1.data,
+ le16_to_cpu(eeprom->v1.len));
+ }
+
+ priv->eeprom = NULL;
+ tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
+ dev_kfree_skb_any(tmp);
+ complete(&priv->eeprom_comp);
+}
+
+static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
+ struct sk_buff *tmp;
+ u32 tsf32;
+
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
+
+ tsf32 = le32_to_cpu(stats->tsf32);
+ if (tsf32 < priv->tsf_low32)
+ priv->tsf_high32++;
+ priv->tsf_low32 = tsf32;
+
+ priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
+ priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
+ priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
+
+ priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise));
+
+ tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
+ dev_kfree_skb_any(tmp);
+}
+
+static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_trap *trap = (struct p54_trap *) hdr->data;
+ u16 event = le16_to_cpu(trap->event);
+ u16 freq = le16_to_cpu(trap->frequency);
+
+ switch (event) {
+ case P54_TRAP_BEACON_TX:
+ break;
+ case P54_TRAP_RADAR:
+ printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
+ wiphy_name(priv->hw->wiphy), freq);
+ break;
+ case P54_TRAP_NO_BEACON:
+ if (priv->vif)
+ ieee80211_beacon_loss(priv->vif);
+ break;
+ case P54_TRAP_SCAN:
+ break;
+ case P54_TRAP_TBTT:
+ break;
+ case P54_TRAP_TIMER:
+ break;
+ case P54_TRAP_FAA_RADIO_OFF:
+ wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
+ break;
+ case P54_TRAP_FAA_RADIO_ON:
+ wiphy_rfkill_set_hw_state(priv->hw->wiphy, false);
+ break;
+ default:
+ printk(KERN_INFO "%s: received event:%x freq:%d\n",
+ wiphy_name(priv->hw->wiphy), event, freq);
+ break;
+ }
+}
+
+static int p54_rx_control(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+
+ switch (le16_to_cpu(hdr->type)) {
+ case P54_CONTROL_TYPE_TXDONE:
+ p54_rx_frame_sent(priv, skb);
+ break;
+ case P54_CONTROL_TYPE_TRAP:
+ p54_rx_trap(priv, skb);
+ break;
+ case P54_CONTROL_TYPE_BBP:
+ break;
+ case P54_CONTROL_TYPE_STAT_READBACK:
+ p54_rx_stats(priv, skb);
+ break;
+ case P54_CONTROL_TYPE_EEPROM_READBACK:
+ p54_rx_eeprom_readback(priv, skb);
+ break;
+ default:
+ printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
+ wiphy_name(priv->hw->wiphy), le16_to_cpu(hdr->type));
+ break;
+ }
+ return 0;
+}
+
+/* returns zero if skb can be reused */
+int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ u16 type = le16_to_cpu(*((__le16 *)skb->data));
+
+ if (type & P54_HDR_FLAG_CONTROL)
+ return p54_rx_control(priv, skb);
+ else
+ return p54_rx_data(priv, skb);
+}
+EXPORT_SYMBOL_GPL(p54_rx);
+
+static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
+ struct ieee80211_tx_info *info, u8 *queue,
+ u32 *extra_len, u16 *flags, u16 *aid,
+ bool *burst_possible)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (ieee80211_is_data_qos(hdr->frame_control))
+ *burst_possible = true;
+ else
+ *burst_possible = false;
+
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+ *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
+
+ if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)
+ *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+
+ if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+ *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+
+ *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA;
+
+ switch (priv->mode) {
+ case NL80211_IFTYPE_MONITOR:
+ /*
+ * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for
+ * every frame in promiscuous/monitor mode.
+ * see STSW45x0C LMAC API - page 12.
+ */
+ *aid = 0;
+ *flags |= P54_HDR_FLAG_DATA_OUT_PROMISC;
+ break;
+ case NL80211_IFTYPE_STATION:
+ *aid = 1;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
+ if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+ *aid = 0;
+ *queue = P54_QUEUE_CAB;
+ return;
+ }
+
+ if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
+ if (ieee80211_is_probe_resp(hdr->frame_control)) {
+ *aid = 0;
+ *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
+ P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+ return;
+ } else if (ieee80211_is_beacon(hdr->frame_control)) {
+ *aid = 0;
+
+ if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+ /*
+ * Injecting beacons on top of a AP is
+ * not a good idea... nevertheless,
+ * it should be doable.
+ */
+
+ return;
+ }
+
+ *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
+ *queue = P54_QUEUE_BEACON;
+ *extra_len = IEEE80211_MAX_TIM_LEN;
+ return;
+ }
+ }
+
+ if (info->control.sta)
+ *aid = info->control.sta->aid;
+ break;
+ }
+}
+
+static u8 p54_convert_algo(enum ieee80211_key_alg alg)
+{
+ switch (alg) {
+ case ALG_WEP:
+ return P54_CRYPTO_WEP;
+ case ALG_TKIP:
+ return P54_CRYPTO_TKIPMICHAEL;
+ case ALG_CCMP:
+ return P54_CRYPTO_AESCCMP;
+ default:
+ return 0;
+ }
+}
+
+int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct p54_tx_info *p54info;
+ struct p54_hdr *hdr;
+ struct p54_tx_data *txhdr;
+ unsigned int padding, len, extra_len;
+ int i, j, ridx;
+ u16 hdr_flags = 0, aid = 0;
+ u8 rate, queue = 0, crypt_offset = 0;
+ u8 cts_rate = 0x20;
+ u8 rc_flags;
+ u8 calculated_tries[4];
+ u8 nrates = 0, nremaining = 8;
+ bool burst_allowed = false;
+
+ p54_tx_80211_header(priv, skb, info, &queue, &extra_len,
+ &hdr_flags, &aid, &burst_allowed);
+
+ if (p54_tx_qos_accounting_alloc(priv, skb, queue)) {
+ if (!IS_QOS_QUEUE(queue)) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ } else {
+ return NETDEV_TX_BUSY;
+ }
+ }
+
+ padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
+ len = skb->len;
+
+ if (info->control.hw_key) {
+ crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
+ if (info->control.hw_key->alg == ALG_TKIP) {
+ u8 *iv = (u8 *)(skb->data + crypt_offset);
+ /*
+ * The firmware excepts that the IV has to have
+ * this special format
+ */
+ iv[1] = iv[0];
+ iv[0] = iv[2];
+ iv[2] = 0;
+ }
+ }
+
+ txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
+ hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
+
+ if (padding)
+ hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
+ hdr->type = cpu_to_le16(aid);
+ hdr->rts_tries = info->control.rates[0].count;
+
+ /*
+ * we register the rates in perfect order, and
+ * RTS/CTS won't happen on 5 GHz
+ */
+ cts_rate = info->control.rts_cts_rate_idx;
+
+ memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
+
+ /* see how many rates got used */
+ for (i = 0; i < dev->max_rates; i++) {
+ if (info->control.rates[i].idx < 0)
+ break;
+ nrates++;
+ }
+
+ /* limit tries to 8/nrates per rate */
+ for (i = 0; i < nrates; i++) {
+ /*
+ * The magic expression here is equivalent to 8/nrates for
+ * all values that matter, but avoids division and jumps.
+ * Note that nrates can only take the values 1 through 4.
+ */
+ calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
+ info->control.rates[i].count);
+ nremaining -= calculated_tries[i];
+ }
+
+ /* if there are tries left, distribute from back to front */
+ for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
+ int tmp = info->control.rates[i].count - calculated_tries[i];
+
+ if (tmp <= 0)
+ continue;
+ /* RC requested more tries at this rate */
+
+ tmp = min_t(int, tmp, nremaining);
+ calculated_tries[i] += tmp;
+ nremaining -= tmp;
+ }
+
+ ridx = 0;
+ for (i = 0; i < nrates && ridx < 8; i++) {
+ /* we register the rates in perfect order */
+ rate = info->control.rates[i].idx;
+ if (info->band == IEEE80211_BAND_5GHZ)
+ rate += 4;
+
+ /* store the count we actually calculated for TX status */
+ info->control.rates[i].count = calculated_tries[i];
+
+ rc_flags = info->control.rates[i].flags;
+ if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
+ rate |= 0x10;
+ cts_rate |= 0x10;
+ }
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+ burst_allowed = false;
+ rate |= 0x40;
+ } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+ rate |= 0x20;
+ burst_allowed = false;
+ }
+ for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
+ txhdr->rateset[ridx] = rate;
+ ridx++;
+ }
+ }
+
+ if (burst_allowed)
+ hdr_flags |= P54_HDR_FLAG_DATA_OUT_BURST;
+
+ /* TODO: enable bursting */
+ hdr->flags = cpu_to_le16(hdr_flags);
+ hdr->tries = ridx;
+ txhdr->rts_rate_idx = 0;
+ if (info->control.hw_key) {
+ txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
+ txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
+ memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
+ if (info->control.hw_key->alg == ALG_TKIP) {
+ /* reserve space for the MIC key */
+ len += 8;
+ memcpy(skb_put(skb, 8), &(info->control.hw_key->key
+ [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
+ }
+ /* reserve some space for ICV */
+ len += info->control.hw_key->icv_len;
+ memset(skb_put(skb, info->control.hw_key->icv_len), 0,
+ info->control.hw_key->icv_len);
+ } else {
+ txhdr->key_type = 0;
+ txhdr->key_len = 0;
+ }
+ txhdr->crypt_offset = crypt_offset;
+ txhdr->hw_queue = queue;
+ txhdr->backlog = priv->tx_stats[queue].len - 1;
+ memset(txhdr->durations, 0, sizeof(txhdr->durations));
+ txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ?
+ 2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask;
+ if (priv->rxhw == 5) {
+ txhdr->longbow.cts_rate = cts_rate;
+ txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
+ } else {
+ txhdr->normal.output_power = priv->output_power;
+ txhdr->normal.cts_rate = cts_rate;
+ }
+ if (padding)
+ txhdr->align[0] = padding;
+
+ hdr->len = cpu_to_le16(len);
+ /* modifies skb->cb and with it info, so must be last! */
+ p54info = (void *) info->rate_driver_data;
+ p54info->extra_len = extra_len;
+
+ p54_tx(priv, skb);
+ return NETDEV_TX_OK;
+}
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index 8f6210993448..872b64783e78 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -50,7 +50,7 @@ islpci_eth_cleanup_transmit(islpci_private *priv,
/* check for holes in the arrays caused by multi fragment frames
* searching for the last fragment of a frame */
- if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) {
+ if (priv->pci_map_tx_address[index]) {
/* entry is the last fragment of a frame
* free the skb structure and unmap pci memory */
skb = priv->data_low_tx[index];
@@ -72,7 +72,7 @@ islpci_eth_cleanup_transmit(islpci_private *priv,
}
}
-int
+netdev_tx_t
islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
{
islpci_private *priv = netdev_priv(ndev);
@@ -234,7 +234,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
/* unlock the driver code */
spin_unlock_irqrestore(&priv->slock, flags);
- return 0;
+ return NETDEV_TX_OK;
drop_free:
ndev->stats.tx_dropped++;
@@ -450,7 +450,7 @@ islpci_eth_receive(islpci_private *priv)
pci_map_single(priv->pdev, (void *) skb->data,
MAX_FRAGMENT_SIZE_RX + 2,
PCI_DMA_FROMDEVICE);
- if (unlikely(priv->pci_map_rx_address[index] == (dma_addr_t) NULL)) {
+ if (unlikely(!priv->pci_map_rx_address[index])) {
/* error mapping the buffer to device accessable memory address */
DEBUG(SHOW_ERROR_MESSAGES,
"Error mapping DMA address\n");
diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h
index 61454d32d74d..54f9a4b7bf9b 100644
--- a/drivers/net/wireless/prism54/islpci_eth.h
+++ b/drivers/net/wireless/prism54/islpci_eth.h
@@ -64,7 +64,7 @@ struct avs_80211_1_header {
};
void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *);
-int islpci_eth_transmit(struct sk_buff *, struct net_device *);
+netdev_tx_t islpci_eth_transmit(struct sk_buff *, struct net_device *);
int islpci_eth_receive(islpci_private *);
void islpci_eth_tx_timeout(struct net_device *);
void islpci_do_reset_and_wake(struct work_struct *);
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index 30876728d7e6..83d366258c81 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -49,9 +49,7 @@ static const struct pci_device_id prism54_id_tbl[] = {
/* 3COM 3CRWE154G72 Wireless LAN adapter */
{
- 0x10b7, 0x6001,
- PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 0
+ PCI_VDEVICE(3COM, 0x6001), 0
},
/* Intersil PRISM Indigo Wireless LAN adapter */
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 698b11b1cadb..88cd58eb3b9f 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -104,7 +104,8 @@ static int ray_dev_init(struct net_device *dev);
static const struct ethtool_ops netdev_ethtool_ops;
static int ray_open(struct net_device *dev);
-static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb,
+ struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static void ray_update_multi_list(struct net_device *dev, int all);
static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx,
@@ -915,16 +916,19 @@ static int ray_dev_config(struct net_device *dev, struct ifmap *map)
}
/*===========================================================================*/
-static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
short length = skb->len;
- if (!(pcmcia_dev_present(link))) {
+ if (!pcmcia_dev_present(link)) {
DEBUG(2, "ray_dev_start_xmit - device not present\n");
- return NETDEV_TX_LOCKED;
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
}
+
DEBUG(3, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev);
if (local->authentication_state == NEED_TO_AUTH) {
DEBUG(0, "ray_cs Sending authentication request.\n");
@@ -937,7 +941,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) {
@@ -951,9 +955,9 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
default:
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
}
- return 0;
+
+ return NETDEV_TX_OK;
} /* ray_dev_start_xmit */
/*===========================================================================*/
@@ -1511,9 +1515,6 @@ static iw_stats *ray_get_wireless_stats(struct net_device *dev)
struct pcmcia_device *link = local->finder;
struct status __iomem *p = local->sram + STATUS_BASE;
- if (local == (ray_dev_t *) NULL)
- return (iw_stats *) NULL;
-
local->wstats.status = local->card_status;
#ifdef WIRELESS_SPY
if ((local->spy_data.spy_number > 0)
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 3bec3dbd3450..54175b6fa86c 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -100,7 +100,6 @@ MODULE_PARM_DESC(workaround_interval,
#define OID_GEN_RCV_ERROR cpu_to_le32(0x00020104)
#define OID_GEN_RCV_NO_BUFFER cpu_to_le32(0x00020105)
-#define OID_802_3_PERMANENT_ADDRESS cpu_to_le32(0x01010101)
#define OID_802_3_CURRENT_ADDRESS cpu_to_le32(0x01010102)
#define OID_802_3_MULTICAST_LIST cpu_to_le32(0x01010103)
#define OID_802_3_MAXIMUM_LIST_SIZE cpu_to_le32(0x01010104)
@@ -139,9 +138,15 @@ MODULE_PARM_DESC(workaround_interval,
/* Assume that Broadcom 4320 (only chipset at time of writing known to be
* based on wireless rndis) has default txpower of 13dBm.
* This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications.
- * 13dBm == 19.9mW
+ * 100% : 20 mW ~ 13dBm
+ * 75% : 15 mW ~ 12dBm
+ * 50% : 10 mW ~ 10dBm
+ * 25% : 5 mW ~ 7dBm
*/
-#define BCM4320_DEFAULT_TXPOWER 20
+#define BCM4320_DEFAULT_TXPOWER_DBM_100 13
+#define BCM4320_DEFAULT_TXPOWER_DBM_75 12
+#define BCM4320_DEFAULT_TXPOWER_DBM_50 10
+#define BCM4320_DEFAULT_TXPOWER_DBM_25 7
/* codes for "status" field of completion messages */
@@ -196,6 +201,24 @@ enum ndis_80211_priv_filter {
NDIS_80211_PRIV_8021X_WEP
};
+enum ndis_80211_status_type {
+ NDIS_80211_STATUSTYPE_AUTHENTICATION,
+ NDIS_80211_STATUSTYPE_MEDIASTREAMMODE,
+ NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST,
+ NDIS_80211_STATUSTYPE_RADIOSTATE,
+};
+
+enum ndis_80211_media_stream_mode {
+ NDIS_80211_MEDIA_STREAM_OFF,
+ NDIS_80211_MEDIA_STREAM_ON
+};
+
+enum ndis_80211_radio_status {
+ NDIS_80211_RADIO_STATUS_ON,
+ NDIS_80211_RADIO_STATUS_HARDWARE_OFF,
+ NDIS_80211_RADIO_STATUS_SOFTWARE_OFF,
+};
+
enum ndis_80211_addkey_bits {
NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28),
NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29),
@@ -208,6 +231,35 @@ enum ndis_80211_addwep_bits {
NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31)
};
+struct ndis_80211_auth_request {
+ __le32 length;
+ u8 bssid[6];
+ u8 padding[2];
+ __le32 flags;
+} __attribute__((packed));
+
+struct ndis_80211_pmkid_candidate {
+ u8 bssid[6];
+ u8 padding[2];
+ __le32 flags;
+} __attribute__((packed));
+
+struct ndis_80211_pmkid_cand_list {
+ __le32 version;
+ __le32 num_candidates;
+ struct ndis_80211_pmkid_candidate candidate_list[0];
+} __attribute__((packed));
+
+struct ndis_80211_status_indication {
+ __le32 status_type;
+ union {
+ __le32 media_stream_mode;
+ __le32 radio_status;
+ struct ndis_80211_auth_request auth_request[0];
+ struct ndis_80211_pmkid_cand_list cand_list;
+ } u;
+} __attribute__((packed));
+
struct ndis_80211_ssid {
__le32 length;
u8 essid[NDIS_802_11_LENGTH_SSID];
@@ -275,6 +327,7 @@ struct ndis_80211_remove_key {
__le32 size;
__le32 index;
u8 bssid[6];
+ u8 padding[2];
} __attribute__((packed));
struct ndis_config_param {
@@ -305,13 +358,6 @@ struct ndis_80211_assoc_info {
__le32 offset_resp_ies;
} __attribute__((packed));
-/* these have to match what is in wpa_supplicant */
-enum wpa_alg { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP };
-enum wpa_cipher { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
- CIPHER_WEP104 };
-enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
- KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE };
-
/*
* private data
*/
@@ -326,6 +372,15 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
#define WORK_LINK_DOWN (1<<1)
#define WORK_SET_MULTICAST_LIST (1<<2)
+#define RNDIS_WLAN_ALG_NONE 0
+#define RNDIS_WLAN_ALG_WEP (1<<0)
+#define RNDIS_WLAN_ALG_TKIP (1<<1)
+#define RNDIS_WLAN_ALG_CCMP (1<<2)
+
+#define RNDIS_WLAN_KEY_MGMT_NONE 0
+#define RNDIS_WLAN_KEY_MGMT_802_1X (1<<0)
+#define RNDIS_WLAN_KEY_MGMT_PSK (1<<1)
+
#define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set))
static const struct ieee80211_channel rndis_channels[] = {
@@ -360,6 +415,22 @@ static const struct ieee80211_rate rndis_rates[] = {
{ .bitrate = 540 }
};
+static const u32 rndis_cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+};
+
+struct rndis_wlan_encr_key {
+ int len;
+ u32 cipher;
+ u8 material[32];
+ u8 bssid[ETH_ALEN];
+ bool pairwise;
+ bool tx_key;
+};
+
/* RNDIS device private data */
struct rndis_wlan_private {
struct usbnet *usbdev;
@@ -369,19 +440,17 @@ struct rndis_wlan_private {
struct cfg80211_scan_request *scan_request;
struct workqueue_struct *workqueue;
- struct delayed_work stats_work;
+ struct delayed_work dev_poller_work;
struct delayed_work scan_work;
struct work_struct work;
struct mutex command_lock;
- spinlock_t stats_lock;
unsigned long work_pending;
+ int last_qual;
struct ieee80211_supported_band band;
struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)];
struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)];
-
- struct iw_statistics iwstats;
- struct iw_statistics privstats;
+ u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)];
int caps;
int multicast_size;
@@ -397,18 +466,19 @@ struct rndis_wlan_private {
u32 param_workaround_interval;
/* hardware state */
- int radio_on;
+ bool radio_on;
int infra_mode;
+ bool connected;
+ u8 bssid[ETH_ALEN];
struct ndis_80211_ssid essid;
+ __le32 current_command_oid;
/* encryption stuff */
int encr_tx_key_index;
- char encr_keys[4][32];
- int encr_key_len[4];
- char encr_key_wpa[4];
+ struct rndis_wlan_encr_key encr_keys[4];
+ enum nl80211_auth_type wpa_auth_type;
int wpa_version;
int wpa_keymgmt;
- int wpa_authalg;
int wpa_ie_len;
u8 *wpa_ie;
int wpa_cipher_pair;
@@ -420,39 +490,186 @@ struct rndis_wlan_private {
/*
* cfg80211 ops
*/
-static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
+static int rndis_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params);
static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request);
+static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);
+
+static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
+ int dbm);
+static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm);
+
+static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+
+static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code);
+
+static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params);
+
+static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev);
+
+static int rndis_set_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan, enum nl80211_channel_type channel_type);
+
+static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, const u8 *mac_addr,
+ struct key_params *params);
+
+static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, const u8 *mac_addr);
+
+static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index);
+
+static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_info *sinfo);
+
+static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *mac, struct station_info *sinfo);
+
static struct cfg80211_ops rndis_config_ops = {
.change_virtual_intf = rndis_change_virtual_intf,
.scan = rndis_scan,
+ .set_wiphy_params = rndis_set_wiphy_params,
+ .set_tx_power = rndis_set_tx_power,
+ .get_tx_power = rndis_get_tx_power,
+ .connect = rndis_connect,
+ .disconnect = rndis_disconnect,
+ .join_ibss = rndis_join_ibss,
+ .leave_ibss = rndis_leave_ibss,
+ .set_channel = rndis_set_channel,
+ .add_key = rndis_add_key,
+ .del_key = rndis_del_key,
+ .set_default_key = rndis_set_default_key,
+ .get_station = rndis_get_station,
+ .dump_station = rndis_dump_station,
};
static void *rndis_wiphy_privid = &rndis_wiphy_privid;
-static const int bcm4320_power_output[4] = { 25, 50, 75, 100 };
-
-static const unsigned char zero_bssid[ETH_ALEN] = {0,};
-static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff };
-
static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev)
{
return (struct rndis_wlan_private *)dev->driver_priv;
}
+static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv)
+{
+ switch (priv->param_power_output) {
+ default:
+ case 3:
+ return BCM4320_DEFAULT_TXPOWER_DBM_100;
+ case 2:
+ return BCM4320_DEFAULT_TXPOWER_DBM_75;
+ case 1:
+ return BCM4320_DEFAULT_TXPOWER_DBM_50;
+ case 0:
+ return BCM4320_DEFAULT_TXPOWER_DBM_25;
+ }
+}
-static u32 get_bcm4320_power(struct rndis_wlan_private *priv)
+static bool is_wpa_key(struct rndis_wlan_private *priv, int idx)
{
- return BCM4320_DEFAULT_TXPOWER *
- bcm4320_power_output[priv->param_power_output] / 100;
+ int cipher = priv->encr_keys[idx].cipher;
+
+ return (cipher == WLAN_CIPHER_SUITE_CCMP ||
+ cipher == WLAN_CIPHER_SUITE_TKIP);
}
+static int rndis_cipher_to_alg(u32 cipher)
+{
+ switch (cipher) {
+ default:
+ return RNDIS_WLAN_ALG_NONE;
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ return RNDIS_WLAN_ALG_WEP;
+ case WLAN_CIPHER_SUITE_TKIP:
+ return RNDIS_WLAN_ALG_TKIP;
+ case WLAN_CIPHER_SUITE_CCMP:
+ return RNDIS_WLAN_ALG_CCMP;
+ }
+}
+
+static int rndis_akm_suite_to_key_mgmt(u32 akm_suite)
+{
+ switch (akm_suite) {
+ default:
+ return RNDIS_WLAN_KEY_MGMT_NONE;
+ case WLAN_AKM_SUITE_8021X:
+ return RNDIS_WLAN_KEY_MGMT_802_1X;
+ case WLAN_AKM_SUITE_PSK:
+ return RNDIS_WLAN_KEY_MGMT_PSK;
+ }
+}
+
+#ifdef DEBUG
+static const char *oid_to_string(__le32 oid)
+{
+ switch (oid) {
+#define OID_STR(oid) case oid: return(#oid)
+ /* from rndis_host.h */
+ OID_STR(OID_802_3_PERMANENT_ADDRESS);
+ OID_STR(OID_GEN_MAXIMUM_FRAME_SIZE);
+ OID_STR(OID_GEN_CURRENT_PACKET_FILTER);
+ OID_STR(OID_GEN_PHYSICAL_MEDIUM);
+
+ /* from rndis_wlan.c */
+ OID_STR(OID_GEN_LINK_SPEED);
+ OID_STR(OID_GEN_RNDIS_CONFIG_PARAMETER);
+
+ OID_STR(OID_GEN_XMIT_OK);
+ OID_STR(OID_GEN_RCV_OK);
+ OID_STR(OID_GEN_XMIT_ERROR);
+ OID_STR(OID_GEN_RCV_ERROR);
+ OID_STR(OID_GEN_RCV_NO_BUFFER);
+
+ OID_STR(OID_802_3_CURRENT_ADDRESS);
+ OID_STR(OID_802_3_MULTICAST_LIST);
+ OID_STR(OID_802_3_MAXIMUM_LIST_SIZE);
+
+ OID_STR(OID_802_11_BSSID);
+ OID_STR(OID_802_11_SSID);
+ OID_STR(OID_802_11_INFRASTRUCTURE_MODE);
+ OID_STR(OID_802_11_ADD_WEP);
+ OID_STR(OID_802_11_REMOVE_WEP);
+ OID_STR(OID_802_11_DISASSOCIATE);
+ OID_STR(OID_802_11_AUTHENTICATION_MODE);
+ OID_STR(OID_802_11_PRIVACY_FILTER);
+ OID_STR(OID_802_11_BSSID_LIST_SCAN);
+ OID_STR(OID_802_11_ENCRYPTION_STATUS);
+ OID_STR(OID_802_11_ADD_KEY);
+ OID_STR(OID_802_11_REMOVE_KEY);
+ OID_STR(OID_802_11_ASSOCIATION_INFORMATION);
+ OID_STR(OID_802_11_PMKID);
+ OID_STR(OID_802_11_NETWORK_TYPES_SUPPORTED);
+ OID_STR(OID_802_11_NETWORK_TYPE_IN_USE);
+ OID_STR(OID_802_11_TX_POWER_LEVEL);
+ OID_STR(OID_802_11_RSSI);
+ OID_STR(OID_802_11_RSSI_TRIGGER);
+ OID_STR(OID_802_11_FRAGMENTATION_THRESHOLD);
+ OID_STR(OID_802_11_RTS_THRESHOLD);
+ OID_STR(OID_802_11_SUPPORTED_RATES);
+ OID_STR(OID_802_11_CONFIGURATION);
+ OID_STR(OID_802_11_BSSID_LIST);
+#undef OID_STR
+ }
+
+ return "?";
+}
+#else
+static const char *oid_to_string(__le32 oid)
+{
+ return "?";
+}
+#endif
/* translate error code */
static int rndis_error_status(__le32 rndis_status)
@@ -477,7 +694,6 @@ static int rndis_error_status(__le32 rndis_status)
return ret;
}
-
static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev);
@@ -508,12 +724,25 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
u.get->msg_len = cpu_to_le32(sizeof *u.get);
u.get->oid = oid;
+ priv->current_command_oid = oid;
ret = rndis_command(dev, u.header, buflen);
+ priv->current_command_oid = 0;
+ if (ret < 0)
+ devdbg(dev, "rndis_query_oid(%s): rndis_command() failed, %d "
+ "(%08x)", oid_to_string(oid), ret,
+ le32_to_cpu(u.get_c->status));
+
if (ret == 0) {
ret = le32_to_cpu(u.get_c->len);
- *len = (*len > ret) ? ret : *len;
+ if (ret > *len)
+ *len = ret;
memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len);
ret = rndis_error_status(u.get_c->status);
+
+ if (ret < 0)
+ devdbg(dev, "rndis_query_oid(%s): device returned "
+ "error, 0x%08x (%d)", oid_to_string(oid),
+ le32_to_cpu(u.get_c->status), ret);
}
mutex_unlock(&priv->command_lock);
@@ -523,7 +752,6 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
return ret;
}
-
static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev);
@@ -558,10 +786,23 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
u.set->handle = cpu_to_le32(0);
memcpy(u.buf + sizeof(*u.set), data, len);
+ priv->current_command_oid = oid;
ret = rndis_command(dev, u.header, buflen);
- if (ret == 0)
+ priv->current_command_oid = 0;
+ if (ret < 0)
+ devdbg(dev, "rndis_set_oid(%s): rndis_command() failed, %d "
+ "(%08x)", oid_to_string(oid), ret,
+ le32_to_cpu(u.set_c->status));
+
+ if (ret == 0) {
ret = rndis_error_status(u.set_c->status);
+ if (ret < 0)
+ devdbg(dev, "rndis_set_oid(%s): device returned error, "
+ "0x%08x (%d)", oid_to_string(oid),
+ le32_to_cpu(u.set_c->status), ret);
+ }
+
mutex_unlock(&priv->command_lock);
if (u.buf != priv->command_buffer)
@@ -569,6 +810,27 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
return ret;
}
+static int rndis_reset(struct usbnet *usbdev)
+{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ struct rndis_reset *reset;
+ int ret;
+
+ mutex_lock(&priv->command_lock);
+
+ reset = (void *)priv->command_buffer;
+ memset(reset, 0, sizeof(*reset));
+ reset->msg_type = RNDIS_MSG_RESET;
+ reset->msg_len = cpu_to_le32(sizeof(*reset));
+ priv->current_command_oid = 0;
+ ret = rndis_command(usbdev, (void *)reset, CONTROL_BUFFER_SIZE);
+
+ mutex_unlock(&priv->command_lock);
+
+ if (ret < 0)
+ return ret;
+ return 0;
+}
/*
* Specs say that we can only set config parameters only soon after device
@@ -656,16 +918,9 @@ static int rndis_set_config_parameter(struct usbnet *dev, char *param,
static int rndis_set_config_parameter_str(struct usbnet *dev,
char *param, char *value)
{
- return(rndis_set_config_parameter(dev, param, 2, value));
+ return rndis_set_config_parameter(dev, param, 2, value);
}
-/*static int rndis_set_config_parameter_u32(struct usbnet *dev,
- char *param, u32 value)
-{
- return(rndis_set_config_parameter(dev, param, 0, &value));
-}*/
-
-
/*
* data conversion functions
*/
@@ -675,91 +930,51 @@ static int level_to_qual(int level)
return qual >= 0 ? (qual <= 100 ? qual : 100) : 0;
}
-
-static void dsconfig_to_freq(unsigned int dsconfig, struct iw_freq *freq)
-{
- freq->e = 0;
- freq->i = 0;
- freq->flags = 0;
-
- /* see comment in wireless.h above the "struct iw_freq"
- * definition for an explanation of this if
- * NOTE: 1000000 is due to the kHz
- */
- if (dsconfig > 1000000) {
- freq->m = dsconfig / 10;
- freq->e = 1;
- } else
- freq->m = dsconfig;
-
- /* convert from kHz to Hz */
- freq->e += 3;
-}
-
-
-static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig)
-{
- if (freq->m < 1000 && freq->e == 0) {
- if (freq->m >= 1 && freq->m <= 14)
- *dsconfig = ieee80211_dsss_chan_to_freq(freq->m) * 1000;
- else
- return -1;
- } else {
- int i;
- *dsconfig = freq->m;
- for (i = freq->e; i > 0; i--)
- *dsconfig *= 10;
- *dsconfig /= 1000;
- }
-
- return 0;
-}
-
-
/*
* common functions
*/
-static int
-add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index);
+static int set_infra_mode(struct usbnet *usbdev, int mode);
+static void restore_keys(struct usbnet *usbdev);
+static int rndis_check_bssid_list(struct usbnet *usbdev);
-static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
+static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
{
- int ret, len;
-
- len = sizeof(*ssid);
- ret = rndis_query_oid(usbdev, OID_802_11_SSID, ssid, &len);
-
- if (ret != 0)
- ssid->length = 0;
-
-#ifdef DEBUG
- {
- unsigned char tmp[NDIS_802_11_LENGTH_SSID + 1];
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ int ret;
- memcpy(tmp, ssid->essid, le32_to_cpu(ssid->length));
- tmp[le32_to_cpu(ssid->length)] = 0;
- devdbg(usbdev, "get_essid: '%s', ret: %d", tmp, ret);
+ ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid));
+ if (ret < 0) {
+ devwarn(usbdev, "setting SSID failed (%08X)", ret);
+ return ret;
}
-#endif
+ if (ret == 0) {
+ memcpy(&priv->essid, ssid, sizeof(priv->essid));
+ priv->radio_on = true;
+ devdbg(usbdev, "set_essid: radio_on = true");
+ }
+
return ret;
}
-
-static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
+static int set_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN])
{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
int ret;
- ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid));
- if (ret == 0) {
- memcpy(&priv->essid, ssid, sizeof(priv->essid));
- priv->radio_on = 1;
- devdbg(usbdev, "set_essid: radio_on = 1");
+ ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN);
+ if (ret < 0) {
+ devwarn(usbdev, "setting BSSID[%pM] failed (%08X)", bssid, ret);
+ return ret;
}
return ret;
}
+static int clear_bssid(struct usbnet *usbdev)
+{
+ u8 broadcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ return set_bssid(usbdev, broadcast_mac);
+}
static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN])
{
@@ -781,18 +996,21 @@ static int get_association_info(struct usbnet *usbdev,
info, &len);
}
-static int is_associated(struct usbnet *usbdev)
+static bool is_associated(struct usbnet *usbdev)
{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
u8 bssid[ETH_ALEN];
int ret;
+ if (!priv->radio_on)
+ return false;
+
ret = get_bssid(usbdev, bssid);
- return(ret == 0 && memcmp(bssid, zero_bssid, ETH_ALEN) != 0);
+ return (ret == 0 && !is_zero_ether_addr(bssid));
}
-
-static int disassociate(struct usbnet *usbdev, int reset_ssid)
+static int disassociate(struct usbnet *usbdev, bool reset_ssid)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
struct ndis_80211_ssid ssid;
@@ -801,8 +1019,8 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid)
if (priv->radio_on) {
ret = rndis_set_oid(usbdev, OID_802_11_DISASSOCIATE, NULL, 0);
if (ret == 0) {
- priv->radio_on = 0;
- devdbg(usbdev, "disassociate: radio_on = 0");
+ priv->radio_on = false;
+ devdbg(usbdev, "disassociate: radio_on = false");
if (reset_ssid)
msleep(100);
@@ -812,6 +1030,11 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid)
/* disassociate causes radio to be turned off; if reset_ssid
* is given, set random ssid to enable radio */
if (reset_ssid) {
+ /* Set device to infrastructure mode so we don't get ad-hoc
+ * 'media connect' indications with the random ssid.
+ */
+ set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA);
+
ssid.length = cpu_to_le32(sizeof(ssid.essid));
get_random_bytes(&ssid.essid[2], sizeof(ssid.essid)-2);
ssid.essid[0] = 0x1;
@@ -823,35 +1046,34 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid)
return ret;
}
-
-static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg)
+static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version,
+ enum nl80211_auth_type auth_type, int keymgmt)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
__le32 tmp;
int auth_mode, ret;
devdbg(usbdev, "set_auth_mode: wpa_version=0x%x authalg=0x%x "
- "keymgmt=0x%x", wpa_version, authalg, priv->wpa_keymgmt);
+ "keymgmt=0x%x", wpa_version, auth_type, keymgmt);
- if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) {
- if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X)
+ if (wpa_version & NL80211_WPA_VERSION_2) {
+ if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X)
auth_mode = NDIS_80211_AUTH_WPA2;
else
auth_mode = NDIS_80211_AUTH_WPA2_PSK;
- } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) {
- if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X)
+ } else if (wpa_version & NL80211_WPA_VERSION_1) {
+ if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X)
auth_mode = NDIS_80211_AUTH_WPA;
- else if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_PSK)
+ else if (keymgmt & RNDIS_WLAN_KEY_MGMT_PSK)
auth_mode = NDIS_80211_AUTH_WPA_PSK;
else
auth_mode = NDIS_80211_AUTH_WPA_NONE;
- } else if (authalg & IW_AUTH_ALG_SHARED_KEY) {
- if (authalg & IW_AUTH_ALG_OPEN_SYSTEM)
- auth_mode = NDIS_80211_AUTH_AUTO_SWITCH;
- else
- auth_mode = NDIS_80211_AUTH_SHARED;
- } else
+ } else if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+ auth_mode = NDIS_80211_AUTH_SHARED;
+ else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
auth_mode = NDIS_80211_AUTH_OPEN;
+ else
+ return -ENOTSUPP;
tmp = cpu_to_le32(auth_mode);
ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp,
@@ -862,11 +1084,12 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg)
}
priv->wpa_version = wpa_version;
- priv->wpa_authalg = authalg;
+ priv->wpa_auth_type = auth_type;
+ priv->wpa_keymgmt = keymgmt;
+
return 0;
}
-
static int set_priv_filter(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
@@ -874,8 +1097,8 @@ static int set_priv_filter(struct usbnet *usbdev)
devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version);
- if (priv->wpa_version & IW_AUTH_WPA_VERSION_WPA2 ||
- priv->wpa_version & IW_AUTH_WPA_VERSION_WPA)
+ if (priv->wpa_version & NL80211_WPA_VERSION_2 ||
+ priv->wpa_version & NL80211_WPA_VERSION_1)
tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP);
else
tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL);
@@ -884,7 +1107,6 @@ static int set_priv_filter(struct usbnet *usbdev)
sizeof(tmp));
}
-
static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
@@ -892,19 +1114,17 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
int encr_mode, ret;
devdbg(usbdev, "set_encr_mode: cipher_pair=0x%x cipher_group=0x%x",
- pairwise,
- groupwise);
+ pairwise, groupwise);
- if (pairwise & IW_AUTH_CIPHER_CCMP)
+ if (pairwise & RNDIS_WLAN_ALG_CCMP)
encr_mode = NDIS_80211_ENCR_CCMP_ENABLED;
- else if (pairwise & IW_AUTH_CIPHER_TKIP)
+ else if (pairwise & RNDIS_WLAN_ALG_TKIP)
encr_mode = NDIS_80211_ENCR_TKIP_ENABLED;
- else if (pairwise &
- (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
+ else if (pairwise & RNDIS_WLAN_ALG_WEP)
encr_mode = NDIS_80211_ENCR_WEP_ENABLED;
- else if (groupwise & IW_AUTH_CIPHER_CCMP)
+ else if (groupwise & RNDIS_WLAN_ALG_CCMP)
encr_mode = NDIS_80211_ENCR_CCMP_ENABLED;
- else if (groupwise & IW_AUTH_CIPHER_TKIP)
+ else if (groupwise & RNDIS_WLAN_ALG_TKIP)
encr_mode = NDIS_80211_ENCR_TKIP_ENABLED;
else
encr_mode = NDIS_80211_ENCR_DISABLED;
@@ -922,24 +1142,11 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
return 0;
}
-
-static int set_assoc_params(struct usbnet *usbdev)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
-
- set_auth_mode(usbdev, priv->wpa_version, priv->wpa_authalg);
- set_priv_filter(usbdev);
- set_encr_mode(usbdev, priv->wpa_cipher_pair, priv->wpa_cipher_group);
-
- return 0;
-}
-
-
static int set_infra_mode(struct usbnet *usbdev, int mode)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
__le32 tmp;
- int ret, i;
+ int ret;
devdbg(usbdev, "set_infra_mode: infra_mode=0x%x", priv->infra_mode);
@@ -954,55 +1161,107 @@ static int set_infra_mode(struct usbnet *usbdev, int mode)
/* NDIS drivers clear keys when infrastructure mode is
* changed. But Linux tools assume otherwise. So set the
* keys */
- if (priv->wpa_keymgmt == 0 ||
- priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) {
- for (i = 0; i < 4; i++) {
- if (priv->encr_key_len[i] > 0 && !priv->encr_key_wpa[i])
- add_wep_key(usbdev, priv->encr_keys[i],
- priv->encr_key_len[i], i);
- }
- }
+ restore_keys(usbdev);
priv->infra_mode = mode;
return 0;
}
+static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold)
+{
+ __le32 tmp;
-static void set_default_iw_params(struct usbnet *usbdev)
+ devdbg(usbdev, "set_rts_threshold %i", rts_threshold);
+
+ if (rts_threshold < 0 || rts_threshold > 2347)
+ rts_threshold = 2347;
+
+ tmp = cpu_to_le32(rts_threshold);
+ return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp,
+ sizeof(tmp));
+}
+
+static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold)
{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ __le32 tmp;
+
+ devdbg(usbdev, "set_frag_threshold %i", frag_threshold);
- priv->wpa_keymgmt = 0;
- priv->wpa_version = 0;
+ if (frag_threshold < 256 || frag_threshold > 2346)
+ frag_threshold = 2346;
+ tmp = cpu_to_le32(frag_threshold);
+ return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
+ sizeof(tmp));
+}
+
+static void set_default_iw_params(struct usbnet *usbdev)
+{
set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA);
- set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED,
- IW_AUTH_ALG_OPEN_SYSTEM);
+ set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM,
+ RNDIS_WLAN_KEY_MGMT_NONE);
set_priv_filter(usbdev);
- set_encr_mode(usbdev, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE);
+ set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE);
}
-
static int deauthenticate(struct usbnet *usbdev)
{
int ret;
- ret = disassociate(usbdev, 1);
+ ret = disassociate(usbdev, true);
set_default_iw_params(usbdev);
return ret;
}
+static int set_channel(struct usbnet *usbdev, int channel)
+{
+ struct ndis_80211_conf config;
+ unsigned int dsconfig;
+ int len, ret;
+
+ devdbg(usbdev, "set_channel(%d)", channel);
+
+ /* this OID is valid only when not associated */
+ if (is_associated(usbdev))
+ return 0;
+
+ dsconfig = ieee80211_dsss_chan_to_freq(channel) * 1000;
+
+ len = sizeof(config);
+ ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len);
+ if (ret < 0) {
+ devdbg(usbdev, "set_channel: querying configuration failed");
+ return ret;
+ }
+
+ config.ds_config = cpu_to_le32(dsconfig);
+ ret = rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config,
+ sizeof(config));
+
+ devdbg(usbdev, "set_channel: %d -> %d", channel, ret);
+
+ return ret;
+}
/* index must be 0 - N, as per NDIS */
-static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index)
+static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len,
+ int index)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
struct ndis_80211_wep_key ndis_key;
+ u32 cipher;
int ret;
- if (key_len <= 0 || key_len > 32 || index < 0 || index >= 4)
+ devdbg(usbdev, "add_wep_key(idx: %d, len: %d)", index, key_len);
+
+ if ((key_len != 5 && key_len != 13) || index < 0 || index > 3)
return -EINVAL;
+ if (key_len == 5)
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ else
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+
memset(&ndis_key, 0, sizeof(ndis_key));
ndis_key.size = cpu_to_le32(sizeof(ndis_key));
@@ -1012,8 +1271,8 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index)
if (index == priv->encr_tx_key_index) {
ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY;
- ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104,
- IW_AUTH_CIPHER_NONE);
+ ret = set_encr_mode(usbdev, RNDIS_WLAN_ALG_WEP,
+ RNDIS_WLAN_ALG_NONE);
if (ret)
devwarn(usbdev, "encryption couldn't be enabled (%08X)",
ret);
@@ -1027,30 +1286,51 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index)
return ret;
}
- priv->encr_key_len[index] = key_len;
- priv->encr_key_wpa[index] = 0;
- memcpy(&priv->encr_keys[index], key, key_len);
+ priv->encr_keys[index].len = key_len;
+ priv->encr_keys[index].cipher = cipher;
+ memcpy(&priv->encr_keys[index].material, key, key_len);
+ memset(&priv->encr_keys[index].bssid, 0xff, ETH_ALEN);
return 0;
}
-
static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
- int index, const struct sockaddr *addr,
- const u8 *rx_seq, int alg, int flags)
+ int index, const u8 *addr, const u8 *rx_seq,
+ int seq_len, u32 cipher, __le32 flags)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
struct ndis_80211_key ndis_key;
+ bool is_addr_ok;
int ret;
- if (index < 0 || index >= 4)
- return -EINVAL;
- if (key_len > sizeof(ndis_key.material) || key_len < 0)
+ if (index < 0 || index >= 4) {
+ devdbg(usbdev, "add_wpa_key: index out of range (%i)", index);
return -EINVAL;
- if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq)
+ }
+ if (key_len > sizeof(ndis_key.material) || key_len < 0) {
+ devdbg(usbdev, "add_wpa_key: key length out of range (%i)",
+ key_len);
return -EINVAL;
- if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !addr)
+ }
+ if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) {
+ if (!rx_seq || seq_len <= 0) {
+ devdbg(usbdev, "add_wpa_key: recv seq flag without"
+ "buffer");
+ return -EINVAL;
+ }
+ if (rx_seq && seq_len > sizeof(ndis_key.rsc)) {
+ devdbg(usbdev, "add_wpa_key: too big recv seq buffer");
+ return -EINVAL;
+ }
+ }
+
+ is_addr_ok = addr && !is_zero_ether_addr(addr) &&
+ !is_broadcast_ether_addr(addr);
+ if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) {
+ devdbg(usbdev, "add_wpa_key: pairwise but bssid invalid (%pM)",
+ addr);
return -EINVAL;
+ }
devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index,
!!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY),
@@ -1064,7 +1344,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
ndis_key.length = cpu_to_le32(key_len);
ndis_key.index = cpu_to_le32(index) | flags;
- if (alg == IW_ENCODE_ALG_TKIP && key_len == 32) {
+ if (cipher == WLAN_CIPHER_SUITE_TKIP && key_len == 32) {
/* wpa_supplicant gives us the Michael MIC RX/TX keys in
* different order than NDIS spec, so swap the order here. */
memcpy(ndis_key.material, key, 16);
@@ -1074,11 +1354,11 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
memcpy(ndis_key.material, key, key_len);
if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ)
- memcpy(ndis_key.rsc, rx_seq, 6);
+ memcpy(ndis_key.rsc, rx_seq, seq_len);
if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) {
/* pairwise key */
- memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN);
+ memcpy(ndis_key.bssid, addr, ETH_ALEN);
} else {
/* group key */
if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
@@ -1093,8 +1373,14 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
if (ret != 0)
return ret;
- priv->encr_key_len[index] = key_len;
- priv->encr_key_wpa[index] = 1;
+ memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index]));
+ priv->encr_keys[index].len = key_len;
+ priv->encr_keys[index].cipher = cipher;
+ memcpy(&priv->encr_keys[index].material, key, key_len);
+ if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY)
+ memcpy(&priv->encr_keys[index].bssid, ndis_key.bssid, ETH_ALEN);
+ else
+ memset(&priv->encr_keys[index].bssid, 0xff, ETH_ALEN);
if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY)
priv->encr_tx_key_index = index;
@@ -1102,31 +1388,62 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
return 0;
}
+static int restore_key(struct usbnet *usbdev, int key_idx)
+{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ struct rndis_wlan_encr_key key;
+
+ if (is_wpa_key(priv, key_idx))
+ return 0;
+
+ key = priv->encr_keys[key_idx];
+
+ devdbg(usbdev, "restore_key: %i:%i", key_idx, key.len);
+
+ if (key.len == 0)
+ return 0;
+
+ return add_wep_key(usbdev, key.material, key.len, key_idx);
+}
+
+static void restore_keys(struct usbnet *usbdev)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ restore_key(usbdev, i);
+}
+
+static void clear_key(struct rndis_wlan_private *priv, int idx)
+{
+ memset(&priv->encr_keys[idx], 0, sizeof(priv->encr_keys[idx]));
+}
/* remove_key is for both wep and wpa */
-static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN])
+static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
struct ndis_80211_remove_key remove_key;
__le32 keyindex;
+ bool is_wpa;
int ret;
- if (priv->encr_key_len[index] == 0)
+ if (priv->encr_keys[index].len == 0)
return 0;
- priv->encr_key_len[index] = 0;
- priv->encr_key_wpa[index] = 0;
- memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index]));
+ is_wpa = is_wpa_key(priv, index);
+
+ devdbg(usbdev, "remove_key: %i:%s:%i", index, is_wpa ? "wpa" : "wep",
+ priv->encr_keys[index].len);
- if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP ||
- priv->wpa_cipher_pair == IW_AUTH_CIPHER_CCMP ||
- priv->wpa_cipher_group == IW_AUTH_CIPHER_TKIP ||
- priv->wpa_cipher_group == IW_AUTH_CIPHER_CCMP) {
+ clear_key(priv, index);
+
+ if (is_wpa) {
remove_key.size = cpu_to_le32(sizeof(remove_key));
remove_key.index = cpu_to_le32(index);
if (bssid) {
/* pairwise key */
- if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0)
+ if (!is_broadcast_ether_addr(bssid))
remove_key.index |=
NDIS_80211_ADDKEY_PAIRWISE_KEY;
memcpy(remove_key.bssid, bssid,
@@ -1153,12 +1470,11 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN])
/* if it is transmit key, disable encryption */
if (index == priv->encr_tx_key_index)
- set_encr_mode(usbdev, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE);
+ set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE);
return 0;
}
-
static void set_multicast_list(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
@@ -1218,24 +1534,18 @@ static void set_multicast_list(struct usbnet *usbdev)
le32_to_cpu(filter), ret);
}
-
/*
* cfg80211 ops
*/
-static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
+static int rndis_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
- struct net_device *dev;
- struct usbnet *usbdev;
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
int mode;
- /* we're under RTNL */
- dev = __dev_get_by_index(&init_net, ifindex);
- if (!dev)
- return -ENODEV;
- usbdev = netdev_priv(dev);
-
switch (type) {
case NL80211_IFTYPE_ADHOC:
mode = NDIS_80211_INFRA_ADHOC;
@@ -1247,11 +1557,67 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
return -EINVAL;
}
+ priv->wdev.iftype = type;
+
return set_infra_mode(usbdev, mode);
}
+static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+ int err;
+
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ err = set_frag_threshold(usbdev, wiphy->frag_threshold);
+ if (err < 0)
+ return err;
+ }
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ err = set_rts_threshold(usbdev, wiphy->rts_threshold);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
+ int dbm)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+
+ devdbg(usbdev, "rndis_set_tx_power type:0x%x dbm:%i", type, dbm);
-#define SCAN_DELAY_JIFFIES (HZ)
+ /* Device doesn't support changing txpower after initialization, only
+ * turn off/on radio. Support 'auto' mode and setting same dBm that is
+ * currently used.
+ */
+ if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) {
+ if (!priv->radio_on)
+ disassociate(usbdev, true); /* turn on radio */
+
+ return 0;
+ }
+
+ return -ENOTSUPP;
+}
+
+static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+
+ *dbm = get_bcm4320_power_dbm(priv);
+
+ devdbg(usbdev, "rndis_get_tx_power dbm:%i", *dbm);
+
+ return 0;
+}
+
+#define SCAN_DELAY_JIFFIES (6 * HZ)
static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request)
{
@@ -1262,6 +1628,11 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
devdbg(usbdev, "cfg80211.scan");
+ /* Get current bssid list from device before new scan, as new scan
+ * clears internal bssid list.
+ */
+ rndis_check_bssid_list(usbdev);
+
if (!request)
return -EINVAL;
@@ -1282,7 +1653,6 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
return ret;
}
-
static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
struct ndis_80211_bssid_ex *bssid)
{
@@ -1296,6 +1666,9 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
int ie_len, bssid_len;
u8 *ie;
+ devdbg(usbdev, " found bssid: '%.32s' [%pM]", bssid->ssid.essid,
+ bssid->mac);
+
/* parse bssid structure */
bssid_len = le32_to_cpu(bssid->length);
@@ -1328,17 +1701,18 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
GFP_KERNEL);
}
-
static int rndis_check_bssid_list(struct usbnet *usbdev)
{
void *buf = NULL;
struct ndis_80211_bssid_list_ex *bssid_list;
struct ndis_80211_bssid_ex *bssid;
int ret = -EINVAL, len, count, bssid_len;
+ bool resized = false;
devdbg(usbdev, "check_bssid_list");
len = CONTROL_BUFFER_SIZE;
+resize_buf:
buf = kmalloc(len, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
@@ -1349,11 +1723,18 @@ static int rndis_check_bssid_list(struct usbnet *usbdev)
if (ret != 0)
goto out;
+ if (!resized && len > CONTROL_BUFFER_SIZE) {
+ resized = true;
+ kfree(buf);
+ goto resize_buf;
+ }
+
bssid_list = buf;
bssid = bssid_list->bssid;
bssid_len = le32_to_cpu(bssid->length);
count = le32_to_cpu(bssid_list->num_items);
- devdbg(usbdev, "check_bssid_list: %d BSSIDs found", count);
+ devdbg(usbdev, "check_bssid_list: %d BSSIDs found (buflen: %d)", count,
+ len);
while (count && ((void *)bssid + bssid_len) <= (buf + len)) {
rndis_bss_info_update(usbdev, bssid);
@@ -1368,7 +1749,6 @@ out:
return ret;
}
-
static void rndis_get_scan_results(struct work_struct *work)
{
struct rndis_wlan_private *priv =
@@ -1378,6 +1758,9 @@ static void rndis_get_scan_results(struct work_struct *work)
devdbg(usbdev, "get_scan_results");
+ if (!priv->scan_request)
+ return;
+
ret = rndis_check_bssid_list(usbdev);
cfg80211_scan_done(priv->scan_request, ret < 0);
@@ -1385,761 +1768,718 @@ static void rndis_get_scan_results(struct work_struct *work)
priv->scan_request = NULL;
}
-
-/*
- * wireless extension handlers
- */
-
-static int rndis_iw_commit(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- /* dummy op */
- return 0;
-}
-
-
-static int rndis_iw_set_essid(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
+static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+ struct ieee80211_channel *channel = sme->channel;
struct ndis_80211_ssid ssid;
- int length = wrqu->essid.length;
- struct usbnet *usbdev = netdev_priv(dev);
+ int pairwise = RNDIS_WLAN_ALG_NONE;
+ int groupwise = RNDIS_WLAN_ALG_NONE;
+ int keymgmt = RNDIS_WLAN_KEY_MGMT_NONE;
+ int length, i, ret, chan = -1;
+
+ if (channel)
+ chan = ieee80211_frequency_to_channel(channel->center_freq);
+
+ groupwise = rndis_cipher_to_alg(sme->crypto.cipher_group);
+ for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++)
+ pairwise |=
+ rndis_cipher_to_alg(sme->crypto.ciphers_pairwise[i]);
+
+ if (sme->crypto.n_ciphers_pairwise > 0 &&
+ pairwise == RNDIS_WLAN_ALG_NONE) {
+ deverr(usbdev, "Unsupported pairwise cipher");
+ return -ENOTSUPP;
+ }
- devdbg(usbdev, "SIOCSIWESSID: [flags:%d,len:%d] '%.32s'",
- wrqu->essid.flags, wrqu->essid.length, essid);
+ for (i = 0; i < sme->crypto.n_akm_suites; i++)
+ keymgmt |=
+ rndis_akm_suite_to_key_mgmt(sme->crypto.akm_suites[i]);
- if (length > NDIS_802_11_LENGTH_SSID)
- length = NDIS_802_11_LENGTH_SSID;
+ if (sme->crypto.n_akm_suites > 0 &&
+ keymgmt == RNDIS_WLAN_KEY_MGMT_NONE) {
+ deverr(usbdev, "Invalid keymgmt");
+ return -ENOTSUPP;
+ }
- ssid.length = cpu_to_le32(length);
- if (length > 0)
- memcpy(ssid.essid, essid, length);
- else
- memset(ssid.essid, 0, NDIS_802_11_LENGTH_SSID);
+ devdbg(usbdev, "cfg80211.connect('%.32s':[%pM]:%d:[%d,0x%x:0x%x]:[0x%x:"
+ "0x%x]:0x%x)", sme->ssid, sme->bssid, chan,
+ sme->privacy, sme->crypto.wpa_versions, sme->auth_type,
+ groupwise, pairwise, keymgmt);
- set_assoc_params(usbdev);
+ if (is_associated(usbdev))
+ disassociate(usbdev, false);
- if (!wrqu->essid.flags || length == 0)
- return disassociate(usbdev, 1);
- else
- return set_essid(usbdev, &ssid);
-}
+ ret = set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA);
+ if (ret < 0) {
+ devdbg(usbdev, "connect: set_infra_mode failed, %d", ret);
+ goto err_turn_radio_on;
+ }
+ ret = set_auth_mode(usbdev, sme->crypto.wpa_versions, sme->auth_type,
+ keymgmt);
+ if (ret < 0) {
+ devdbg(usbdev, "connect: set_auth_mode failed, %d", ret);
+ goto err_turn_radio_on;
+ }
-static int rndis_iw_get_essid(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
-{
- struct ndis_80211_ssid ssid;
- struct usbnet *usbdev = netdev_priv(dev);
- int ret;
+ set_priv_filter(usbdev);
- ret = get_essid(usbdev, &ssid);
+ ret = set_encr_mode(usbdev, pairwise, groupwise);
+ if (ret < 0) {
+ devdbg(usbdev, "connect: set_encr_mode failed, %d", ret);
+ goto err_turn_radio_on;
+ }
- if (ret == 0 && le32_to_cpu(ssid.length) > 0) {
- wrqu->essid.flags = 1;
- wrqu->essid.length = le32_to_cpu(ssid.length);
- memcpy(essid, ssid.essid, wrqu->essid.length);
- essid[wrqu->essid.length] = 0;
- } else {
- memset(essid, 0, sizeof(NDIS_802_11_LENGTH_SSID));
- wrqu->essid.flags = 0;
- wrqu->essid.length = 0;
+ if (channel) {
+ ret = set_channel(usbdev, chan);
+ if (ret < 0) {
+ devdbg(usbdev, "connect: set_channel failed, %d", ret);
+ goto err_turn_radio_on;
+ }
}
- devdbg(usbdev, "SIOCGIWESSID: %s", essid);
- return ret;
-}
+ if (sme->key && ((groupwise | pairwise) & RNDIS_WLAN_ALG_WEP)) {
+ priv->encr_tx_key_index = sme->key_idx;
+ ret = add_wep_key(usbdev, sme->key, sme->key_len, sme->key_idx);
+ if (ret < 0) {
+ devdbg(usbdev, "connect: add_wep_key failed, %d "
+ "(%d, %d)", ret, sme->key_len, sme->key_idx);
+ goto err_turn_radio_on;
+ }
+ }
-static int rndis_iw_get_bssid(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- unsigned char bssid[ETH_ALEN];
- int ret;
+ if (sme->bssid && !is_zero_ether_addr(sme->bssid) &&
+ !is_broadcast_ether_addr(sme->bssid)) {
+ ret = set_bssid(usbdev, sme->bssid);
+ if (ret < 0) {
+ devdbg(usbdev, "connect: set_bssid failed, %d", ret);
+ goto err_turn_radio_on;
+ }
+ } else
+ clear_bssid(usbdev);
- ret = get_bssid(usbdev, bssid);
+ length = sme->ssid_len;
+ if (length > NDIS_802_11_LENGTH_SSID)
+ length = NDIS_802_11_LENGTH_SSID;
- if (ret == 0)
- devdbg(usbdev, "SIOCGIWAP: %pM", bssid);
- else
- devdbg(usbdev, "SIOCGIWAP: <not associated>");
+ memset(&ssid, 0, sizeof(ssid));
+ ssid.length = cpu_to_le32(length);
+ memcpy(ssid.essid, sme->ssid, length);
- wrqu->ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu->ap_addr.sa_data, bssid, ETH_ALEN);
+ /* Pause and purge rx queue, so we don't pass packets before
+ * 'media connect'-indication.
+ */
+ usbnet_pause_rx(usbdev);
+ usbnet_purge_paused_rxq(usbdev);
+ ret = set_essid(usbdev, &ssid);
+ if (ret < 0)
+ devdbg(usbdev, "connect: set_essid failed, %d", ret);
return ret;
-}
+err_turn_radio_on:
+ disassociate(usbdev, true);
-static int rndis_iw_set_bssid(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- u8 *bssid = (u8 *)wrqu->ap_addr.sa_data;
- int ret;
+ return ret;
+}
- devdbg(usbdev, "SIOCSIWAP: %pM", bssid);
+static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
- ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN);
+ devdbg(usbdev, "cfg80211.disconnect(%d)", reason_code);
- /* user apps may set ap's mac address, which is not required;
- * they may fail to work if this function fails, so return
- * success */
- if (ret)
- devwarn(usbdev, "setting AP mac address failed (%08X)", ret);
+ priv->connected = false;
+ memset(priv->bssid, 0, ETH_ALEN);
- return 0;
+ return deauthenticate(usbdev);
}
-
-static int rndis_iw_set_auth(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params)
{
- struct iw_param *p = &wrqu->param;
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- int ret = -ENOTSUPP;
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+ struct ieee80211_channel *channel = params->channel;
+ struct ndis_80211_ssid ssid;
+ enum nl80211_auth_type auth_type;
+ int ret, alg, length, chan = -1;
- switch (p->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- devdbg(usbdev, "SIOCSIWAUTH: WPA_VERSION, %08x", p->value);
- priv->wpa_version = p->value;
- ret = 0;
- break;
+ if (channel)
+ chan = ieee80211_frequency_to_channel(channel->center_freq);
- case IW_AUTH_CIPHER_PAIRWISE:
- devdbg(usbdev, "SIOCSIWAUTH: CIPHER_PAIRWISE, %08x", p->value);
- priv->wpa_cipher_pair = p->value;
- ret = 0;
- break;
+ /* TODO: How to handle ad-hoc encryption?
+ * connect() has *key, join_ibss() doesn't. RNDIS requires key to be
+ * pre-shared for encryption (open/shared/wpa), is key set before
+ * join_ibss? Which auth_type to use (not in params)? What about WPA?
+ */
+ if (params->privacy) {
+ auth_type = NL80211_AUTHTYPE_SHARED_KEY;
+ alg = RNDIS_WLAN_ALG_WEP;
+ } else {
+ auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+ alg = RNDIS_WLAN_ALG_NONE;
+ }
- case IW_AUTH_CIPHER_GROUP:
- devdbg(usbdev, "SIOCSIWAUTH: CIPHER_GROUP, %08x", p->value);
- priv->wpa_cipher_group = p->value;
- ret = 0;
- break;
+ devdbg(usbdev, "cfg80211.join_ibss('%.32s':[%pM]:%d:%d)", params->ssid,
+ params->bssid, chan, params->privacy);
- case IW_AUTH_KEY_MGMT:
- devdbg(usbdev, "SIOCSIWAUTH: KEY_MGMT, %08x", p->value);
- priv->wpa_keymgmt = p->value;
- ret = 0;
- break;
+ if (is_associated(usbdev))
+ disassociate(usbdev, false);
- case IW_AUTH_TKIP_COUNTERMEASURES:
- devdbg(usbdev, "SIOCSIWAUTH: TKIP_COUNTERMEASURES, %08x",
- p->value);
- ret = 0;
- break;
+ ret = set_infra_mode(usbdev, NDIS_80211_INFRA_ADHOC);
+ if (ret < 0) {
+ devdbg(usbdev, "join_ibss: set_infra_mode failed, %d", ret);
+ goto err_turn_radio_on;
+ }
- case IW_AUTH_DROP_UNENCRYPTED:
- devdbg(usbdev, "SIOCSIWAUTH: DROP_UNENCRYPTED, %08x", p->value);
- ret = 0;
- break;
+ ret = set_auth_mode(usbdev, 0, auth_type, RNDIS_WLAN_KEY_MGMT_NONE);
+ if (ret < 0) {
+ devdbg(usbdev, "join_ibss: set_auth_mode failed, %d", ret);
+ goto err_turn_radio_on;
+ }
- case IW_AUTH_80211_AUTH_ALG:
- devdbg(usbdev, "SIOCSIWAUTH: 80211_AUTH_ALG, %08x", p->value);
- priv->wpa_authalg = p->value;
- ret = 0;
- break;
+ set_priv_filter(usbdev);
- case IW_AUTH_WPA_ENABLED:
- devdbg(usbdev, "SIOCSIWAUTH: WPA_ENABLED, %08x", p->value);
- if (wrqu->param.value)
- deauthenticate(usbdev);
- ret = 0;
- break;
+ ret = set_encr_mode(usbdev, alg, RNDIS_WLAN_ALG_NONE);
+ if (ret < 0) {
+ devdbg(usbdev, "join_ibss: set_encr_mode failed, %d", ret);
+ goto err_turn_radio_on;
+ }
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- devdbg(usbdev, "SIOCSIWAUTH: RX_UNENCRYPTED_EAPOL, %08x",
- p->value);
- ret = 0;
- break;
+ if (channel) {
+ ret = set_channel(usbdev, chan);
+ if (ret < 0) {
+ devdbg(usbdev, "join_ibss: set_channel failed, %d",
+ ret);
+ goto err_turn_radio_on;
+ }
+ }
- case IW_AUTH_ROAMING_CONTROL:
- devdbg(usbdev, "SIOCSIWAUTH: ROAMING_CONTROL, %08x", p->value);
- ret = 0;
- break;
+ if (params->bssid && !is_zero_ether_addr(params->bssid) &&
+ !is_broadcast_ether_addr(params->bssid)) {
+ ret = set_bssid(usbdev, params->bssid);
+ if (ret < 0) {
+ devdbg(usbdev, "join_ibss: set_bssid failed, %d", ret);
+ goto err_turn_radio_on;
+ }
+ } else
+ clear_bssid(usbdev);
- case IW_AUTH_PRIVACY_INVOKED:
- devdbg(usbdev, "SIOCSIWAUTH: invalid cmd %d",
- wrqu->param.flags & IW_AUTH_INDEX);
- return -EOPNOTSUPP;
+ length = params->ssid_len;
+ if (length > NDIS_802_11_LENGTH_SSID)
+ length = NDIS_802_11_LENGTH_SSID;
- default:
- devdbg(usbdev, "SIOCSIWAUTH: UNKNOWN %08x, %08x",
- p->flags & IW_AUTH_INDEX, p->value);
- }
- return ret;
-}
+ memset(&ssid, 0, sizeof(ssid));
+ ssid.length = cpu_to_le32(length);
+ memcpy(ssid.essid, params->ssid, length);
+ /* Don't need to pause rx queue for ad-hoc. */
+ usbnet_purge_paused_rxq(usbdev);
+ usbnet_resume_rx(usbdev);
-static int rndis_iw_get_auth(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *p = &wrqu->param;
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ ret = set_essid(usbdev, &ssid);
+ if (ret < 0)
+ devdbg(usbdev, "join_ibss: set_essid failed, %d", ret);
+ return ret;
- switch (p->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- p->value = priv->wpa_version;
- break;
- case IW_AUTH_CIPHER_PAIRWISE:
- p->value = priv->wpa_cipher_pair;
- break;
- case IW_AUTH_CIPHER_GROUP:
- p->value = priv->wpa_cipher_group;
- break;
- case IW_AUTH_KEY_MGMT:
- p->value = priv->wpa_keymgmt;
- break;
- case IW_AUTH_80211_AUTH_ALG:
- p->value = priv->wpa_authalg;
- break;
- default:
- devdbg(usbdev, "SIOCGIWAUTH: invalid cmd %d",
- wrqu->param.flags & IW_AUTH_INDEX);
- return -EOPNOTSUPP;
- }
- return 0;
-}
+err_turn_radio_on:
+ disassociate(usbdev, true);
+ return ret;
+}
-static int rndis_iw_set_encode(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- int ret, index, key_len;
- u8 *key;
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
- index = (wrqu->encoding.flags & IW_ENCODE_INDEX);
+ devdbg(usbdev, "cfg80211.leave_ibss()");
- /* iwconfig gives index as 1 - N */
- if (index > 0)
- index--;
- else
- index = priv->encr_tx_key_index;
+ priv->connected = false;
+ memset(priv->bssid, 0, ETH_ALEN);
- if (index < 0 || index >= 4) {
- devwarn(usbdev, "encryption index out of range (%u)", index);
- return -EINVAL;
- }
+ return deauthenticate(usbdev);
+}
- /* remove key if disabled */
- if (wrqu->data.flags & IW_ENCODE_DISABLED) {
- if (remove_key(usbdev, index, NULL))
- return -EINVAL;
- else
- return 0;
- }
+static int rndis_set_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan, enum nl80211_channel_type channel_type)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
- /* global encryption state (for all keys) */
- if (wrqu->data.flags & IW_ENCODE_OPEN)
- ret = set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED,
- IW_AUTH_ALG_OPEN_SYSTEM);
- else /*if (wrqu->data.flags & IW_ENCODE_RESTRICTED)*/
- ret = set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED,
- IW_AUTH_ALG_SHARED_KEY);
- if (ret != 0)
- return ret;
+ return set_channel(usbdev,
+ ieee80211_frequency_to_channel(chan->center_freq));
+}
- if (wrqu->data.length > 0) {
- key_len = wrqu->data.length;
- key = extra;
- } else {
- /* must be set as tx key */
- if (priv->encr_key_len[index] == 0)
- return -EINVAL;
- key_len = priv->encr_key_len[index];
- key = priv->encr_keys[index];
- priv->encr_tx_key_index = index;
+static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, const u8 *mac_addr,
+ struct key_params *params)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+ __le32 flags;
+
+ devdbg(usbdev, "rndis_add_key(%i, %pM, %08x)", key_index, mac_addr,
+ params->cipher);
+
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ return add_wep_key(usbdev, params->key, params->key_len,
+ key_index);
+ case WLAN_CIPHER_SUITE_TKIP:
+ case WLAN_CIPHER_SUITE_CCMP:
+ flags = 0;
+
+ if (params->seq && params->seq_len > 0)
+ flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ;
+ if (mac_addr)
+ flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY |
+ NDIS_80211_ADDKEY_TRANSMIT_KEY;
+
+ return add_wpa_key(usbdev, params->key, params->key_len,
+ key_index, mac_addr, params->seq,
+ params->seq_len, params->cipher, flags);
+ default:
+ devdbg(usbdev, "rndis_add_key: unsupported cipher %08x",
+ params->cipher);
+ return -ENOTSUPP;
}
-
- if (add_wep_key(usbdev, key, key_len, index) != 0)
- return -EINVAL;
-
- if (index == priv->encr_tx_key_index)
- /* ndis drivers want essid to be set after setting encr */
- set_essid(usbdev, &priv->essid);
-
- return 0;
}
-
-static int rndis_iw_set_encode_ext(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, const u8 *mac_addr)
{
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- int keyidx, flags;
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
- keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX;
+ devdbg(usbdev, "rndis_del_key(%i, %pM)", key_index, mac_addr);
- /* iwconfig gives index as 1 - N */
- if (keyidx)
- keyidx--;
- else
- keyidx = priv->encr_tx_key_index;
+ return remove_key(usbdev, key_index, mac_addr);
+}
- if (keyidx < 0 || keyidx >= 4)
- return -EINVAL;
+static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+ struct rndis_wlan_encr_key key;
- if (ext->alg == WPA_ALG_WEP) {
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
- priv->encr_tx_key_index = keyidx;
- return add_wep_key(usbdev, ext->key, ext->key_len, keyidx);
- }
+ devdbg(usbdev, "rndis_set_default_key(%i)", key_index);
- if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) ||
- ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0)
- return remove_key(usbdev, keyidx, NULL);
+ priv->encr_tx_key_index = key_index;
- flags = 0;
- if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
- flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ;
- if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY))
- flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY;
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
- flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY;
+ key = priv->encr_keys[key_index];
- return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr,
- ext->rx_seq, ext->alg, flags);
+ return add_wep_key(usbdev, key.material, key.len, key_index);
}
-
-static int rndis_iw_set_genie(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+static void rndis_fill_station_info(struct usbnet *usbdev,
+ struct station_info *sinfo)
{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- int ret = 0;
+ __le32 linkspeed, rssi;
+ int ret, len;
-#ifdef DEBUG
- int j;
- u8 *gie = extra;
- for (j = 0; j < wrqu->data.length; j += 8)
- devdbg(usbdev,
- "SIOCSIWGENIE %04x - "
- "%02x %02x %02x %02x %02x %02x %02x %02x", j,
- gie[j + 0], gie[j + 1], gie[j + 2], gie[j + 3],
- gie[j + 4], gie[j + 5], gie[j + 6], gie[j + 7]);
-#endif
- /* clear existing IEs */
- if (priv->wpa_ie_len) {
- kfree(priv->wpa_ie);
- priv->wpa_ie_len = 0;
+ memset(sinfo, 0, sizeof(*sinfo));
+
+ len = sizeof(linkspeed);
+ ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &linkspeed, &len);
+ if (ret == 0) {
+ sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000;
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
}
- /* set new IEs */
- priv->wpa_ie = kmalloc(wrqu->data.length, GFP_KERNEL);
- if (priv->wpa_ie) {
- priv->wpa_ie_len = wrqu->data.length;
- memcpy(priv->wpa_ie, extra, priv->wpa_ie_len);
- } else
- ret = -ENOMEM;
- return ret;
+ len = sizeof(rssi);
+ ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len);
+ if (ret == 0) {
+ sinfo->signal = level_to_qual(le32_to_cpu(rssi));
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ }
}
-
-static int rndis_iw_get_genie(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_info *sinfo)
{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
-
- devdbg(usbdev, "SIOCGIWGENIE");
-
- if (priv->wpa_ie_len == 0 || priv->wpa_ie == NULL) {
- wrqu->data.length = 0;
- return 0;
- }
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
- if (wrqu->data.length < priv->wpa_ie_len)
- return -E2BIG;
+ if (compare_ether_addr(priv->bssid, mac))
+ return -ENOENT;
- wrqu->data.length = priv->wpa_ie_len;
- memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
+ rndis_fill_station_info(usbdev, sinfo);
return 0;
}
-
-static int rndis_iw_set_rts(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *mac, struct station_info *sinfo)
{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
- devdbg(usbdev, "SIOCSIWRTS");
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
- tmp = cpu_to_le32(wrqu->rts.value);
- return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp,
- sizeof(tmp));
-}
+ if (idx != 0)
+ return -ENOENT;
+
+ memcpy(mac, priv->bssid, ETH_ALEN);
+ rndis_fill_station_info(usbdev, sinfo);
-static int rndis_iw_get_rts(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+ return 0;
+}
+
+/*
+ * workers, indication handlers, device poller
+ */
+static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
- int len, ret;
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ struct ndis_80211_assoc_info *info;
+ u8 assoc_buf[sizeof(*info) + IW_CUSTOM_MAX + 32];
+ u8 bssid[ETH_ALEN];
+ int resp_ie_len, req_ie_len;
+ u8 *req_ie, *resp_ie;
+ int ret, offset;
+ bool roamed = false;
- len = sizeof(tmp);
- ret = rndis_query_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, &len);
- if (ret == 0) {
- wrqu->rts.value = le32_to_cpu(tmp);
- wrqu->rts.flags = 1;
- wrqu->rts.disabled = 0;
+ if (priv->infra_mode == NDIS_80211_INFRA_INFRA && priv->connected) {
+ /* received media connect indication while connected, either
+ * device reassociated with same AP or roamed to new. */
+ roamed = true;
}
- devdbg(usbdev, "SIOCGIWRTS: %d", wrqu->rts.value);
+ req_ie_len = 0;
+ resp_ie_len = 0;
+ req_ie = NULL;
+ resp_ie = NULL;
- return ret;
-}
+ if (priv->infra_mode == NDIS_80211_INFRA_INFRA) {
+ memset(assoc_buf, 0, sizeof(assoc_buf));
+ info = (void *)assoc_buf;
+ /* Get association info IEs from device and send them back to
+ * userspace. */
+ ret = get_association_info(usbdev, info, sizeof(assoc_buf));
+ if (!ret) {
+ req_ie_len = le32_to_cpu(info->req_ie_length);
+ if (req_ie_len > 0) {
+ offset = le32_to_cpu(info->offset_req_ies);
+ req_ie = (u8 *)info + offset;
+ }
-static int rndis_iw_set_frag(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
+ resp_ie_len = le32_to_cpu(info->resp_ie_length);
+ if (resp_ie_len > 0) {
+ offset = le32_to_cpu(info->offset_resp_ies);
+ resp_ie = (u8 *)info + offset;
+ }
+ }
+ } else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC))
+ return;
- devdbg(usbdev, "SIOCSIWFRAG");
+ ret = get_bssid(usbdev, bssid);
+ if (ret < 0)
+ memset(bssid, 0, sizeof(bssid));
- tmp = cpu_to_le32(wrqu->frag.value);
- return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
- sizeof(tmp));
-}
+ devdbg(usbdev, "link up work: [%pM] %s", bssid, roamed ? "roamed" : "");
+ /* Internal bss list in device always contains at least the currently
+ * connected bss and we can get it to cfg80211 with
+ * rndis_check_bssid_list().
+ * NOTE: This is true for Broadcom chip, but not mentioned in RNDIS
+ * spec.
+ */
+ rndis_check_bssid_list(usbdev);
-static int rndis_iw_get_frag(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
- int len, ret;
+ if (priv->infra_mode == NDIS_80211_INFRA_INFRA) {
+ if (!roamed)
+ cfg80211_connect_result(usbdev->net, bssid, req_ie,
+ req_ie_len, resp_ie,
+ resp_ie_len, 0, GFP_KERNEL);
+ else
+ cfg80211_roamed(usbdev->net, bssid, req_ie, req_ie_len,
+ resp_ie, resp_ie_len, GFP_KERNEL);
+ } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
+ cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
- len = sizeof(tmp);
- ret = rndis_query_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
- &len);
- if (ret == 0) {
- wrqu->frag.value = le32_to_cpu(tmp);
- wrqu->frag.flags = 1;
- wrqu->frag.disabled = 0;
- }
- devdbg(usbdev, "SIOCGIWFRAG: %d", wrqu->frag.value);
- return ret;
-}
+ priv->connected = true;
+ memcpy(priv->bssid, bssid, ETH_ALEN);
+ usbnet_resume_rx(usbdev);
+ netif_carrier_on(usbdev->net);
+}
-static int rndis_iw_set_freq(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+static void rndis_wlan_do_link_down_work(struct usbnet *usbdev)
{
- struct usbnet *usbdev = netdev_priv(dev);
- struct ndis_80211_conf config;
- unsigned int dsconfig;
- int len, ret;
-
- /* this OID is valid only when not associated */
- if (is_associated(usbdev))
- return 0;
-
- dsconfig = 0;
- if (freq_to_dsconfig(&wrqu->freq, &dsconfig))
- return -EINVAL;
-
- len = sizeof(config);
- ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len);
- if (ret != 0) {
- devdbg(usbdev, "SIOCSIWFREQ: querying configuration failed");
- return 0;
- }
+ union iwreq_data evt;
- config.ds_config = cpu_to_le32(dsconfig);
+ netif_carrier_off(usbdev->net);
- devdbg(usbdev, "SIOCSIWFREQ: %d * 10^%d", wrqu->freq.m, wrqu->freq.e);
- return rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config,
- sizeof(config));
+ evt.data.flags = 0;
+ evt.data.length = 0;
+ memset(evt.ap_addr.sa_data, 0, ETH_ALEN);
+ wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
}
-
-static int rndis_iw_get_freq(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+static void rndis_wlan_worker(struct work_struct *work)
{
- struct usbnet *usbdev = netdev_priv(dev);
- struct ndis_80211_conf config;
- int len, ret;
+ struct rndis_wlan_private *priv =
+ container_of(work, struct rndis_wlan_private, work);
+ struct usbnet *usbdev = priv->usbdev;
- len = sizeof(config);
- ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len);
- if (ret == 0)
- dsconfig_to_freq(le32_to_cpu(config.ds_config), &wrqu->freq);
+ if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending))
+ rndis_wlan_do_link_up_work(usbdev);
- devdbg(usbdev, "SIOCGIWFREQ: %d", wrqu->freq.m);
- return ret;
-}
+ if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending))
+ rndis_wlan_do_link_down_work(usbdev);
+ if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
+ set_multicast_list(usbdev);
+}
-static int rndis_iw_get_txpower(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+static void rndis_wlan_set_multicast_list(struct net_device *dev)
{
struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- __le32 tx_power;
-
- if (priv->radio_on) {
- /* fake since changing tx_power (by userlevel) not supported */
- tx_power = cpu_to_le32(get_bcm4320_power(priv));
- wrqu->txpower.flags = IW_TXPOW_MWATT;
- wrqu->txpower.value = le32_to_cpu(tx_power);
- wrqu->txpower.disabled = 0;
- } else {
- wrqu->txpower.flags = IW_TXPOW_MWATT;
- wrqu->txpower.value = 0;
- wrqu->txpower.disabled = 1;
- }
-
- devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value);
+ if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
+ return;
- return 0;
+ set_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending);
+ queue_work(priv->workqueue, &priv->work);
}
-
-static int rndis_iw_set_txpower(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+static void rndis_wlan_auth_indication(struct usbnet *usbdev,
+ struct ndis_80211_status_indication *indication,
+ int len)
{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- __le32 tx_power = 0;
-
- if (!wrqu->txpower.disabled) {
- if (wrqu->txpower.flags == IW_TXPOW_MWATT)
- tx_power = cpu_to_le32(wrqu->txpower.value);
- else { /* wrqu->txpower.flags == IW_TXPOW_DBM */
- if (wrqu->txpower.value > 20)
- tx_power = cpu_to_le32(128);
- else if (wrqu->txpower.value < -43)
- tx_power = cpu_to_le32(127);
- else {
- signed char tmp;
- tmp = wrqu->txpower.value;
- tmp = -12 - tmp;
- tmp <<= 2;
- tx_power = cpu_to_le32((unsigned char)tmp);
- }
- }
+ u8 *buf;
+ const char *type;
+ int flags, buflen, key_id;
+ bool pairwise_error, group_error;
+ struct ndis_80211_auth_request *auth_req;
+ enum nl80211_key_type key_type;
+
+ /* must have at least one array entry */
+ if (len < offsetof(struct ndis_80211_status_indication, u) +
+ sizeof(struct ndis_80211_auth_request)) {
+ devinfo(usbdev, "authentication indication: "
+ "too short message (%i)", len);
+ return;
}
- devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power));
+ buf = (void *)&indication->u.auth_request[0];
+ buflen = len - offsetof(struct ndis_80211_status_indication, u);
+
+ while (buflen >= sizeof(*auth_req)) {
+ auth_req = (void *)buf;
+ type = "unknown";
+ flags = le32_to_cpu(auth_req->flags);
+ pairwise_error = false;
+ group_error = false;
+
+ if (flags & 0x1)
+ type = "reauth request";
+ if (flags & 0x2)
+ type = "key update request";
+ if (flags & 0x6) {
+ pairwise_error = true;
+ type = "pairwise_error";
+ }
+ if (flags & 0xe) {
+ group_error = true;
+ type = "group_error";
+ }
- if (le32_to_cpu(tx_power) != 0) {
- /* txpower unsupported, just turn radio on */
- if (!priv->radio_on)
- return disassociate(usbdev, 1);
- return 0; /* all ready on */
- }
+ devinfo(usbdev, "authentication indication: %s (0x%08x)", type,
+ le32_to_cpu(auth_req->flags));
- /* tx_power == 0, turn off radio */
- return disassociate(usbdev, 0);
-}
+ if (pairwise_error) {
+ key_type = NL80211_KEYTYPE_PAIRWISE;
+ key_id = -1;
+ cfg80211_michael_mic_failure(usbdev->net,
+ auth_req->bssid,
+ key_type, key_id, NULL,
+ GFP_KERNEL);
+ }
-static int rndis_iw_get_rate(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
- int ret, len;
+ if (group_error) {
+ key_type = NL80211_KEYTYPE_GROUP;
+ key_id = -1;
- len = sizeof(tmp);
- ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &tmp, &len);
- if (ret == 0) {
- wrqu->bitrate.value = le32_to_cpu(tmp) * 100;
- wrqu->bitrate.disabled = 0;
- wrqu->bitrate.flags = 1;
+ cfg80211_michael_mic_failure(usbdev->net,
+ auth_req->bssid,
+ key_type, key_id, NULL,
+ GFP_KERNEL);
+ }
+
+ buflen -= le32_to_cpu(auth_req->length);
+ buf += le32_to_cpu(auth_req->length);
}
- return ret;
}
-
-static int rndis_iw_set_mlme(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev,
+ struct ndis_80211_status_indication *indication,
+ int len)
{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct iw_mlme *mlme = (struct iw_mlme *)extra;
- unsigned char bssid[ETH_ALEN];
+ struct ndis_80211_pmkid_cand_list *cand_list;
+ int list_len, expected_len, i;
- get_bssid(usbdev, bssid);
+ if (len < offsetof(struct ndis_80211_status_indication, u) +
+ sizeof(struct ndis_80211_pmkid_cand_list)) {
+ devinfo(usbdev, "pmkid candidate list indication: "
+ "too short message (%i)", len);
+ return;
+ }
- if (memcmp(bssid, mlme->addr.sa_data, ETH_ALEN))
- return -EINVAL;
+ list_len = le32_to_cpu(indication->u.cand_list.num_candidates) *
+ sizeof(struct ndis_80211_pmkid_candidate);
+ expected_len = sizeof(struct ndis_80211_pmkid_cand_list) + list_len +
+ offsetof(struct ndis_80211_status_indication, u);
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- return deauthenticate(usbdev);
- case IW_MLME_DISASSOC:
- return disassociate(usbdev, priv->radio_on);
- default:
- return -EOPNOTSUPP;
+ if (len < expected_len) {
+ devinfo(usbdev, "pmkid candidate list indication: "
+ "list larger than buffer (%i < %i)",
+ len, expected_len);
+ return;
}
- return 0;
-}
+ cand_list = &indication->u.cand_list;
+ devinfo(usbdev, "pmkid candidate list indication: "
+ "version %i, candidates %i",
+ le32_to_cpu(cand_list->version),
+ le32_to_cpu(cand_list->num_candidates));
-static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->stats_lock, flags);
- memcpy(&priv->iwstats, &priv->privstats, sizeof(priv->iwstats));
- spin_unlock_irqrestore(&priv->stats_lock, flags);
-
- return &priv->iwstats;
-}
-
-
-#define IW_IOCTL(x) [(x) - SIOCSIWCOMMIT]
-static const iw_handler rndis_iw_handler[] =
-{
- IW_IOCTL(SIOCSIWCOMMIT) = rndis_iw_commit,
- IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname,
- IW_IOCTL(SIOCSIWFREQ) = rndis_iw_set_freq,
- IW_IOCTL(SIOCGIWFREQ) = rndis_iw_get_freq,
- IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode,
- IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode,
- IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange,
- IW_IOCTL(SIOCSIWAP) = rndis_iw_set_bssid,
- IW_IOCTL(SIOCGIWAP) = rndis_iw_get_bssid,
- IW_IOCTL(SIOCSIWSCAN) = (iw_handler) cfg80211_wext_siwscan,
- IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan,
- IW_IOCTL(SIOCSIWESSID) = rndis_iw_set_essid,
- IW_IOCTL(SIOCGIWESSID) = rndis_iw_get_essid,
- IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate,
- IW_IOCTL(SIOCSIWRTS) = rndis_iw_set_rts,
- IW_IOCTL(SIOCGIWRTS) = rndis_iw_get_rts,
- IW_IOCTL(SIOCSIWFRAG) = rndis_iw_set_frag,
- IW_IOCTL(SIOCGIWFRAG) = rndis_iw_get_frag,
- IW_IOCTL(SIOCSIWTXPOW) = rndis_iw_set_txpower,
- IW_IOCTL(SIOCGIWTXPOW) = rndis_iw_get_txpower,
- IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode,
- IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext,
- IW_IOCTL(SIOCSIWAUTH) = rndis_iw_set_auth,
- IW_IOCTL(SIOCGIWAUTH) = rndis_iw_get_auth,
- IW_IOCTL(SIOCSIWGENIE) = rndis_iw_set_genie,
- IW_IOCTL(SIOCGIWGENIE) = rndis_iw_get_genie,
- IW_IOCTL(SIOCSIWMLME) = rndis_iw_set_mlme,
-};
+ if (le32_to_cpu(cand_list->version) != 1)
+ return;
-static const iw_handler rndis_wlan_private_handler[] = {
-};
+ for (i = 0; i < le32_to_cpu(cand_list->num_candidates); i++) {
+ struct ndis_80211_pmkid_candidate *cand =
+ &cand_list->candidate_list[i];
-static const struct iw_priv_args rndis_wlan_private_args[] = {
-};
+ devdbg(usbdev, "cand[%i]: flags: 0x%08x, bssid: %pM",
+ i, le32_to_cpu(cand->flags), cand->bssid);
+#if 0
+ struct iw_pmkid_cand pcand;
+ union iwreq_data wrqu;
-static const struct iw_handler_def rndis_iw_handlers = {
- .num_standard = ARRAY_SIZE(rndis_iw_handler),
- .num_private = ARRAY_SIZE(rndis_wlan_private_handler),
- .num_private_args = ARRAY_SIZE(rndis_wlan_private_args),
- .standard = (iw_handler *)rndis_iw_handler,
- .private = (iw_handler *)rndis_wlan_private_handler,
- .private_args = (struct iw_priv_args *)rndis_wlan_private_args,
- .get_wireless_stats = rndis_get_wireless_stats,
-};
+ memset(&pcand, 0, sizeof(pcand));
+ if (le32_to_cpu(cand->flags) & 0x01)
+ pcand.flags |= IW_PMKID_CAND_PREAUTH;
+ pcand.index = i;
+ memcpy(pcand.bssid.sa_data, cand->bssid, ETH_ALEN);
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = sizeof(pcand);
+ wireless_send_event(usbdev->net, IWEVPMKIDCAND, &wrqu,
+ (u8 *)&pcand);
+#endif
+ }
+}
-static void rndis_wlan_worker(struct work_struct *work)
+static void rndis_wlan_media_specific_indication(struct usbnet *usbdev,
+ struct rndis_indicate *msg, int buflen)
{
- struct rndis_wlan_private *priv =
- container_of(work, struct rndis_wlan_private, work);
- struct usbnet *usbdev = priv->usbdev;
- union iwreq_data evt;
- unsigned char bssid[ETH_ALEN];
- struct ndis_80211_assoc_info *info;
- int assoc_size = sizeof(*info) + IW_CUSTOM_MAX + 32;
- int ret, offset;
+ struct ndis_80211_status_indication *indication;
+ int len, offset;
- if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) {
- netif_carrier_on(usbdev->net);
+ offset = offsetof(struct rndis_indicate, status) +
+ le32_to_cpu(msg->offset);
+ len = le32_to_cpu(msg->length);
- info = kzalloc(assoc_size, GFP_KERNEL);
- if (!info)
- goto get_bssid;
+ if (len < 8) {
+ devinfo(usbdev, "media specific indication, "
+ "ignore too short message (%i < 8)", len);
+ return;
+ }
- /* Get association info IEs from device and send them back to
- * userspace. */
- ret = get_association_info(usbdev, info, assoc_size);
- if (!ret) {
- evt.data.length = le32_to_cpu(info->req_ie_length);
- if (evt.data.length > 0) {
- offset = le32_to_cpu(info->offset_req_ies);
- wireless_send_event(usbdev->net,
- IWEVASSOCREQIE, &evt,
- (char *)info + offset);
- }
+ if (offset + len > buflen) {
+ devinfo(usbdev, "media specific indication, "
+ "too large to fit to buffer (%i > %i)",
+ offset + len, buflen);
+ return;
+ }
- evt.data.length = le32_to_cpu(info->resp_ie_length);
- if (evt.data.length > 0) {
- offset = le32_to_cpu(info->offset_resp_ies);
- wireless_send_event(usbdev->net,
- IWEVASSOCRESPIE, &evt,
- (char *)info + offset);
- }
- }
+ indication = (void *)((u8 *)msg + offset);
- kfree(info);
+ switch (le32_to_cpu(indication->status_type)) {
+ case NDIS_80211_STATUSTYPE_RADIOSTATE:
+ devinfo(usbdev, "radio state indication: %i",
+ le32_to_cpu(indication->u.radio_status));
+ return;
-get_bssid:
- ret = get_bssid(usbdev, bssid);
- if (!ret) {
- evt.data.flags = 0;
- evt.data.length = 0;
- memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN);
- wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
- }
- }
+ case NDIS_80211_STATUSTYPE_MEDIASTREAMMODE:
+ devinfo(usbdev, "media stream mode indication: %i",
+ le32_to_cpu(indication->u.media_stream_mode));
+ return;
- if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) {
- netif_carrier_off(usbdev->net);
+ case NDIS_80211_STATUSTYPE_AUTHENTICATION:
+ rndis_wlan_auth_indication(usbdev, indication, len);
+ return;
- evt.data.flags = 0;
- evt.data.length = 0;
- memset(evt.ap_addr.sa_data, 0, ETH_ALEN);
- wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
- }
+ case NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST:
+ rndis_wlan_pmkid_cand_list_indication(usbdev, indication, len);
+ return;
- if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
- set_multicast_list(usbdev);
+ default:
+ devinfo(usbdev, "media specific indication: "
+ "unknown status type 0x%08x",
+ le32_to_cpu(indication->status_type));
+ }
}
-static void rndis_wlan_set_multicast_list(struct net_device *dev)
+static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen)
{
- struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ struct rndis_indicate *msg = ind;
+
+ switch (msg->status) {
+ case RNDIS_STATUS_MEDIA_CONNECT:
+ if (priv->current_command_oid == OID_802_11_ADD_KEY) {
+ /* OID_802_11_ADD_KEY causes sometimes extra
+ * "media connect" indications which confuses driver
+ * and userspace to think that device is
+ * roaming/reassociating when it isn't.
+ */
+ devdbg(usbdev, "ignored OID_802_11_ADD_KEY triggered "
+ "'media connect'");
+ return;
+ }
- if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
- return;
+ usbnet_pause_rx(usbdev);
- set_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending);
- queue_work(priv->workqueue, &priv->work);
-}
+ devinfo(usbdev, "media connect");
-static void rndis_wlan_link_change(struct usbnet *usbdev, int state)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ /* queue work to avoid recursive calls into rndis_command */
+ set_bit(WORK_LINK_UP, &priv->work_pending);
+ queue_work(priv->workqueue, &priv->work);
+ break;
- /* queue work to avoid recursive calls into rndis_command */
- set_bit(state ? WORK_LINK_UP : WORK_LINK_DOWN, &priv->work_pending);
- queue_work(priv->workqueue, &priv->work);
-}
+ case RNDIS_STATUS_MEDIA_DISCONNECT:
+ devinfo(usbdev, "media disconnect");
+
+ /* queue work to avoid recursive calls into rndis_command */
+ set_bit(WORK_LINK_DOWN, &priv->work_pending);
+ queue_work(priv->workqueue, &priv->work);
+ break;
+ case RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION:
+ rndis_wlan_media_specific_indication(usbdev, msg, buflen);
+ break;
+
+ default:
+ devinfo(usbdev, "indication: 0x%08x",
+ le32_to_cpu(msg->status));
+ break;
+ }
+}
static int rndis_wlan_get_caps(struct usbnet *usbdev)
{
@@ -2177,78 +2517,44 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev)
return retval;
}
-
-#define STATS_UPDATE_JIFFIES (HZ)
-static void rndis_update_wireless_stats(struct work_struct *work)
+#define DEVICE_POLLER_JIFFIES (HZ)
+static void rndis_device_poller(struct work_struct *work)
{
struct rndis_wlan_private *priv =
- container_of(work, struct rndis_wlan_private, stats_work.work);
+ container_of(work, struct rndis_wlan_private,
+ dev_poller_work.work);
struct usbnet *usbdev = priv->usbdev;
- struct iw_statistics iwstats;
__le32 rssi, tmp;
int len, ret, j;
- unsigned long flags;
- int update_jiffies = STATS_UPDATE_JIFFIES;
+ int update_jiffies = DEVICE_POLLER_JIFFIES;
void *buf;
- spin_lock_irqsave(&priv->stats_lock, flags);
- memcpy(&iwstats, &priv->privstats, sizeof(iwstats));
- spin_unlock_irqrestore(&priv->stats_lock, flags);
-
- /* only update stats when connected */
- if (!is_associated(usbdev)) {
- iwstats.qual.qual = 0;
- iwstats.qual.level = 0;
- iwstats.qual.updated = IW_QUAL_QUAL_UPDATED
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_NOISE_INVALID
- | IW_QUAL_QUAL_INVALID
- | IW_QUAL_LEVEL_INVALID;
+ /* Only check/do workaround when connected. Calling is_associated()
+ * also polls device with rndis_command() and catches for media link
+ * indications.
+ */
+ if (!is_associated(usbdev))
goto end;
- }
len = sizeof(rssi);
ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len);
-
- devdbg(usbdev, "stats: OID_802_11_RSSI -> %d, rssi:%d", ret,
- le32_to_cpu(rssi));
- if (ret == 0) {
- memset(&iwstats.qual, 0, sizeof(iwstats.qual));
- iwstats.qual.qual = level_to_qual(le32_to_cpu(rssi));
- iwstats.qual.level = level_to_qual(le32_to_cpu(rssi));
- iwstats.qual.updated = IW_QUAL_QUAL_UPDATED
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_NOISE_INVALID;
- }
-
- memset(&iwstats.discard, 0, sizeof(iwstats.discard));
-
- len = sizeof(tmp);
- ret = rndis_query_oid(usbdev, OID_GEN_XMIT_ERROR, &tmp, &len);
if (ret == 0)
- iwstats.discard.misc += le32_to_cpu(tmp);
+ priv->last_qual = level_to_qual(le32_to_cpu(rssi));
- len = sizeof(tmp);
- ret = rndis_query_oid(usbdev, OID_GEN_RCV_ERROR, &tmp, &len);
- if (ret == 0)
- iwstats.discard.misc += le32_to_cpu(tmp);
-
- len = sizeof(tmp);
- ret = rndis_query_oid(usbdev, OID_GEN_RCV_NO_BUFFER, &tmp, &len);
- if (ret == 0)
- iwstats.discard.misc += le32_to_cpu(tmp);
+ devdbg(usbdev, "dev-poller: OID_802_11_RSSI -> %d, rssi:%d, qual: %d",
+ ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi)));
/* Workaround transfer stalls on poor quality links.
* TODO: find right way to fix these stalls (as stalls do not happen
* with ndiswrapper/windows driver). */
- if (iwstats.qual.qual <= 25) {
+ if (priv->last_qual <= 25) {
/* Decrease stats worker interval to catch stalls.
* faster. Faster than 400-500ms causes packet loss,
* Slower doesn't catch stalls fast enough.
*/
j = msecs_to_jiffies(priv->param_workaround_interval);
- if (j > STATS_UPDATE_JIFFIES)
- j = STATS_UPDATE_JIFFIES;
+ if (j > DEVICE_POLLER_JIFFIES)
+ j = DEVICE_POLLER_JIFFIES;
else if (j <= 0)
j = 1;
update_jiffies = j;
@@ -2268,11 +2574,8 @@ static void rndis_update_wireless_stats(struct work_struct *work)
rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len);
kfree(buf);
}
-end:
- spin_lock_irqsave(&priv->stats_lock, flags);
- memcpy(&priv->privstats, &iwstats, sizeof(iwstats));
- spin_unlock_irqrestore(&priv->stats_lock, flags);
+end:
if (update_jiffies >= HZ)
update_jiffies = round_jiffies_relative(update_jiffies);
else {
@@ -2281,10 +2584,13 @@ end:
update_jiffies = j;
}
- queue_delayed_work(priv->workqueue, &priv->stats_work, update_jiffies);
+ queue_delayed_work(priv->workqueue, &priv->dev_poller_work,
+ update_jiffies);
}
-
+/*
+ * driver/device initialization
+ */
static int bcm4320a_early_init(struct usbnet *usbdev)
{
/* bcm4320a doesn't handle configuration parameters well. Try
@@ -2294,7 +2600,6 @@ static int bcm4320a_early_init(struct usbnet *usbdev)
return 0;
}
-
static int bcm4320b_early_init(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
@@ -2373,7 +2678,6 @@ static const struct net_device_ops rndis_wlan_netdev_ops = {
.ndo_set_multicast_list = rndis_wlan_set_multicast_list,
};
-
static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
{
struct wiphy *wiphy;
@@ -2398,16 +2702,14 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
* Otherwise we'll be in big trouble in rndis_wlan_early_init().
*/
usbdev->driver_priv = priv;
- usbdev->net->wireless_handlers = &rndis_iw_handlers;
priv->usbdev = usbdev;
mutex_init(&priv->command_lock);
- spin_lock_init(&priv->stats_lock);
/* because rndis_command() sleeps we need to use workqueue */
priv->workqueue = create_singlethread_workqueue("rndis_wlan");
INIT_WORK(&priv->work, rndis_wlan_worker);
- INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats);
+ INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller);
INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results);
/* try bind rndis_host */
@@ -2439,14 +2741,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
else
usbdev->net->flags &= ~IFF_MULTICAST;
- priv->iwstats.qual.qual = 0;
- priv->iwstats.qual.level = 0;
- priv->iwstats.qual.updated = IW_QUAL_QUAL_UPDATED
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_NOISE_INVALID
- | IW_QUAL_QUAL_INVALID
- | IW_QUAL_LEVEL_INVALID;
-
/* fill-out wiphy structure and register w/ cfg80211 */
memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN);
wiphy->privid = rndis_wiphy_privid;
@@ -2454,7 +2748,7 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
| BIT(NL80211_IFTYPE_ADHOC);
wiphy->max_scan_ssids = 1;
- /* TODO: fill-out band information based on priv->caps */
+ /* TODO: fill-out band/encr information based on priv->caps */
rndis_wlan_get_caps(usbdev);
memcpy(priv->channels, rndis_channels, sizeof(rndis_channels));
@@ -2466,6 +2760,11 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
+ memcpy(priv->cipher_suites, rndis_cipher_suites,
+ sizeof(rndis_cipher_suites));
+ wiphy->cipher_suites = priv->cipher_suites;
+ wiphy->n_cipher_suites = ARRAY_SIZE(rndis_cipher_suites);
+
set_wiphy_dev(wiphy, &usbdev->udev->dev);
if (wiphy_register(wiphy)) {
@@ -2475,18 +2774,19 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
set_default_iw_params(usbdev);
+ /* set default rts/frag */
+ rndis_set_wiphy_params(wiphy,
+ WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD);
+
/* turn radio on */
- priv->radio_on = 1;
- disassociate(usbdev, 1);
+ priv->radio_on = true;
+ disassociate(usbdev, true);
netif_carrier_off(usbdev->net);
- queue_delayed_work(priv->workqueue, &priv->stats_work,
- round_jiffies_relative(STATS_UPDATE_JIFFIES));
-
return 0;
fail:
- cancel_delayed_work_sync(&priv->stats_work);
+ cancel_delayed_work_sync(&priv->dev_poller_work);
cancel_delayed_work_sync(&priv->scan_work);
cancel_work_sync(&priv->work);
flush_workqueue(priv->workqueue);
@@ -2496,15 +2796,14 @@ fail:
return retval;
}
-
static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
/* turn radio off */
- disassociate(usbdev, 0);
+ disassociate(usbdev, false);
- cancel_delayed_work_sync(&priv->stats_work);
+ cancel_delayed_work_sync(&priv->dev_poller_work);
cancel_delayed_work_sync(&priv->scan_work);
cancel_work_sync(&priv->work);
flush_workqueue(priv->workqueue);
@@ -2519,50 +2818,100 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
wiphy_free(priv->wdev.wiphy);
}
-
static int rndis_wlan_reset(struct usbnet *usbdev)
{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ int retval;
+
+ devdbg(usbdev, "rndis_wlan_reset");
+
+ retval = rndis_reset(usbdev);
+ if (retval)
+ devwarn(usbdev, "rndis_reset() failed: %d", retval);
+
+ /* rndis_reset cleared multicast list, so restore here.
+ (set_multicast_list() also turns on current packet filter) */
+ set_multicast_list(usbdev);
+
+ queue_delayed_work(priv->workqueue, &priv->dev_poller_work,
+ round_jiffies_relative(DEVICE_POLLER_JIFFIES));
+
return deauthenticate(usbdev);
}
+static int rndis_wlan_stop(struct usbnet *usbdev)
+{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ int retval;
+ __le32 filter;
+
+ devdbg(usbdev, "rndis_wlan_stop");
+
+ retval = disassociate(usbdev, false);
+
+ priv->work_pending = 0;
+ cancel_delayed_work_sync(&priv->dev_poller_work);
+ cancel_delayed_work_sync(&priv->scan_work);
+ cancel_work_sync(&priv->work);
+ flush_workqueue(priv->workqueue);
+
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, true);
+ priv->scan_request = NULL;
+ }
+
+ /* Set current packet filter zero to block receiving data packets from
+ device. */
+ filter = 0;
+ rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter,
+ sizeof(filter));
+
+ return retval;
+}
static const struct driver_info bcm4320b_info = {
.description = "Wireless RNDIS device, BCM4320b based",
- .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+ .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
+ FLAG_AVOID_UNLINK_URBS,
.bind = rndis_wlan_bind,
.unbind = rndis_wlan_unbind,
.status = rndis_status,
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
+ .stop = rndis_wlan_stop,
.early_init = bcm4320b_early_init,
- .link_change = rndis_wlan_link_change,
+ .indication = rndis_wlan_indication,
};
static const struct driver_info bcm4320a_info = {
.description = "Wireless RNDIS device, BCM4320a based",
- .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+ .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
+ FLAG_AVOID_UNLINK_URBS,
.bind = rndis_wlan_bind,
.unbind = rndis_wlan_unbind,
.status = rndis_status,
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
+ .stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
- .link_change = rndis_wlan_link_change,
+ .indication = rndis_wlan_indication,
};
static const struct driver_info rndis_wlan_info = {
.description = "Wireless RNDIS device",
- .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+ .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
+ FLAG_AVOID_UNLINK_URBS,
.bind = rndis_wlan_bind,
.unbind = rndis_wlan_unbind,
.status = rndis_status,
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
+ .stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
- .link_change = rndis_wlan_link_change,
+ .indication = rndis_wlan_indication,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index 8aab3e6754bd..ed1f997e3521 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -1,8 +1,8 @@
menuconfig RT2X00
tristate "Ralink driver support"
- depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
+ depends on MAC80211 && WLAN_80211
---help---
- This will enable the experimental support for the Ralink drivers,
+ This will enable the support for the Ralink drivers,
developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
These drivers make use of the mac80211 stack.
@@ -79,14 +79,14 @@ config RT73USB
config RT2800USB
tristate "Ralink rt2800 (USB) support"
- depends on USB
+ depends on USB && EXPERIMENTAL
select RT2X00_LIB_USB
select RT2X00_LIB_HT
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select CRC_CCITT
---help---
- This adds support for rt2800 wireless chipset family.
+ This adds experimental support for rt2800 wireless chipset family.
Supported chips: RT2770, RT2870 & RT3070.
When compiled as a module, this driver will be called "rt2800usb.ko".
@@ -112,14 +112,6 @@ config RT2X00_LIB_FIRMWARE
config RT2X00_LIB_CRYPTO
boolean
-config RT2X00_LIB_RFKILL
- boolean
- default y if (RT2X00_LIB=y && INPUT=y) || (RT2X00_LIB=m && INPUT!=n)
- select INPUT_POLLDEV
-
-comment "rt2x00 rfkill support disabled due to modularized INPUT and built-in rt2x00"
- depends on RT2X00_LIB=y && INPUT=m
-
config RT2X00_LIB_LEDS
boolean
default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
index bfc7226f0afe..13043ea97667 100644
--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -5,7 +5,6 @@ rt2x00lib-y += rt2x00queue.o
rt2x00lib-y += rt2x00link.o
rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o
rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o
-rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o
rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 435f945fe64d..798f625e38f7 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -199,7 +199,6 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -207,9 +206,6 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
return rt2x00_get_field32(reg, GPIOCSR_BIT0);
}
-#else
-#define rt2400pci_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2400pci_brightness_set(struct led_classdev *led_cdev,
@@ -335,9 +331,8 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev,
preamble_mask = erp->short_preamble << 3;
rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
- rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, erp->ack_timeout);
- rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME,
- erp->ack_consume_time);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, 0x1ff);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, 0x13a);
rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
@@ -1073,8 +1068,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry)
* otherwise we might be sending out invalid data.
*/
rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
- rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
- rt2x00_set_field32(&reg, CSR14_TBCN, 0);
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
@@ -1391,10 +1384,8 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Check if the BBP tuning should be enabled.
@@ -1567,12 +1558,14 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2400pci_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2400pci_get_tsf,
.tx_last_beacon = rt2400pci_tx_last_beacon,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index ec3b004ddc3c..ccd644104ad1 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -928,7 +928,7 @@
#define RXD_W7_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
* NOTE: Logics in rt2400pci for txpower are reversed
* compared to the other rt2x00 drivers. A higher txpower
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 08b30d01e67d..2e872ac69826 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -199,7 +199,6 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -207,9 +206,6 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
return rt2x00_get_field32(reg, GPIOCSR_BIT0);
}
-#else
-#define rt2500pci_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2500pci_brightness_set(struct led_classdev *led_cdev,
@@ -341,9 +337,8 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev,
preamble_mask = erp->short_preamble << 3;
rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
- rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, erp->ack_timeout);
- rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME,
- erp->ack_consume_time);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, 0x162);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, 0xa2);
rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
@@ -1231,8 +1226,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry)
* otherwise we might be sending out invalid data.
*/
rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
- rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
- rt2x00_set_field32(&reg, CSR14_TBCN, 0);
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
@@ -1548,10 +1541,8 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Check if the BBP tuning should be enabled.
@@ -1866,12 +1857,14 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2500pci_get_tsf,
.tx_last_beacon = rt2500pci_tx_last_beacon,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
index ce2f065c7486..54d37957883c 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -1218,7 +1218,7 @@
#define RXD_W10_DROP FIELD32(0x00000001)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index ce75426764a1..22dd6d9e2981 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -277,7 +277,6 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u16 reg;
@@ -285,9 +284,6 @@ static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2500usb_register_read(rt2x00dev, MAC_CSR19, &reg);
return rt2x00_get_field32(reg, MAC_CSR19_BIT7);
}
-#else
-#define rt2500usb_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2500usb_brightness_set(struct led_classdev *led_cdev,
@@ -492,10 +488,6 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev,
{
u16 reg;
- rt2500usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
- rt2x00_set_field16(&reg, TXRX_CSR1_ACK_TIMEOUT, erp->ack_timeout);
- rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg);
-
rt2500usb_register_read(rt2x00dev, TXRX_CSR10, &reg);
rt2x00_set_field16(&reg, TXRX_CSR10_AUTORESPOND_PREAMBLE,
!!erp->short_preamble);
@@ -1242,8 +1234,6 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
* otherwise we might be sending out invalid data.
*/
rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
- rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
- rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
@@ -1291,7 +1281,7 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue)
{
- u16 reg;
+ u16 reg, reg0;
if (queue != QID_BEACON) {
rt2x00usb_kick_tx_queue(rt2x00dev, queue);
@@ -1302,16 +1292,19 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) {
rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
+ reg0 = reg;
rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 1);
/*
* Beacon generation will fail initially.
- * To prevent this we need to register the TXRX_CSR19
- * register several times.
+ * To prevent this we need to change the TXRX_CSR19
+ * register several times (reg0 is the same as reg
+ * except for TXRX_CSR19_BEACON_GEN, which is 0 in reg0
+ * and 1 in reg).
*/
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
- rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
- rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
}
}
@@ -1603,10 +1596,8 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Check if the BBP tuning should be disabled.
@@ -1879,7 +1870,6 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
*/
__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags);
if (!modparam_nohwcrypt) {
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags);
@@ -1902,11 +1892,13 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
index 5bc46fe72179..b01edca42583 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -831,7 +831,7 @@
#define RXD_W3_EIV FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 37561667925b..a084077a1c61 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -264,7 +264,6 @@ static const struct rt2x00debug rt2800usb_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -272,9 +271,6 @@ static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2);
}
-#else
-#define rt2800usb_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2800usb_brightness_set(struct led_classdev *led_cdev,
@@ -522,7 +518,7 @@ static void rt2800usb_config_filter(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_RTS,
!(filter_flags & FIF_CONTROL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
- !(filter_flags & FIF_CONTROL));
+ !(filter_flags & FIF_PSPOLL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 1);
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR, 0);
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL,
@@ -584,8 +580,7 @@ static void rt2800usb_config_erp(struct rt2x00_dev *rt2x00dev,
u32 reg;
rt2x00usb_register_read(rt2x00dev, TX_TIMEOUT_CFG, &reg);
- rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT,
- DIV_ROUND_UP(erp->ack_timeout, erp->slot_time));
+ rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20);
rt2x00usb_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg);
rt2x00usb_register_read(rt2x00dev, AUTO_RSP_CFG, &reg);
@@ -1467,6 +1462,10 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
/*
* ASIC will keep garbage value after boot, clear encryption keys.
*/
+ for (i = 0; i < 4; i++)
+ rt2x00usb_register_write(rt2x00dev,
+ SHARED_KEY_MODE_ENTRY(i), 0);
+
for (i = 0; i < 256; i++) {
u32 wcid[2] = { 0xffffffff, 0x00ffffff };
rt2x00usb_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i),
@@ -1476,10 +1475,6 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
}
- for (i = 0; i < 16; i++)
- rt2x00usb_register_write(rt2x00dev,
- SHARED_KEY_MODE_ENTRY(i), 0);
-
/*
* Clear all beacons
* For the Beacon base registers we only need to clear
@@ -1524,7 +1519,7 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_read(rt2x00dev, LG_FBK_CFG0, &reg);
rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS0FBK, 8);
rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS1FBK, 8);
- rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS2FBK, 3);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS2FBK, 9);
rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS3FBK, 10);
rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS4FBK, 11);
rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS5FBK, 12);
@@ -1914,7 +1909,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* Before the radio can be enabled, the device first has
* to be woken up. After that it needs a bit of time
- * to be fully awake and the radio can be enabled.
+ * to be fully awake and then the radio can be enabled.
*/
rt2800usb_set_state(rt2x00dev, STATE_AWAKE);
msleep(1);
@@ -1922,7 +1917,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
break;
case STATE_RADIO_OFF:
/*
- * After the radio has been disablee, the device should
+ * After the radio has been disabled, the device should
* be put to sleep for powersaving.
*/
rt2800usb_disable_radio(rt2x00dev);
@@ -1999,11 +1994,11 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
- txdesc->key_idx : 0xff);
+ (skbdesc->entry->entry_idx + 1) : 0xff);
rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
skb->len - txdesc->l2pad);
rt2x00_set_field32(&word, TXWI_W1_PACKETID,
- skbdesc->entry->entry_idx);
+ skbdesc->entry->queue->qid + 1);
rt2x00_desc_write(txwi, 1, word);
/*
@@ -2054,8 +2049,6 @@ static void rt2800usb_write_beacon(struct queue_entry *entry)
* otherwise we might be sending out invalid data.
*/
rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg);
@@ -2169,8 +2162,10 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS;
- if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD))
+ if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) {
rxdesc->dev_flags |= RXDONE_L2PAD;
+ skbdesc->flags |= SKBDESC_L2_PADDED;
+ }
if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
rxdesc->flags |= RX_FLAG_SHORT_GI;
@@ -2224,10 +2219,8 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
*/
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
- DECLARE_MAC_BUF(macbuf);
-
random_ether_addr(mac);
- EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -2385,10 +2378,8 @@ static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Store led settings, for correct led behaviour.
@@ -2632,10 +2623,16 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
return retval;
/*
+ * This device has multiple filters for control frames
+ * and has a separate filter for PS Poll frames.
+ */
+ __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
+ __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags);
+
+ /*
* This device requires firmware.
*/
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
@@ -2792,6 +2789,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.get_tkip_seq = rt2800usb_get_tkip_seq,
@@ -2800,6 +2798,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.conf_tx = rt2800usb_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2800usb_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h
index 61a8be61d3f5..4d9991c9a51c 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.h
+++ b/drivers/net/wireless/rt2x00/rt2800usb.h
@@ -36,6 +36,9 @@
* RF2750 2.4G/5G 1T2R
* RF3020 2.4G 1T1R
* RF2020 2.4G B/G
+ * RF3021 2.4G 1T2R
+ * RF3022 2.4G 2T2R
+ * RF3052 2.4G 2T2R
*/
#define RF2820 0x0001
#define RF2850 0x0002
@@ -43,6 +46,9 @@
#define RF2750 0x0004
#define RF3020 0x0005
#define RF2020 0x0006
+#define RF3021 0x0007
+#define RF3022 0x0008
+#define RF3052 0x0009
/*
* RT2870 version
@@ -1300,8 +1306,8 @@
* PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry
* MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry
* MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry
- * SHARED_KEY_TABLE_BASE: 32-byte * 16-entry
- * SHARED_KEY_MODE_BASE: 4-byte * 16-entry
+ * SHARED_KEY_TABLE_BASE: 32 bytes * 32-entry
+ * SHARED_KEY_MODE_BASE: 4 bits * 32-entry
*/
#define MAC_WCID_BASE 0x1800
#define PAIRWISE_KEY_TABLE_BASE 0x4000
@@ -1921,7 +1927,7 @@ struct mac_iveiv_entry {
#define RXWI_W3_SNR1 FIELD32(0x0000ff00)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_G_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 49c9e2c1433d..27bc6b7fbfde 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -134,6 +134,17 @@
GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) )
/*
+ * Structure for average calculation
+ * The avg field contains the actual average value,
+ * but avg_weight is internally used during calculations
+ * to prevent rounding errors.
+ */
+struct avg_val {
+ int avg;
+ int avg_weight;
+};
+
+/*
* Chipset identification
* The chipset on the device is composed of a RT and RF chip.
* The chipset combination is important for determining device capabilities.
@@ -245,21 +256,18 @@ struct link_ant {
struct antenna_setup active;
/*
- * RSSI information for the different antenna's.
- * These statistics are used to determine when
- * to switch antenna when using software diversity.
- *
- * rssi[0] -> Antenna A RSSI
- * rssi[1] -> Antenna B RSSI
+ * RSSI history information for the antenna.
+ * Used to determine when to switch antenna
+ * when using software diversity.
*/
- int rssi_history[2];
+ int rssi_history;
/*
* Current RSSI average of the currently active antenna.
* Similar to the avg_rssi in the link_qual structure
* this value is updated by using the walking average.
*/
- int rssi_ant;
+ struct avg_val rssi_ant;
};
/*
@@ -288,7 +296,7 @@ struct link {
/*
* Currently active average RSSI value
*/
- int avg_rssi;
+ struct avg_val avg_rssi;
/*
* Currently precalculated percentages of successful
@@ -326,6 +334,11 @@ struct rt2x00_intf {
u8 bssid[ETH_ALEN];
/*
+ * beacon->skb must be protected with the mutex.
+ */
+ struct mutex beacon_skb_mutex;
+
+ /*
* Entry in the beacon queue which belongs to
* this interface. Each interface has its own
* dedicated beacon entry.
@@ -337,8 +350,6 @@ struct rt2x00_intf {
*/
unsigned int delayed_flags;
#define DELAYED_UPDATE_BEACON 0x00000001
-#define DELAYED_CONFIG_ERP 0x00000002
-#define DELAYED_LED_ASSOC 0x00000004
/*
* Software sequence counter, this is only required
@@ -406,9 +417,6 @@ struct rt2x00lib_erp {
int short_preamble;
int cts_protection;
- int ack_timeout;
- int ack_consume_time;
-
u32 basic_rates;
int slot_time;
@@ -594,7 +602,6 @@ enum rt2x00_flags {
DEVICE_STATE_INITIALIZED,
DEVICE_STATE_STARTED,
DEVICE_STATE_ENABLED_RADIO,
- DEVICE_STATE_DISABLED_RADIO_HW,
/*
* Driver requirements
@@ -602,7 +609,6 @@ enum rt2x00_flags {
DRIVER_REQUIRE_FIRMWARE,
DRIVER_REQUIRE_BEACON_GUARD,
DRIVER_REQUIRE_ATIM_QUEUE,
- DRIVER_REQUIRE_SCHEDULED,
DRIVER_REQUIRE_DMA,
DRIVER_REQUIRE_COPY_IV,
DRIVER_REQUIRE_L2PAD,
@@ -612,6 +618,8 @@ enum rt2x00_flags {
*/
CONFIG_SUPPORT_HW_BUTTON,
CONFIG_SUPPORT_HW_CRYPTO,
+ DRIVER_SUPPORT_CONTROL_FILTERS,
+ DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL,
/*
* Driver configuration
@@ -634,7 +642,7 @@ struct rt2x00_dev {
* The structure stored in here depends on the
* system bus (PCI or USB).
* When accessing this variable, the rt2x00dev_{pci,usb}
- * macro's should be used for correct typecasting.
+ * macros should be used for correct typecasting.
*/
struct device *dev;
@@ -651,18 +659,6 @@ struct rt2x00_dev {
enum ieee80211_band curr_band;
/*
- * rfkill structure for RF state switching support.
- * This will only be compiled in when required.
- */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
- unsigned long rfkill_state;
-#define RFKILL_STATE_ALLOCATED 1
-#define RFKILL_STATE_REGISTERED 2
-#define RFKILL_STATE_BLOCKED 3
- struct input_polled_dev *rfkill_poll_dev;
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
-
- /*
* If enabled, the debugfs interface structures
* required for deregistration of debugfs.
*/
@@ -824,7 +820,6 @@ struct rt2x00_dev {
* due to RTNL locking requirements.
*/
struct work_struct intf_work;
- struct work_struct filter_work;
/*
* Data queue arrays for RX, TX and Beacon.
@@ -976,7 +971,9 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed);
void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
- int mc_count, struct dev_addr_list *mc_list);
+ u64 multicast);
+int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ bool set);
#ifdef CONFIG_RT2X00_LIB_CRYPTO
int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
@@ -994,6 +991,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
u32 changes);
int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params);
+void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
/*
* Driver allocation handlers.
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 3e019a12df2e..40a201e2e151 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -94,17 +94,6 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS;
erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS;
- erp.ack_timeout = PLCP + erp.difs + GET_DURATION(ACK_SIZE, 10);
- erp.ack_consume_time = SIFS + PLCP + GET_DURATION(ACK_SIZE, 10);
-
- if (bss_conf->use_short_preamble) {
- erp.ack_timeout += SHORT_PREAMBLE;
- erp.ack_consume_time += SHORT_PREAMBLE;
- } else {
- erp.ack_timeout += PREAMBLE;
- erp.ack_consume_time += PREAMBLE;
- }
-
erp.basic_rates = bss_conf->basic_rates;
erp.beacon_int = bss_conf->beacon_int;
@@ -124,24 +113,34 @@ enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant,
}
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
- struct antenna_setup *ant)
+ struct antenna_setup config)
{
+ struct link_ant *ant = &rt2x00dev->link.ant;
struct antenna_setup *def = &rt2x00dev->default_ant;
struct antenna_setup *active = &rt2x00dev->link.ant.active;
/*
* Failsafe: Make sure we are not sending the
* ANTENNA_SW_DIVERSITY state to the driver.
- * If that happes fallback to hardware default,
+ * If that happens, fallback to hardware defaults,
* or our own default.
+ * If diversity handling is active for a particular antenna,
+ * we shouldn't overwrite that antenna.
* The calls to rt2x00lib_config_antenna_check()
* might have caused that we restore back to the already
* active setting. If that has happened we can quit.
*/
- ant->rx = rt2x00lib_config_antenna_check(ant->rx, def->rx);
- ant->tx = rt2x00lib_config_antenna_check(ant->tx, def->tx);
+ if (!(ant->flags & ANTENNA_RX_DIVERSITY))
+ config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx);
+ else
+ config.rx = active->rx;
+
+ if (!(ant->flags & ANTENNA_TX_DIVERSITY))
+ config.tx = rt2x00lib_config_antenna_check(config.tx, def->tx);
+ else
+ config.tx = active->tx;
- if (ant->rx == active->rx && ant->tx == active->tx)
+ if (config.rx == active->rx && config.tx == active->tx)
return;
/*
@@ -156,11 +155,11 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
* The latter is required since we need to recalibrate the
* noise-sensitivity ratio for the new setup.
*/
- rt2x00dev->ops->lib->config_ant(rt2x00dev, ant);
+ rt2x00dev->ops->lib->config_ant(rt2x00dev, &config);
rt2x00link_reset_tuner(rt2x00dev, true);
- memcpy(active, ant, sizeof(*ant));
+ memcpy(active, &config, sizeof(config));
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index bc4e81e21841..de36837dcf86 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -53,8 +53,7 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
- if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) ||
- !hw_key || entry->skb->do_not_encrypt)
+ if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !hw_key)
return;
__set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
@@ -82,8 +81,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
struct ieee80211_key_conf *key = tx_info->control.hw_key;
unsigned int overhead = 0;
- if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) ||
- !key || skb->do_not_encrypt)
+ if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !key)
return overhead;
/*
@@ -131,7 +129,7 @@ void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
/* Pull buffer to correct size */
skb_pull(skb, txdesc->iv_len);
- /* IV/EIV data has officially be stripped */
+ /* IV/EIV data has officially been stripped */
skbdesc->flags |= SKBDESC_IV_STRIPPED;
}
@@ -156,7 +154,7 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length)
skbdesc->flags &= ~SKBDESC_IV_STRIPPED;
}
-void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad,
+void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
unsigned int header_length,
struct rxdone_entry_desc *rxdesc)
{
@@ -201,7 +199,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad,
* move the header more then iv_len since we must
* make room for the payload move as well.
*/
- if (l2pad) {
+ if (rxdesc->dev_flags & RXDONE_L2PAD) {
skb_push(skb, iv_len - align);
skb_put(skb, icv_len);
@@ -232,7 +230,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad,
* Move payload for alignment purposes. Note that
* this is only needed when no l2 padding is present.
*/
- if (!l2pad) {
+ if (!(rxdesc->dev_flags & RXDONE_L2PAD)) {
memmove(skb->data + transfer,
skb->data + transfer + align,
payload_len);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 57813e72c808..71761b343839 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -40,8 +40,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
* Don't enable the radio twice.
* And check if the hardware button has been disabled.
*/
- if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
- test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags))
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return 0;
/*
@@ -119,20 +118,11 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state)
rt2x00link_start_tuner(rt2x00dev);
}
-static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
-{
- struct rt2x00_dev *rt2x00dev =
- container_of(work, struct rt2x00_dev, filter_work);
-
- rt2x00dev->ops->lib->config_filter(rt2x00dev, rt2x00dev->packet_filter);
-}
-
static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = data;
struct rt2x00_intf *intf = vif_to_intf(vif);
- struct ieee80211_bss_conf conf;
int delayed_flags;
/*
@@ -142,7 +132,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
*/
spin_lock(&intf->lock);
- memcpy(&conf, &vif->bss_conf, sizeof(conf));
delayed_flags = intf->delayed_flags;
intf->delayed_flags = 0;
@@ -159,12 +148,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
if (delayed_flags & DELAYED_UPDATE_BEACON)
rt2x00queue_update_beacon(rt2x00dev, vif, true);
-
- if (delayed_flags & DELAYED_CONFIG_ERP)
- rt2x00lib_config_erp(rt2x00dev, intf, &conf);
-
- if (delayed_flags & DELAYED_LED_ASSOC)
- rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
}
static void rt2x00lib_intf_scheduled(struct work_struct *work)
@@ -187,7 +170,6 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
- struct rt2x00_dev *rt2x00dev = data;
struct rt2x00_intf *intf = vif_to_intf(vif);
if (vif->type != NL80211_IFTYPE_AP &&
@@ -196,12 +178,6 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
vif->type != NL80211_IFTYPE_WDS)
return;
- /*
- * Clean up the beacon skb.
- */
- rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb);
- intf->beacon->skb = NULL;
-
spin_lock(&intf->lock);
intf->delayed_flags |= DELAYED_UPDATE_BEACON;
spin_unlock(&intf->lock);
@@ -216,7 +192,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
rt2x00lib_beacondone_iter,
rt2x00dev);
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
}
EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
@@ -228,7 +204,9 @@ void rt2x00lib_txdone(struct queue_entry *entry,
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
- u8 rate_idx, rate_flags;
+ u8 rate_idx, rate_flags, retry_rates;
+ unsigned int i;
+ bool success;
/*
* Unmap the skb.
@@ -239,7 +217,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* Remove L2 padding which was added during
*/
if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
- rt2x00queue_payload_align(entry->skb, true, header_length);
+ rt2x00queue_remove_l2pad(entry->skb, header_length);
/*
* If the IV/EIV data was stripped from the frame before it was
@@ -257,40 +235,54 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb);
/*
- * Update TX statistics.
+ * Determine if the frame has been successfully transmitted.
*/
- rt2x00dev->link.qual.tx_success +=
+ success =
test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
- test_bit(TXDONE_UNKNOWN, &txdesc->flags);
- rt2x00dev->link.qual.tx_failed +=
- test_bit(TXDONE_FAILURE, &txdesc->flags);
+ test_bit(TXDONE_UNKNOWN, &txdesc->flags) ||
+ test_bit(TXDONE_FALLBACK, &txdesc->flags);
+
+ /*
+ * Update TX statistics.
+ */
+ rt2x00dev->link.qual.tx_success += success;
+ rt2x00dev->link.qual.tx_failed += !success;
rate_idx = skbdesc->tx_rate_idx;
rate_flags = skbdesc->tx_rate_flags;
+ retry_rates = test_bit(TXDONE_FALLBACK, &txdesc->flags) ?
+ (txdesc->retry + 1) : 1;
/*
* Initialize TX status
*/
memset(&tx_info->status, 0, sizeof(tx_info->status));
tx_info->status.ack_signal = 0;
- tx_info->status.rates[0].idx = rate_idx;
- tx_info->status.rates[0].flags = rate_flags;
- tx_info->status.rates[0].count = txdesc->retry + 1;
- tx_info->status.rates[1].idx = -1; /* terminate */
+
+ /*
+ * Frame was send with retries, hardware tried
+ * different rates to send out the frame, at each
+ * retry it lowered the rate 1 step.
+ */
+ for (i = 0; i < retry_rates && i < IEEE80211_TX_MAX_RATES; i++) {
+ tx_info->status.rates[i].idx = rate_idx - i;
+ tx_info->status.rates[i].flags = rate_flags;
+ tx_info->status.rates[i].count = 1;
+ }
+ if (i < (IEEE80211_TX_MAX_RATES - 1))
+ tx_info->status.rates[i].idx = -1; /* terminate */
if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
- if (test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
- test_bit(TXDONE_UNKNOWN, &txdesc->flags))
+ if (success)
tx_info->flags |= IEEE80211_TX_STAT_ACK;
- else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
+ else
rt2x00dev->low_level_stats.dot11ACKFailureCount++;
}
if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
- if (test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
- test_bit(TXDONE_UNKNOWN, &txdesc->flags))
+ if (success)
rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
- else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
+ else
rt2x00dev->low_level_stats.dot11RTSFailureCount++;
}
@@ -372,7 +364,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb;
struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
unsigned int header_length;
- bool l2pad;
int rate_idx;
/*
* Allocate a new sk_buffer. If no new buffer available, drop the
@@ -401,7 +392,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
* aligned on a 4 byte boundary.
*/
header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
- l2pad = !!(rxdesc.dev_flags & RXDONE_L2PAD);
/*
* Hardware might have stripped the IV/EIV/ICV data,
@@ -411,10 +401,12 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
*/
if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) &&
(rxdesc.flags & RX_FLAG_IV_STRIPPED))
- rt2x00crypto_rx_insert_iv(entry->skb, l2pad, header_length,
+ rt2x00crypto_rx_insert_iv(entry->skb, header_length,
&rxdesc);
+ else if (rxdesc.dev_flags & RXDONE_L2PAD)
+ rt2x00queue_remove_l2pad(entry->skb, header_length);
else
- rt2x00queue_payload_align(entry->skb, l2pad, header_length);
+ rt2x00queue_align_payload(entry->skb, header_length);
/*
* Check if the frame was received using HT. In that case,
@@ -449,7 +441,8 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
* mac80211 will clean up the skb structure.
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
- ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
+ memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
+ ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
/*
* Replace the skb with the freshly allocated one.
@@ -785,6 +778,13 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
rt2x00dev->intf_sta_count = 0;
rt2x00dev->intf_associated = 0;
+ /* Enable the radio */
+ retval = rt2x00lib_enable_radio(rt2x00dev);
+ if (retval) {
+ rt2x00queue_uninitialize(rt2x00dev);
+ return retval;
+ }
+
set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags);
return 0;
@@ -847,7 +847,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
* Initialize configuration work.
*/
INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
- INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
/*
* Allocate queue array.
@@ -870,7 +869,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
*/
rt2x00link_register(rt2x00dev);
rt2x00leds_register(rt2x00dev);
- rt2x00rfkill_allocate(rt2x00dev);
rt2x00debug_register(rt2x00dev);
set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
@@ -894,6 +892,11 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
rt2x00lib_disable_radio(rt2x00dev);
/*
+ * Stop all work.
+ */
+ cancel_work_sync(&rt2x00dev->intf_work);
+
+ /*
* Uninitialize device.
*/
rt2x00lib_uninitialize(rt2x00dev);
@@ -902,7 +905,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
* Free extra components
*/
rt2x00debug_deregister(rt2x00dev);
- rt2x00rfkill_free(rt2x00dev);
rt2x00leds_unregister(rt2x00dev);
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 0bf2715fa93a..5462cb5ad994 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -30,10 +30,8 @@
/*
* Interval defines
- * Both the link tuner as the rfkill will be called once per second.
*/
#define LINK_TUNE_INTERVAL round_jiffies_relative(HZ)
-#define RFKILL_POLL_INTERVAL 1000
/*
* rt2x00_rate: Per rate device information
@@ -90,7 +88,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
struct ieee80211_bss_conf *conf);
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
- struct antenna_setup *ant);
+ struct antenna_setup ant);
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf,
const unsigned int changed_flags);
@@ -122,21 +120,42 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/**
- * rt2x00queue_payload_align - Align 802.11 payload to 4-byte boundary
+ * rt2x00queue_align_frame - Align 802.11 frame to 4-byte boundary
+ * @skb: The skb to align
+ *
+ * Align the start of the 802.11 frame to a 4-byte boundary, this could
+ * mean the payload is not aligned properly though.
+ */
+void rt2x00queue_align_frame(struct sk_buff *skb);
+
+/**
+ * rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary
+ * @skb: The skb to align
+ * @header_length: Length of 802.11 header
+ *
+ * Align the 802.11 payload to a 4-byte boundary, this could
+ * mean the header is not aligned properly though.
+ */
+void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length);
+
+/**
+ * rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary
+ * @skb: The skb to align
+ * @header_length: Length of 802.11 header
+ *
+ * Apply L2 padding to align both header and payload to 4-byte boundary
+ */
+void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length);
+
+/**
+ * rt2x00queue_insert_l2pad - Remove L2 padding from 802.11 frame
* @skb: The skb to align
- * @l2pad: Should L2 padding be used
* @header_length: Length of 802.11 header
*
- * This function prepares the @skb to be send to the device or mac80211.
- * If @l2pad is set to true padding will occur between the 802.11 header
- * and payload. Otherwise the padding will be done in front of the 802.11
- * header.
- * When @l2pad is set the function will check for the &SKBDESC_L2_PADDED
- * flag in &skb_frame_desc. If that flag is set, the padding is removed
- * and the flag cleared. Otherwise the padding is added and the flag is set.
+ * Remove L2 padding used to align both header and payload to 4-byte boundary,
+ * by removing the L2 padding the header will no longer be 4-byte aligned.
*/
-void rt2x00queue_payload_align(struct sk_buff *skb,
- bool l2pad, unsigned int header_length);
+void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length);
/**
* rt2x00queue_write_tx_frame - Write TX frame to hardware
@@ -326,7 +345,7 @@ void rt2x00crypto_tx_copy_iv(struct sk_buff *skb,
void rt2x00crypto_tx_remove_iv(struct sk_buff *skb,
struct txentry_desc *txdesc);
void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length);
-void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad,
+void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
unsigned int header_length,
struct rxdone_entry_desc *rxdesc);
#else
@@ -386,29 +405,18 @@ static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
/*
* RFkill handlers.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
-void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev);
-#else
static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
{
+ if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy);
}
static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
{
+ if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy);
}
-static inline void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
-{
-}
-
-static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
-{
-}
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
-
/*
* LED handlers
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index eb9b981b9139..c64db0ba7f40 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -46,7 +46,15 @@
#define DEFAULT_PERCENTAGE 50
/*
- * Small helper macro to work with moving/walking averages.
+ * Small helper macro for percentage calculation
+ * This is a very simple macro with the only catch that it will
+ * produce a default value in case no total value was provided.
+ */
+#define PERCENTAGE(__value, __total) \
+ ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) )
+
+/*
+ * Helper struct and macro to work with moving/walking averages.
* When adding a value to the average value the following calculation
* is needed:
*
@@ -60,18 +68,28 @@
* for a few minutes but when the device is moved away from the AP
* the average will not decrease fast enough to compensate.
* The walking average compensates this and will move towards
- * the new values correctly allowing a effective link tuning.
- */
-#define MOVING_AVERAGE(__avg, __val, __samples) \
- ( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) )
-
-/*
- * Small helper macro for percentage calculation
- * This is a very simple macro with the only catch that it will
- * produce a default value in case no total value was provided.
+ * the new values correctly allowing a effective link tuning,
+ * the speed of the average moving towards other values depends
+ * on the value for the number of samples. The higher the number
+ * of samples, the slower the average will move.
+ * We use two variables to keep track of the average value to
+ * compensate for the rounding errors. This can be a significant
+ * error (>5dBm) if the factor is too low.
*/
-#define PERCENTAGE(__value, __total) \
- ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) )
+#define AVG_SAMPLES 8
+#define AVG_FACTOR 1000
+#define MOVING_AVERAGE(__avg, __val) \
+({ \
+ struct avg_val __new; \
+ __new.avg_weight = \
+ (__avg).avg_weight ? \
+ ((((__avg).avg_weight * ((AVG_SAMPLES) - 1)) + \
+ ((__val) * (AVG_FACTOR))) / \
+ (AVG_SAMPLES) ) : \
+ ((__val) * (AVG_FACTOR)); \
+ __new.avg = __new.avg_weight / (AVG_FACTOR); \
+ __new; \
+})
/*
* For calculating the Signal quality we have determined
@@ -98,56 +116,41 @@ static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
- if (ant->rssi_ant && rt2x00dev->link.qual.rx_success)
- return ant->rssi_ant;
+ if (ant->rssi_ant.avg && rt2x00dev->link.qual.rx_success)
+ return ant->rssi_ant.avg;
return DEFAULT_RSSI;
}
-static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev,
- enum antenna antenna)
+static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
- if (ant->rssi_history[antenna - ANTENNA_A])
- return ant->rssi_history[antenna - ANTENNA_A];
+ if (ant->rssi_history)
+ return ant->rssi_history;
return DEFAULT_RSSI;
}
-/* Small wrapper for rt2x00link_antenna_get_rssi_history() */
-#define rt2x00link_antenna_get_rssi_rx_history(__dev) \
- rt2x00link_antenna_get_rssi_history((__dev), \
- (__dev)->link.ant.active.rx)
-#define rt2x00link_antenna_get_rssi_tx_history(__dev) \
- rt2x00link_antenna_get_rssi_history((__dev), \
- (__dev)->link.ant.active.tx)
static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev,
- enum antenna antenna,
int rssi)
{
struct link_ant *ant = &rt2x00dev->link.ant;
- ant->rssi_history[ant->active.rx - ANTENNA_A] = rssi;
+ ant->rssi_history = rssi;
}
-/* Small wrapper for rt2x00link_antenna_get_rssi_history() */
-#define rt2x00link_antenna_update_rssi_rx_history(__dev, __rssi) \
- rt2x00link_antenna_update_rssi_history((__dev), \
- (__dev)->link.ant.active.rx, \
- (__rssi))
-#define rt2x00link_antenna_update_rssi_tx_history(__dev, __rssi) \
- rt2x00link_antenna_update_rssi_history((__dev), \
- (__dev)->link.ant.active.tx, \
- (__rssi))
static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)
{
- rt2x00dev->link.ant.rssi_ant = 0;
+ rt2x00dev->link.ant.rssi_ant.avg = 0;
+ rt2x00dev->link.ant.rssi_ant.avg_weight = 0;
}
static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
struct antenna_setup new_ant;
- int sample_a = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_A);
- int sample_b = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_B);
+ int other_antenna;
+
+ int sample_current = rt2x00link_antenna_get_link_rssi(rt2x00dev);
+ int sample_other = rt2x00link_antenna_get_rssi_history(rt2x00dev);
memcpy(&new_ant, &ant->active, sizeof(new_ant));
@@ -158,22 +161,27 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
/*
* During the last period we have sampled the RSSI
- * from both antenna's. It now is time to determine
+ * from both antennas. It now is time to determine
* which antenna demonstrated the best performance.
* When we are already on the antenna with the best
- * performance, then there really is nothing for us
- * left to do.
+ * performance, just create a good starting point
+ * for the history and we are done.
*/
- if (sample_a == sample_b)
+ if (sample_current >= sample_other) {
+ rt2x00link_antenna_update_rssi_history(rt2x00dev,
+ sample_current);
return;
+ }
+
+ other_antenna = (ant->active.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
if (ant->flags & ANTENNA_RX_DIVERSITY)
- new_ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
+ new_ant.rx = other_antenna;
if (ant->flags & ANTENNA_TX_DIVERSITY)
- new_ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
+ new_ant.tx = other_antenna;
- rt2x00lib_config_antenna(rt2x00dev, &new_ant);
+ rt2x00lib_config_antenna(rt2x00dev, new_ant);
}
static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
@@ -190,8 +198,8 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
* after that update the history with the current value.
*/
rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev);
- rssi_old = rt2x00link_antenna_get_rssi_rx_history(rt2x00dev);
- rt2x00link_antenna_update_rssi_rx_history(rt2x00dev, rssi_curr);
+ rssi_old = rt2x00link_antenna_get_rssi_history(rt2x00dev);
+ rt2x00link_antenna_update_rssi_history(rt2x00dev, rssi_curr);
/*
* Legacy driver indicates that we should swap antenna's
@@ -213,12 +221,13 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
if (ant->flags & ANTENNA_TX_DIVERSITY)
new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
- rt2x00lib_config_antenna(rt2x00dev, &new_ant);
+ rt2x00lib_config_antenna(rt2x00dev, new_ant);
}
-static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
+static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
+ unsigned int flags = ant->flags;
/*
* Determine if software diversity is enabled for
@@ -226,30 +235,38 @@ static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
* Always perform this check since within the link
* tuner interval the configuration might have changed.
*/
- ant->flags &= ~ANTENNA_RX_DIVERSITY;
- ant->flags &= ~ANTENNA_TX_DIVERSITY;
+ flags &= ~ANTENNA_RX_DIVERSITY;
+ flags &= ~ANTENNA_TX_DIVERSITY;
if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
- ant->flags |= ANTENNA_RX_DIVERSITY;
+ flags |= ANTENNA_RX_DIVERSITY;
if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
- ant->flags |= ANTENNA_TX_DIVERSITY;
+ flags |= ANTENNA_TX_DIVERSITY;
if (!(ant->flags & ANTENNA_RX_DIVERSITY) &&
!(ant->flags & ANTENNA_TX_DIVERSITY)) {
ant->flags = 0;
- return;
+ return true;
}
+ /* Update flags */
+ ant->flags = flags;
+
/*
* If we have only sampled the data over the last period
* we should now harvest the data. Otherwise just evaluate
* the data. The latter should only be performed once
* every 2 seconds.
*/
- if (ant->flags & ANTENNA_MODE_SAMPLE)
+ if (ant->flags & ANTENNA_MODE_SAMPLE) {
rt2x00lib_antenna_diversity_sample(rt2x00dev);
- else if (rt2x00dev->link.count & 1)
+ return true;
+ } else if (rt2x00dev->link.count & 1) {
rt2x00lib_antenna_diversity_eval(rt2x00dev);
+ return true;
+ }
+
+ return false;
}
void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
@@ -260,8 +277,6 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
struct link_qual *qual = &rt2x00dev->link.qual;
struct link_ant *ant = &rt2x00dev->link.ant;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- int avg_rssi = rxdesc->rssi;
- int ant_rssi = rxdesc->rssi;
/*
* Frame was received successfully since non-succesfull
@@ -281,16 +296,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
/*
* Update global RSSI
*/
- if (link->avg_rssi)
- avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi, 8);
- link->avg_rssi = avg_rssi;
+ link->avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi);
/*
* Update antenna RSSI
*/
- if (ant->rssi_ant)
- ant_rssi = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi, 8);
- ant->rssi_ant = ant_rssi;
+ ant->rssi_ant = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi);
}
static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev)
@@ -351,8 +362,8 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
rt2x00link_reset_tuner(rt2x00dev, false);
- queue_delayed_work(rt2x00dev->hw->workqueue,
- &link->work, LINK_TUNE_INTERVAL);
+ ieee80211_queue_delayed_work(rt2x00dev->hw,
+ &link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
@@ -423,10 +434,10 @@ static void rt2x00link_tuner(struct work_struct *work)
* collect the RSSI data we could use this. Otherwise we
* must fallback to the default RSSI value.
*/
- if (!link->avg_rssi || !qual->rx_success)
+ if (!link->avg_rssi.avg || !qual->rx_success)
qual->rssi = DEFAULT_RSSI;
else
- qual->rssi = link->avg_rssi;
+ qual->rssi = link->avg_rssi.avg;
/*
* Only perform the link tuning when Link tuning
@@ -444,25 +455,22 @@ static void rt2x00link_tuner(struct work_struct *work)
/*
* Send a signal to the led to update the led signal strength.
*/
- rt2x00leds_led_quality(rt2x00dev, link->avg_rssi);
-
- /*
- * Evaluate antenna setup, make this the last step since this could
- * possibly reset some statistics.
- */
- rt2x00lib_antenna_diversity(rt2x00dev);
+ rt2x00leds_led_quality(rt2x00dev, qual->rssi);
/*
- * Reset the quality counters which recounted during each period.
+ * Evaluate antenna setup, make this the last step when
+ * rt2x00lib_antenna_diversity made changes the quality
+ * statistics will be reset.
*/
- rt2x00link_reset_qual(rt2x00dev);
+ if (rt2x00lib_antenna_diversity(rt2x00dev))
+ rt2x00link_reset_qual(rt2x00dev);
/*
* Increase tuner counter, and reschedule the next link tuner run.
*/
link->count++;
- queue_delayed_work(rt2x00dev->hw->workqueue,
- &link->work, LINK_TUNE_INTERVAL);
+ ieee80211_queue_delayed_work(rt2x00dev->hw,
+ &link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index c4c06b4e1f08..929b85f34f38 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -73,7 +73,8 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
else
rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
- skb->do_not_encrypt = 1;
+ /* Disable hardware encryption */
+ rts_info->control.hw_key = NULL;
/*
* RTS/CTS frame should use the length of the frame plus any
@@ -273,6 +274,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
spin_lock_init(&intf->lock);
spin_lock_init(&intf->seqlock);
+ mutex_init(&intf->beacon_skb_mutex);
intf->beacon = entry;
if (conf->type == NL80211_IFTYPE_AP)
@@ -337,54 +339,38 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
- int status;
/*
- * Mac80211 might be calling this function while we are trying
+ * mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
/*
- * Only change device state when the radio is enabled. It does not
- * matter what parameters we have configured when the radio is disabled
- * because we won't be able to send or receive anyway. Also note that
- * some configuration parameters (e.g. channel and antenna values) can
- * only be set when the radio is enabled.
+ * Some configuration parameters (e.g. channel and antenna values) can
+ * only be set when the radio is enabled, but do require the RX to
+ * be off.
*/
- if (conf->radio_enabled) {
- /* For programming the values, we have to turn RX off */
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
- /* Enable the radio */
- status = rt2x00lib_enable_radio(rt2x00dev);
- if (unlikely(status))
- return status;
+ /*
+ * When we've just turned on the radio, we want to reprogram
+ * everything to ensure a consistent state
+ */
+ rt2x00lib_config(rt2x00dev, conf, changed);
- /*
- * When we've just turned on the radio, we want to reprogram
- * everything to ensure a consistent state
- */
- rt2x00lib_config(rt2x00dev, conf, changed);
+ /*
+ * After the radio has been enabled we need to configure
+ * the antenna to the default settings. rt2x00lib_config_antenna()
+ * should determine if any action should be taken based on
+ * checking if diversity has been enabled or no antenna changes
+ * have been made since the last configuration change.
+ */
+ rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant);
- /*
- * The radio was enabled, configure the antenna to the
- * default settings, the link tuner will later start
- * continue configuring the antenna based on the software
- * diversity. But for non-diversity configurations, we need
- * to have configured the correct state now.
- */
- if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED)
- rt2x00lib_config_antenna(rt2x00dev,
- &rt2x00dev->default_ant);
-
- /* Turn RX back on */
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
- } else {
- /* Disable the radio */
- rt2x00lib_disable_radio(rt2x00dev);
- }
+ /* Turn RX back on */
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
return 0;
}
@@ -393,7 +379,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_config);
void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
- int mc_count, struct dev_addr_list *mc_list)
+ u64 multicast)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -406,6 +392,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
FIF_FCSFAIL |
FIF_PLCPFAIL |
FIF_CONTROL |
+ FIF_PSPOLL |
FIF_OTHER_BSS |
FIF_PROMISC_IN_BSS;
@@ -421,19 +408,42 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
/*
+ * If the device has a single filter for all control frames,
+ * FIF_CONTROL and FIF_PSPOLL flags imply each other.
+ * And if the device has more than one filter for control frames
+ * of different types, but has no a separate filter for PS Poll frames,
+ * FIF_CONTROL flag implies FIF_PSPOLL.
+ */
+ if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags)) {
+ if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL)
+ *total_flags |= FIF_CONTROL | FIF_PSPOLL;
+ }
+ if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags)) {
+ if (*total_flags & FIF_CONTROL)
+ *total_flags |= FIF_PSPOLL;
+ }
+
+ /*
* Check if there is any work left for us.
*/
if (rt2x00dev->packet_filter == *total_flags)
return;
rt2x00dev->packet_filter = *total_flags;
- if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
- rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
- else
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+ rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
}
EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
+int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ bool set)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ rt2x00lib_beacondone(rt2x00dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
+
#ifdef CONFIG_RT2X00_LIB_CRYPTO
static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
{
@@ -572,11 +582,10 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(vif);
- unsigned int delayed = 0;
int update_bssid = 0;
/*
- * Mac80211 might be calling this function while we are trying
+ * mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
@@ -626,30 +635,15 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
else
rt2x00dev->intf_associated--;
- if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
- rt2x00leds_led_assoc(rt2x00dev,
- !!rt2x00dev->intf_associated);
- else
- delayed |= DELAYED_LED_ASSOC;
+ rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
}
/*
* When the erp information has changed, we should perform
* additional configuration steps. For all other changes we are done.
*/
- if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
- if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
- rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
- else
- delayed |= DELAYED_CONFIG_ERP;
- }
-
- spin_lock(&intf->lock);
- if (delayed) {
- intf->delayed_flags |= delayed;
- schedule_work(&rt2x00dev->intf_work);
- }
- spin_unlock(&intf->lock);
+ if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT))
+ rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
}
EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
@@ -687,3 +681,12 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);
+
+void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ bool active = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
+
+ wiphy_rfkill_set_hw_state(hw->wiphy, !active);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 44e5b3279ca7..577029efe320 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -148,35 +148,89 @@ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
dev_kfree_skb_any(skb);
}
-void rt2x00queue_payload_align(struct sk_buff *skb,
- bool l2pad, unsigned int header_length)
+void rt2x00queue_align_frame(struct sk_buff *skb)
{
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
unsigned int frame_length = skb->len;
- unsigned int align = ALIGN_SIZE(skb, header_length);
+ unsigned int align = ALIGN_SIZE(skb, 0);
if (!align)
return;
- if (l2pad) {
- if (skbdesc->flags & SKBDESC_L2_PADDED) {
- /* Remove L2 padding */
- memmove(skb->data + align, skb->data, header_length);
- skb_pull(skb, align);
- skbdesc->flags &= ~SKBDESC_L2_PADDED;
- } else {
- /* Add L2 padding */
- skb_push(skb, align);
- memmove(skb->data, skb->data + align, header_length);
- skbdesc->flags |= SKBDESC_L2_PADDED;
- }
+ skb_push(skb, align);
+ memmove(skb->data, skb->data + align, frame_length);
+ skb_trim(skb, frame_length);
+}
+
+void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_lengt)
+{
+ unsigned int frame_length = skb->len;
+ unsigned int align = ALIGN_SIZE(skb, header_lengt);
+
+ if (!align)
+ return;
+
+ skb_push(skb, align);
+ memmove(skb->data, skb->data + align, frame_length);
+ skb_trim(skb, frame_length);
+}
+
+void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
+{
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+ unsigned int frame_length = skb->len;
+ unsigned int header_align = ALIGN_SIZE(skb, 0);
+ unsigned int payload_align = ALIGN_SIZE(skb, header_length);
+ unsigned int l2pad = 4 - (payload_align - header_align);
+
+ if (header_align == payload_align) {
+ /*
+ * Both header and payload must be moved the same
+ * amount of bytes to align them properly. This means
+ * we don't use the L2 padding but just move the entire
+ * frame.
+ */
+ rt2x00queue_align_frame(skb);
+ } else if (!payload_align) {
+ /*
+ * Simple L2 padding, only the header needs to be moved,
+ * the payload is already properly aligned.
+ */
+ skb_push(skb, header_align);
+ memmove(skb->data, skb->data + header_align, frame_length);
+ skbdesc->flags |= SKBDESC_L2_PADDED;
} else {
- /* Generic payload alignment to 4-byte boundary */
- skb_push(skb, align);
- memmove(skb->data, skb->data + align, frame_length);
+ /*
+ *
+ * Complicated L2 padding, both header and payload need
+ * to be moved. By default we only move to the start
+ * of the buffer, so our header alignment needs to be
+ * increased if there is not enough room for the header
+ * to be moved.
+ */
+ if (payload_align > header_align)
+ header_align += 4;
+
+ skb_push(skb, header_align);
+ memmove(skb->data, skb->data + header_align, header_length);
+ memmove(skb->data + header_length + l2pad,
+ skb->data + header_length + l2pad + header_align,
+ frame_length - header_length);
+ skbdesc->flags |= SKBDESC_L2_PADDED;
}
}
+void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
+{
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+ unsigned int l2pad = 4 - (header_length & 3);
+
+ if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED))
+ return;
+
+ memmove(skb->data + l2pad, skb->data, header_length);
+ skb_pull(skb, l2pad);
+}
+
static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
@@ -324,7 +378,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
/*
* Check if more fragments are pending
*/
- if (ieee80211_has_morefrags(hdr->frame_control)) {
+ if (ieee80211_has_morefrags(hdr->frame_control) ||
+ (tx_info->flags & IEEE80211_TX_CTL_MORE_FRAMES)) {
__set_bit(ENTRY_TXD_BURST, &txdesc->flags);
__set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags);
}
@@ -452,9 +507,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
rt2x00crypto_tx_remove_iv(skb, &txdesc);
}
+ /*
+ * When DMA allocation is required we should guarentee to the
+ * driver that the DMA is aligned to a 4-byte boundary.
+ * However some drivers require L2 padding to pad the payload
+ * rather then the header. This could be a requirement for
+ * PCI and USB devices, while header alignment only is valid
+ * for PCI devices.
+ */
if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags))
- rt2x00queue_payload_align(entry->skb, true,
- txdesc.header_length);
+ rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length);
+ else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
+ rt2x00queue_align_frame(entry->skb);
/*
* It could be possible that the queue was corrupted and this
@@ -490,14 +554,25 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
if (unlikely(!intf->beacon))
return -ENOBUFS;
+ mutex_lock(&intf->beacon_skb_mutex);
+
+ /*
+ * Clean up the beacon skb.
+ */
+ rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb);
+ intf->beacon->skb = NULL;
+
if (!enable_beacon) {
rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_BEACON);
+ mutex_unlock(&intf->beacon_skb_mutex);
return 0;
}
intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
- if (!intf->beacon->skb)
+ if (!intf->beacon->skb) {
+ mutex_unlock(&intf->beacon_skb_mutex);
return -ENOMEM;
+ }
/*
* Copy all TX descriptor information into txdesc,
@@ -535,6 +610,8 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
rt2x00dev->ops->lib->write_beacon(intf->beacon);
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
+ mutex_unlock(&intf->beacon_skb_mutex);
+
return 0;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index b5e06347c8a7..a5591fb2b191 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -29,7 +29,7 @@
#include <linux/prefetch.h>
/**
- * DOC: Entrie frame size
+ * DOC: Entry frame size
*
* Ralink PCI devices demand the Frame size to be a multiple of 128 bytes,
* for USB devices this restriction does not apply, but the value of
@@ -45,13 +45,13 @@
/**
* DOC: Number of entries per queue
*
- * Under normal load without fragmentation 12 entries are sufficient
+ * Under normal load without fragmentation, 12 entries are sufficient
* without the queue being filled up to the maximum. When using fragmentation
- * and the queue threshold code we need to add some additional margins to
+ * and the queue threshold code, we need to add some additional margins to
* make sure the queue will never (or only under extreme load) fill up
* completely.
- * Since we don't use preallocated DMA having a large number of queue entries
- * will have only minimal impact on the memory requirements for the queue.
+ * Since we don't use preallocated DMA, having a large number of queue entries
+ * will have minimal impact on the memory requirements for the queue.
*/
#define RX_ENTRIES 24
#define TX_ENTRIES 24
@@ -214,6 +214,7 @@ struct rxdone_entry_desc {
*
* @TXDONE_UNKNOWN: Hardware could not determine success of transmission.
* @TXDONE_SUCCESS: Frame was successfully send
+ * @TXDONE_FALLBACK: Frame was successfully send using a fallback rate.
* @TXDONE_FAILURE: Frame was not successfully send
* @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the
* frame transmission failed due to excessive retries.
@@ -221,6 +222,7 @@ struct rxdone_entry_desc {
enum txdone_entry_desc_flags {
TXDONE_UNKNOWN,
TXDONE_SUCCESS,
+ TXDONE_FALLBACK,
TXDONE_FAILURE,
TXDONE_EXCESSIVE_RETRY,
};
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index 861322d97fce..983e52e127a7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -176,8 +176,8 @@ struct rt2x00_field32 {
#define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x))
/*
- * Macro's to find first set bit in a variable.
- * These macro's behaves the same as the __ffs() function with
+ * Macros to find first set bit in a variable.
+ * These macros behave the same as the __ffs() functions but
* the most important difference that this is done during
* compile-time rather then run-time.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
deleted file mode 100644
index b6d4c6700bf3..000000000000
--- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
- <http://rt2x00.serialmonkey.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the
- Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- Module: rt2x00rfkill
- Abstract: rt2x00 rfkill routines.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "rt2x00.h"
-#include "rt2x00lib.h"
-
-static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev)
-{
- struct rt2x00_dev *rt2x00dev = poll_dev->private;
- int state, old_state;
-
- if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state) ||
- !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
- return;
-
- /*
- * Poll latest state, if the state is different then the previous state,
- * we should generate an input event.
- */
- state = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
- old_state = !!test_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state);
-
- if (old_state != state) {
- input_report_switch(poll_dev->input, SW_RFKILL_ALL, state);
- change_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state);
- }
-}
-
-void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
-{
- if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
- test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
- return;
-
- if (input_register_polled_device(rt2x00dev->rfkill_poll_dev)) {
- ERROR(rt2x00dev, "Failed to register polled device.\n");
- return;
- }
-
- __set_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
-
- /*
- * Force initial poll which will detect the initial device state,
- * and correctly sends the signal to the input layer about this
- * state.
- */
- rt2x00rfkill_poll(rt2x00dev->rfkill_poll_dev);
-}
-
-void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
-{
- if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
- !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
- return;
-
- input_unregister_polled_device(rt2x00dev->rfkill_poll_dev);
-
- __clear_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
-}
-
-void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
-{
- struct input_polled_dev *poll_dev;
-
- if (test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
- !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
- return;
-
- poll_dev = input_allocate_polled_device();
- if (!poll_dev) {
- ERROR(rt2x00dev, "Failed to allocate polled device.\n");
- return;
- }
-
- poll_dev->private = rt2x00dev;
- poll_dev->poll = rt2x00rfkill_poll;
- poll_dev->poll_interval = RFKILL_POLL_INTERVAL;
-
- poll_dev->input->name = rt2x00dev->ops->name;
- poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy);
- poll_dev->input->id.bustype = BUS_HOST;
- poll_dev->input->id.vendor = 0x1814;
- poll_dev->input->id.product = rt2x00dev->chip.rt;
- poll_dev->input->id.version = rt2x00dev->chip.rev;
- poll_dev->input->dev.parent = wiphy_dev(rt2x00dev->hw->wiphy);
- poll_dev->input->evbit[0] = BIT(EV_SW);
- poll_dev->input->swbit[0] = BIT(SW_RFKILL_ALL);
-
- rt2x00dev->rfkill_poll_dev = poll_dev;
-
- __set_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state);
-}
-
-void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
-{
- if (!__test_and_clear_bit(RFKILL_STATE_ALLOCATED,
- &rt2x00dev->rfkill_state))
- return;
-
- input_free_polled_device(rt2x00dev->rfkill_poll_dev);
- rt2x00dev->rfkill_poll_dev = NULL;
-}
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 49b29ff90c47..b20e3eac9d67 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -237,7 +237,6 @@ static const struct rt2x00debug rt61pci_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -245,9 +244,6 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
return rt2x00_get_field32(reg, MAC_CSR13_BIT5);
}
-#else
-#define rt61pci_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt61pci_brightness_set(struct led_classdev *led_cdev,
@@ -534,7 +530,7 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
- !(filter_flags & FIF_CONTROL));
+ !(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
!(filter_flags & FIF_PROMISC_IN_BSS));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
@@ -602,7 +598,7 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev,
u32 reg;
rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout);
+ rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32);
rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
@@ -1859,8 +1855,6 @@ static void rt61pci_write_beacon(struct queue_entry *entry)
* otherwise we might be sending out invalid data.
*/
rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
- rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
@@ -2316,7 +2310,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
}
/*
- * Determine number of antenna's.
+ * Determine number of antennas.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
__set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags);
@@ -2338,10 +2332,8 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Read frequency offset and RF programming sequence.
@@ -2607,6 +2599,11 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
int retval;
/*
+ * Disable power saving.
+ */
+ rt2x00pci_register_write(rt2x00dev, SOFT_RESET_CSR, 0x00000007);
+
+ /*
* Allocate eeprom data.
*/
retval = rt61pci_validate_eeprom(rt2x00dev);
@@ -2625,6 +2622,12 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
return retval;
/*
+ * This device has multiple filters for control frames,
+ * but has no a separate filter for PS Poll frames.
+ */
+ __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
+
+ /*
* This device requires firmware and DMA mapped skbs.
*/
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
@@ -2722,12 +2725,14 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt61pci_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt61pci_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 6c71f77c8165..93eb699165cc 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -1476,7 +1476,7 @@ struct hw_pairwise_ta_entry {
#define RXD_W15_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index c18848836f2d..1cbd9b4a3efc 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -183,7 +183,6 @@ static const struct rt2x00debug rt73usb_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -191,9 +190,6 @@ static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_read(rt2x00dev, MAC_CSR13, &reg);
return rt2x00_get_field32(reg, MAC_CSR13_BIT7);
}
-#else
-#define rt73usb_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt73usb_brightness_set(struct led_classdev *led_cdev,
@@ -497,7 +493,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
- !(filter_flags & FIF_CONTROL));
+ !(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
!(filter_flags & FIF_PROMISC_IN_BSS));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
@@ -565,7 +561,7 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev,
u32 reg;
rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout);
+ rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32);
rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
@@ -1531,8 +1527,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
* otherwise we might be sending out invalid data.
*/
rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
- rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
@@ -1863,10 +1857,8 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Read frequency offset.
@@ -2150,10 +2142,15 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
return retval;
/*
+ * This device has multiple filters for control frames,
+ * but has no a separate filter for PS Poll frames.
+ */
+ __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
+
+ /*
* This device requires firmware.
*/
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
@@ -2247,12 +2244,14 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt73usb_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt73usb_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index c8016f65b4bd..81fe0be51c42 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -809,7 +809,7 @@ struct hw_pairwise_ta_entry {
/*
* EEPROM antenna.
- * ANTENNA_NUM: Number of antenna's.
+ * ANTENNA_NUM: Number of antennas.
* TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only.
@@ -1058,7 +1058,7 @@ struct hw_pairwise_ta_entry {
#define RXD_W5_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile
index 37e3d4db0c40..93cbfbedb46d 100644
--- a/drivers/net/wireless/rtl818x/Makefile
+++ b/drivers/net/wireless/rtl818x/Makefile
@@ -1,5 +1,5 @@
rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
-rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o
+rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o rtl8187_rfkill.o
obj-$(CONFIG_RTL8180) += rtl8180.o
obj-$(CONFIG_RTL8187) += rtl8187.o
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index 7e65d7c31802..16429c49139c 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -143,7 +143,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(dev, skb);
skb = new_skb;
priv->rx_buf[priv->rx_idx] = skb;
@@ -280,7 +281,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
(ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
remainder = (16 * (skb->len + 4)) %
((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
- if (remainder > 0 && remainder <= 6)
+ if (remainder <= 6)
plcp_len |= 1 << 15;
}
@@ -727,10 +728,16 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
priv->rf->conf_erp(dev, info);
}
+static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ return mc_count;
+}
+
static void rtl8180_configure_filter(struct ieee80211_hw *dev,
unsigned int changed_flags,
unsigned int *total_flags,
- int mc_count, struct dev_addr_list *mclist)
+ u64 multicast)
{
struct rtl8180_priv *priv = dev->priv;
@@ -740,7 +747,7 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev,
priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
if (changed_flags & FIF_OTHER_BSS)
priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
- if (*total_flags & FIF_ALLMULTI || mc_count > 0)
+ if (*total_flags & FIF_ALLMULTI || multicast > 0)
priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
else
priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST;
@@ -767,6 +774,7 @@ static const struct ieee80211_ops rtl8180_ops = {
.remove_interface = rtl8180_remove_interface,
.config = rtl8180_config,
.bss_info_changed = rtl8180_bss_info_changed,
+ .prepare_multicast = rtl8180_prepare_multicast,
.configure_filter = rtl8180_configure_filter,
};
diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h
index c09bfefc70f3..bf9175a8c1f4 100644
--- a/drivers/net/wireless/rtl818x/rtl8187.h
+++ b/drivers/net/wireless/rtl818x/rtl8187.h
@@ -133,6 +133,7 @@ struct rtl8187_priv {
__le16 bits16;
__le32 bits32;
} *io_dmabuf;
+ bool rfkill_off;
};
void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 87a95588a8e3..2017ccc00145 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -32,6 +32,7 @@
#ifdef CONFIG_RTL8187_LEDS
#include "rtl8187_leds.h"
#endif
+#include "rtl8187_rfkill.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
@@ -220,7 +221,7 @@ static void rtl8187_tx_cb(struct urb *urb)
* reading a register in the device. We are in interrupt mode
* here, thus queue the skb and finish on a work queue. */
skb_queue_tail(&priv->b_tx_status.queue, skb);
- queue_delayed_work(hw->workqueue, &priv->work, 0);
+ ieee80211_queue_delayed_work(hw, &priv->work, 0);
}
}
@@ -380,7 +381,8 @@ static void rtl8187_rx_cb(struct urb *urb)
rx_status.flag |= RX_FLAG_TSFT;
if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(dev, skb);
skb = dev_alloc_skb(RTL8187_MAX_RX);
if (unlikely(!skb)) {
@@ -647,10 +649,10 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
/* setup card */
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0);
- rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
+ rtl818x_iowrite8(priv, &priv->map->GPIO0, 0);
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8));
- rtl818x_iowrite8(priv, &priv->map->GPIO, 1);
+ rtl818x_iowrite8(priv, &priv->map->GPIO0, 1);
rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
@@ -673,11 +675,11 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
/* host_usb_init */
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0);
- rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
+ rtl818x_iowrite8(priv, &priv->map->GPIO0, 0);
reg = rtl818x_ioread8(priv, (u8 *)0xFE53);
rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7));
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8));
- rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20);
+ rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x20);
rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80);
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80);
@@ -909,12 +911,12 @@ static int rtl8187_start(struct ieee80211_hw *dev)
u32 reg;
int ret;
+ mutex_lock(&priv->conf_mutex);
+
ret = (!priv->is_rtl8187b) ? rtl8187_init_hw(dev) :
rtl8187b_init_hw(dev);
if (ret)
- return ret;
-
- mutex_lock(&priv->conf_mutex);
+ goto rtl8187_start_exit;
init_usb_anchor(&priv->anchored);
priv->dev = dev;
@@ -941,8 +943,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
(7 << 21 /* MAX TX DMA */));
rtl8187_init_urbs(dev);
rtl8187b_init_status_urb(dev);
- mutex_unlock(&priv->conf_mutex);
- return 0;
+ goto rtl8187_start_exit;
}
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
@@ -986,9 +987,10 @@ static int rtl8187_start(struct ieee80211_hw *dev)
reg |= RTL818X_CMD_RX_ENABLE;
rtl818x_iowrite8(priv, &priv->map->CMD, reg);
INIT_DELAYED_WORK(&priv->work, rtl8187_work);
- mutex_unlock(&priv->conf_mutex);
- return 0;
+rtl8187_start_exit:
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
}
static void rtl8187_stop(struct ieee80211_hw *dev)
@@ -1016,9 +1018,10 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
dev_kfree_skb_any(skb);
usb_kill_anchored_urbs(&priv->anchored);
+ mutex_unlock(&priv->conf_mutex);
+
if (!priv->is_rtl8187b)
cancel_delayed_work_sync(&priv->work);
- mutex_unlock(&priv->conf_mutex);
}
static int rtl8187_add_interface(struct ieee80211_hw *dev,
@@ -1197,10 +1200,16 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
info->use_short_preamble);
}
+static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev,
+ int mc_count, struct dev_addr_list *mc_list)
+{
+ return mc_count;
+}
+
static void rtl8187_configure_filter(struct ieee80211_hw *dev,
unsigned int changed_flags,
unsigned int *total_flags,
- int mc_count, struct dev_addr_list *mclist)
+ u64 multicast)
{
struct rtl8187_priv *priv = dev->priv;
@@ -1210,7 +1219,7 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev,
priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
if (changed_flags & FIF_OTHER_BSS)
priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
- if (*total_flags & FIF_ALLMULTI || mc_count > 0)
+ if (*total_flags & FIF_ALLMULTI || multicast > 0)
priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
else
priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST;
@@ -1273,8 +1282,10 @@ static const struct ieee80211_ops rtl8187_ops = {
.remove_interface = rtl8187_remove_interface,
.config = rtl8187_config,
.bss_info_changed = rtl8187_bss_info_changed,
+ .prepare_multicast = rtl8187_prepare_multicast,
.configure_filter = rtl8187_configure_filter,
- .conf_tx = rtl8187_conf_tx
+ .conf_tx = rtl8187_conf_tx,
+ .rfkill_poll = rtl8187_rfkill_poll
};
static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -1514,6 +1525,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
reg &= 0xFF;
rtl8187_leds_init(dev, reg);
#endif
+ rtl8187_rfkill_init(dev);
return 0;
@@ -1537,6 +1549,7 @@ static void __devexit rtl8187_disconnect(struct usb_interface *intf)
#ifdef CONFIG_RTL8187_LEDS
rtl8187_leds_exit(dev);
#endif
+ rtl8187_rfkill_exit(dev);
ieee80211_unregister_hw(dev);
priv = dev->priv;
diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c
index cf9f899fe0e6..a1c670fc1552 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_leds.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c
@@ -42,7 +42,7 @@ static void led_turn_on(struct work_struct *work)
mutex_lock(&priv->conf_mutex);
switch (led->ledpin) {
case LED_PIN_GPIO0:
- rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01);
+ rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01);
rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x00);
break;
case LED_PIN_LED0:
@@ -80,7 +80,7 @@ static void led_turn_off(struct work_struct *work)
mutex_lock(&priv->conf_mutex);
switch (led->ledpin) {
case LED_PIN_GPIO0:
- rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01);
+ rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01);
rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x01);
break;
case LED_PIN_LED0:
@@ -108,11 +108,11 @@ static void rtl8187_led_brightness_set(struct led_classdev *led_dev,
struct rtl8187_priv *priv = hw->priv;
if (brightness == LED_OFF) {
- queue_delayed_work(hw->workqueue, &priv->led_off, 0);
+ ieee80211_queue_delayed_work(hw, &priv->led_off, 0);
/* The LED is off for 1/20 sec so that it just blinks. */
- queue_delayed_work(hw->workqueue, &priv->led_on, HZ / 20);
+ ieee80211_queue_delayed_work(hw, &priv->led_on, HZ / 20);
} else
- queue_delayed_work(hw->workqueue, &priv->led_on, 0);
+ ieee80211_queue_delayed_work(hw, &priv->led_on, 0);
}
static int rtl8187_register_led(struct ieee80211_hw *dev,
@@ -193,7 +193,7 @@ void rtl8187_leds_init(struct ieee80211_hw *dev, u16 custid)
err = rtl8187_register_led(dev, &priv->led_rx, name,
ieee80211_get_rx_led_name(dev), ledpin);
if (!err) {
- queue_delayed_work(dev->workqueue, &priv->led_on, 0);
+ ieee80211_queue_delayed_work(dev, &priv->led_on, 0);
return;
}
/* registration of RX LED failed - unregister TX */
@@ -209,7 +209,7 @@ void rtl8187_leds_exit(struct ieee80211_hw *dev)
struct rtl8187_priv *priv = dev->priv;
/* turn the LED off before exiting */
- queue_delayed_work(dev->workqueue, &priv->led_off, 0);
+ ieee80211_queue_delayed_work(dev, &priv->led_off, 0);
cancel_delayed_work_sync(&priv->led_off);
cancel_delayed_work_sync(&priv->led_on);
rtl8187_unregister_led(&priv->led_rx);
diff --git a/drivers/net/wireless/rtl818x/rtl8187_rfkill.c b/drivers/net/wireless/rtl818x/rtl8187_rfkill.c
new file mode 100644
index 000000000000..9fab13e4004e
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8187_rfkill.c
@@ -0,0 +1,63 @@
+/*
+ * Linux RFKILL support for RTL8187
+ *
+ * Copyright (c) 2009 Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ *
+ * Based on the RFKILL handling in the r8187 driver, which is:
+ * Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+ *
+ * Thanks to Realtek for their support!
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <net/mac80211.h>
+
+#include "rtl8187.h"
+
+static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv)
+{
+ u8 gpio;
+
+ gpio = rtl818x_ioread8(priv, &priv->map->GPIO0);
+ rtl818x_iowrite8(priv, &priv->map->GPIO0, gpio & ~0x02);
+ gpio = rtl818x_ioread8(priv, &priv->map->GPIO1);
+
+ return gpio & 0x02;
+}
+
+void rtl8187_rfkill_init(struct ieee80211_hw *hw)
+{
+ struct rtl8187_priv *priv = hw->priv;
+
+ priv->rfkill_off = rtl8187_is_radio_enabled(priv);
+ printk(KERN_INFO "rtl8187: wireless switch is %s\n",
+ priv->rfkill_off ? "on" : "off");
+ wiphy_rfkill_set_hw_state(hw->wiphy, !priv->rfkill_off);
+ wiphy_rfkill_start_polling(hw->wiphy);
+}
+
+void rtl8187_rfkill_poll(struct ieee80211_hw *hw)
+{
+ bool enabled;
+ struct rtl8187_priv *priv = hw->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ enabled = rtl8187_is_radio_enabled(priv);
+ if (unlikely(enabled != priv->rfkill_off)) {
+ priv->rfkill_off = enabled;
+ printk(KERN_INFO "rtl8187: wireless radio switch turned %s\n",
+ enabled ? "on" : "off");
+ wiphy_rfkill_set_hw_state(hw->wiphy, !enabled);
+ }
+ mutex_unlock(&priv->conf_mutex);
+}
+
+void rtl8187_rfkill_exit(struct ieee80211_hw *hw)
+{
+ wiphy_rfkill_stop_polling(hw->wiphy);
+}
diff --git a/drivers/net/wireless/rtl818x/rtl8187_rfkill.h b/drivers/net/wireless/rtl818x/rtl8187_rfkill.h
new file mode 100644
index 000000000000..e12575e96d11
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8187_rfkill.h
@@ -0,0 +1,8 @@
+#ifndef RTL8187_RFKILL_H
+#define RTL8187_RFKILL_H
+
+void rtl8187_rfkill_init(struct ieee80211_hw *hw);
+void rtl8187_rfkill_poll(struct ieee80211_hw *hw);
+void rtl8187_rfkill_exit(struct ieee80211_hw *hw);
+
+#endif /* RTL8187_RFKILL_H */
diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h
index 34a5555cc19c..8522490d2e29 100644
--- a/drivers/net/wireless/rtl818x/rtl818x.h
+++ b/drivers/net/wireless/rtl818x/rtl818x.h
@@ -138,8 +138,9 @@ struct rtl818x_csr {
__le32 RF_PARA;
__le32 RF_TIMING;
u8 GP_ENABLE;
- u8 GPIO;
- u8 reserved_12[2];
+ u8 GPIO0;
+ u8 GPIO1;
+ u8 reserved_12;
__le32 HSSI_PARA;
u8 reserved_13[4];
u8 TX_AGC_CTL;
@@ -194,8 +195,18 @@ struct rtl818x_rf_ops {
void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *);
};
-/* Tx/Rx flags are common between RTL818X chips */
-
+/**
+ * enum rtl818x_tx_desc_flags - Tx/Rx flags are common between RTL818X chips
+ *
+ * @RTL818X_TX_DESC_FLAG_NO_ENC: Disable hardware based encryption.
+ * @RTL818X_TX_DESC_FLAG_TX_OK: TX frame was ACKed.
+ * @RTL818X_TX_DESC_FLAG_SPLCP: Use short preamble.
+ * @RTL818X_TX_DESC_FLAG_MOREFRAG: More fragments follow.
+ * @RTL818X_TX_DESC_FLAG_CTS: Use CTS-to-self protection.
+ * @RTL818X_TX_DESC_FLAG_RTS: Use RTS/CTS protection.
+ * @RTL818X_TX_DESC_FLAG_LS: Last segment of the frame.
+ * @RTL818X_TX_DESC_FLAG_FS: First segment of the frame.
+ */
enum rtl818x_tx_desc_flags {
RTL818X_TX_DESC_FLAG_NO_ENC = (1 << 15),
RTL818X_TX_DESC_FLAG_TX_OK = (1 << 15),
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 38366a56b71f..ea6a87c19319 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -1533,7 +1533,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
}
/* Encapsulate a datagram and kick it into a TTY queue. */
-static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t strip_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct strip *strip_info = netdev_priv(dev);
@@ -1550,9 +1550,12 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
if (time_after(jiffies, strip_info->pps_timer + HZ)) {
unsigned long t = jiffies - strip_info->pps_timer;
- unsigned long rx_pps_count = (strip_info->rx_pps_count * HZ * 8 + t / 2) / t;
- unsigned long tx_pps_count = (strip_info->tx_pps_count * HZ * 8 + t / 2) / t;
- unsigned long sx_pps_count = (strip_info->sx_pps_count * HZ * 8 + t / 2) / t;
+ unsigned long rx_pps_count =
+ DIV_ROUND_CLOSEST(strip_info->rx_pps_count*HZ*8, t);
+ unsigned long tx_pps_count =
+ DIV_ROUND_CLOSEST(strip_info->tx_pps_count*HZ*8, t);
+ unsigned long sx_pps_count =
+ DIV_ROUND_CLOSEST(strip_info->sx_pps_count*HZ*8, t);
strip_info->pps_timer = jiffies;
strip_info->rx_pps_count = 0;
@@ -1582,7 +1585,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index ab7fc5c0c8b4..d634b2da3b84 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -2841,7 +2841,8 @@ static int wv_packet_write(struct net_device * dev, void *buf, short length)
* the packet. We also prevent reentrance. Then we call the function
* to send the packet.
*/
-static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
+static netdev_tx_t wavelan_packet_xmit(struct sk_buff *skb,
+ struct net_device * dev)
{
net_local *lp = netdev_priv(dev);
unsigned long flags;
@@ -2891,7 +2892,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
#endif
- return 0;
+ return NETDEV_TX_OK;
}
/*********************** HARDWARE CONFIGURATION ***********************/
diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h
index 2daa0210d789..dbe8de6e5f52 100644
--- a/drivers/net/wireless/wavelan.p.h
+++ b/drivers/net/wireless/wavelan.p.h
@@ -611,7 +611,7 @@ static inline int
wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer. */
void *,
short);
-static int
+static netdev_tx_t
wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */
struct net_device *);
/* -------------------- HARDWARE CONFIGURATION -------------------- */
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index c6d300666ad8..431a20ec6db6 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -3078,7 +3078,7 @@ wv_packet_write(struct net_device * dev,
* the packet. We also prevent reentrance. Then, we call the function
* to send the packet...
*/
-static int
+static netdev_tx_t
wavelan_packet_xmit(struct sk_buff * skb,
struct net_device * dev)
{
@@ -3113,7 +3113,7 @@ wavelan_packet_xmit(struct sk_buff * skb,
* able to detect collisions, therefore in theory we don't really
* need to pad. Jean II */
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
wv_packet_write(dev, skb->data, skb->len);
@@ -3122,7 +3122,7 @@ wavelan_packet_xmit(struct sk_buff * skb,
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
#endif
- return(0);
+ return NETDEV_TX_OK;
}
/********************** HARDWARE CONFIGURATION **********************/
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
index 706fd3007d21..81d91531c4f9 100644
--- a/drivers/net/wireless/wavelan_cs.p.h
+++ b/drivers/net/wireless/wavelan_cs.p.h
@@ -707,7 +707,7 @@ static void
wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer */
void *,
short);
-static int
+static netdev_tx_t
wavelan_packet_xmit(struct sk_buff *, /* Send a packet */
struct net_device *);
/* -------------------- HARDWARE CONFIGURATION -------------------- */
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index a82c4cd436d8..7b14d5bc63d6 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -1,11 +1,52 @@
-config WL12XX
- tristate "TI wl1251/wl1271 support"
- depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS && EXPERIMENTAL
+menuconfig WL12XX
+ boolean "TI wl12xx driver support"
+ depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
+ ---help---
+ This will enable TI wl12xx driver support. The drivers make
+ use of the mac80211 stack.
+
+config WL1251
+ tristate "TI wl1251 support"
+ depends on WL12XX && GENERIC_HARDIRQS
select FW_LOADER
select CRC7
---help---
This module adds support for wireless adapters based on
- TI wl1251/wl1271 chipsets.
+ TI wl1251 chipset.
+
+ If you choose to build a module, it'll be called wl1251. Say
+ N if unsure.
+
+config WL1251_SPI
+ tristate "TI wl1251 SPI support"
+ depends on WL1251 && SPI_MASTER
+ ---help---
+ This module adds support for the SPI interface of adapters using
+ TI wl1251 chipset. Select this if your platform is using
+ the SPI bus.
+
+ If you choose to build a module, it'll be called wl1251_spi.
+ Say N if unsure.
+
+config WL1251_SDIO
+ tristate "TI wl1251 SDIO support"
+ depends on WL1251 && MMC
+ ---help---
+ This module adds support for the SDIO interface of adapters using
+ TI wl1251 chipset. Select this if your platform is using
+ the SDIO bus.
+
+ If you choose to build a module, it'll be called
+ wl1251_sdio. Say N if unsure.
+
+config WL1271
+ tristate "TI wl1271 support"
+ depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS
+ select FW_LOADER
+ select CRC7
+ ---help---
+ This module adds support for wireless adapters based on the
+ TI wl1271 chipset.
- If you choose to build a module, it'll be called wl12xx. Say N if
+ If you choose to build a module, it'll be called wl1271. Say N if
unsure.
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index d43de27dc54c..62e37ad01cc0 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -1,4 +1,14 @@
-wl12xx-objs = main.o spi.o event.o tx.o rx.o \
- ps.o cmd.o acx.o boot.o init.o wl1251.o \
- debugfs.o
-obj-$(CONFIG_WL12XX) += wl12xx.o
+wl1251-objs = wl1251_main.o wl1251_event.o \
+ wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \
+ wl1251_acx.o wl1251_boot.o wl1251_init.o \
+ wl1251_debugfs.o wl1251_io.o
+
+obj-$(CONFIG_WL1251) += wl1251.o
+obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o
+obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o
+
+wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \
+ wl1271_event.o wl1271_tx.o wl1271_rx.o \
+ wl1271_ps.o wl1271_acx.o wl1271_boot.o \
+ wl1271_init.o wl1271_debugfs.o
+obj-$(CONFIG_WL1271) += wl1271.o
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
deleted file mode 100644
index 1cfd458ad5ab..000000000000
--- a/drivers/net/wireless/wl12xx/acx.c
+++ /dev/null
@@ -1,689 +0,0 @@
-#include "acx.h"
-
-#include <linux/module.h>
-#include <linux/crc7.h>
-#include <linux/spi/spi.h>
-
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
-#include "reg.h"
-#include "spi.h"
-#include "ps.h"
-
-int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod,
- u8 mgt_rate, u8 mgt_mod)
-{
- int ret;
- struct acx_fw_gen_frame_rates rates;
-
- wl12xx_debug(DEBUG_ACX, "acx frame rates");
-
- rates.header.id = ACX_FW_GEN_FRAME_RATES;
- rates.header.len = sizeof(struct acx_fw_gen_frame_rates) -
- sizeof(struct acx_header);
-
- rates.tx_ctrl_frame_rate = ctrl_rate;
- rates.tx_ctrl_frame_mod = ctrl_mod;
- rates.tx_mgt_frame_rate = mgt_rate;
- rates.tx_mgt_frame_mod = mgt_mod;
-
- ret = wl12xx_cmd_configure(wl, &rates, sizeof(rates));
- if (ret < 0) {
- wl12xx_error("Failed to set FW rates and modulation");
- return ret;
- }
-
- return 0;
-}
-
-
-int wl12xx_acx_station_id(struct wl12xx *wl)
-{
- int ret, i;
- struct dot11_station_id mac;
-
- wl12xx_debug(DEBUG_ACX, "acx dot11_station_id");
-
- mac.header.id = DOT11_STATION_ID;
- mac.header.len = sizeof(mac) - sizeof(struct acx_header);
-
- for (i = 0; i < ETH_ALEN; i++)
- mac.mac[i] = wl->mac_addr[ETH_ALEN - 1 - i];
-
- ret = wl12xx_cmd_configure(wl, &mac, sizeof(mac));
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id)
-{
- struct acx_dot11_default_key default_key;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id);
-
- default_key.header.id = DOT11_DEFAULT_KEY;
- default_key.header.len = sizeof(default_key) -
- sizeof(struct acx_header);
-
- default_key.id = key_id;
-
- ret = wl12xx_cmd_configure(wl, &default_key, sizeof(default_key));
- if (ret < 0) {
- wl12xx_error("Couldnt set default key");
- return ret;
- }
-
- wl->default_key = key_id;
-
- return 0;
-}
-
-int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval)
-{
- struct acx_wake_up_condition wake_up;
-
- wl12xx_debug(DEBUG_ACX, "acx wake up conditions");
-
- wake_up.header.id = ACX_WAKE_UP_CONDITIONS;
- wake_up.header.len = sizeof(wake_up) - sizeof(struct acx_header);
-
- wake_up.wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP;
- wake_up.listen_interval = listen_interval;
-
- return wl12xx_cmd_configure(wl, &wake_up, sizeof(wake_up));
-}
-
-int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth)
-{
- int ret;
- struct acx_sleep_auth auth;
-
- wl12xx_debug(DEBUG_ACX, "acx sleep auth");
-
- auth.header.id = ACX_SLEEP_AUTH;
- auth.header.len = sizeof(auth) - sizeof(struct acx_header);
-
- auth.sleep_auth = sleep_auth;
-
- ret = wl12xx_cmd_configure(wl, &auth, sizeof(auth));
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len)
-{
- struct wl12xx_command cmd;
- struct acx_revision *rev;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx fw rev");
-
- memset(&cmd, 0, sizeof(cmd));
-
- ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, sizeof(*rev), &cmd);
- if (ret < 0) {
- wl12xx_warning("ACX_FW_REV interrogate failed");
- return ret;
- }
-
- rev = (struct acx_revision *) &cmd.parameters;
-
- /* be careful with the buffer sizes */
- strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
-
- /*
- * if the firmware version string is exactly
- * sizeof(rev->fw_version) long or fw_len is less than
- * sizeof(rev->fw_version) it won't be null terminated
- */
- buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
-
- return 0;
-}
-
-int wl12xx_acx_tx_power(struct wl12xx *wl, int power)
-{
- struct acx_current_tx_power ie;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr");
-
- if (power < 0 || power > 25)
- return -EINVAL;
-
- memset(&ie, 0, sizeof(ie));
-
- ie.header.id = DOT11_CUR_TX_PWR;
- ie.header.len = sizeof(ie) - sizeof(struct acx_header);
- ie.current_tx_power = power * 10;
-
- ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
- if (ret < 0) {
- wl12xx_warning("configure of tx power failed: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_feature_cfg(struct wl12xx *wl)
-{
- struct acx_feature_config feature;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx feature cfg");
-
- memset(&feature, 0, sizeof(feature));
-
- feature.header.id = ACX_FEATURE_CFG;
- feature.header.len = sizeof(feature) - sizeof(struct acx_header);
-
- /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
- feature.data_flow_options = 0;
- feature.options = 0;
-
- ret = wl12xx_cmd_configure(wl, &feature, sizeof(feature));
- if (ret < 0)
- wl12xx_error("Couldnt set HW encryption");
-
- return ret;
-}
-
-int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len)
-{
- struct wl12xx_command cmd;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx mem map");
-
- ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, len, &cmd);
- if (ret < 0)
- return ret;
- else if (cmd.status != CMD_STATUS_SUCCESS)
- return -EIO;
-
- memcpy(mem_map, &cmd.parameters, len);
-
- return 0;
-}
-
-int wl12xx_acx_data_path_params(struct wl12xx *wl,
- struct acx_data_path_params_resp *data_path)
-{
- struct acx_data_path_params params;
- struct wl12xx_command cmd;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx data path params");
-
- params.rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE;
- params.tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE;
-
- params.rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM;
- params.tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM;
-
- params.tx_complete_threshold = 1;
-
- params.tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE;
-
- params.tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT;
-
- params.header.id = ACX_DATA_PATH_PARAMS;
- params.header.len = sizeof(params) - sizeof(struct acx_header);
-
- ret = wl12xx_cmd_configure(wl, &params, sizeof(params));
- if (ret < 0)
- return ret;
-
-
- ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS,
- sizeof(struct acx_data_path_params_resp),
- &cmd);
-
- if (ret < 0) {
- wl12xx_warning("failed to read data path parameters: %d", ret);
- return ret;
- } else if (cmd.status != CMD_STATUS_SUCCESS) {
- wl12xx_warning("data path parameter acx status failed");
- return -EIO;
- }
-
- memcpy(data_path, &cmd.parameters, sizeof(*data_path));
-
- return 0;
-}
-
-int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time)
-{
- struct rx_msdu_lifetime msdu_lifetime;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx rx msdu life time");
-
- msdu_lifetime.header.id = DOT11_RX_MSDU_LIFE_TIME;
- msdu_lifetime.header.len = sizeof(msdu_lifetime) -
- sizeof(struct acx_header);
- msdu_lifetime.lifetime = life_time;
-
- ret = wl12xx_cmd_configure(wl, &msdu_lifetime, sizeof(msdu_lifetime));
- if (ret < 0) {
- wl12xx_warning("failed to set rx msdu life time: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter)
-{
- struct acx_rx_config rx_config;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx rx config");
-
- rx_config.header.id = ACX_RX_CFG;
- rx_config.header.len = sizeof(rx_config) - sizeof(struct acx_header);
- rx_config.config_options = config;
- rx_config.filter_options = filter;
-
- ret = wl12xx_cmd_configure(wl, &rx_config, sizeof(rx_config));
- if (ret < 0) {
- wl12xx_warning("failed to set rx config: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_pd_threshold(struct wl12xx *wl)
-{
- struct acx_packet_detection packet_detection;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx data pd threshold");
-
- /* FIXME: threshold value not set */
- packet_detection.header.id = ACX_PD_THRESHOLD;
- packet_detection.header.len = sizeof(packet_detection) -
- sizeof(struct acx_header);
-
- ret = wl12xx_cmd_configure(wl, &packet_detection,
- sizeof(packet_detection));
- if (ret < 0) {
- wl12xx_warning("failed to set pd threshold: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time)
-{
- struct acx_slot slot;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx slot");
-
- slot.header.id = ACX_SLOT;
- slot.header.len = sizeof(slot) - sizeof(struct acx_header);
-
- slot.wone_index = STATION_WONE_INDEX;
- slot.slot_time = slot_time;
-
- ret = wl12xx_cmd_configure(wl, &slot, sizeof(slot));
- if (ret < 0) {
- wl12xx_warning("failed to set slot time: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_group_address_tbl(struct wl12xx *wl)
-{
- struct multicast_grp_addr_start multicast;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx group address tbl");
-
- /* MAC filtering */
- multicast.header.id = DOT11_GROUP_ADDRESS_TBL;
- multicast.header.len = sizeof(multicast) - sizeof(struct acx_header);
-
- multicast.enabled = 0;
- multicast.num_groups = 0;
- memset(multicast.mac_table, 0, ADDRESS_GROUP_MAX_LEN);
-
- ret = wl12xx_cmd_configure(wl, &multicast, sizeof(multicast));
- if (ret < 0) {
- wl12xx_warning("failed to set group addr table: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_service_period_timeout(struct wl12xx *wl)
-{
- struct acx_rx_timeout rx_timeout;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx service period timeout");
-
- /* RX timeout */
- rx_timeout.header.id = ACX_SERVICE_PERIOD_TIMEOUT;
- rx_timeout.header.len = sizeof(rx_timeout) - sizeof(struct acx_header);
-
- rx_timeout.ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF;
- rx_timeout.upsd_timeout = RX_TIMEOUT_UPSD_DEF;
-
- ret = wl12xx_cmd_configure(wl, &rx_timeout, sizeof(rx_timeout));
- if (ret < 0) {
- wl12xx_warning("failed to set service period timeout: %d",
- ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold)
-{
- struct acx_rts_threshold rts;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx rts threshold");
-
- rts.header.id = DOT11_RTS_THRESHOLD;
- rts.header.len = sizeof(rts) - sizeof(struct acx_header);
-
- rts.threshold = rts_threshold;
-
- ret = wl12xx_cmd_configure(wl, &rts, sizeof(rts));
- if (ret < 0) {
- wl12xx_warning("failed to set rts threshold: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl)
-{
- struct acx_beacon_filter_option beacon_filter;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx beacon filter opt");
-
- beacon_filter.header.id = ACX_BEACON_FILTER_OPT;
- beacon_filter.header.len = sizeof(beacon_filter) -
- sizeof(struct acx_header);
-
- beacon_filter.enable = 0;
- beacon_filter.max_num_beacons = 0;
-
- ret = wl12xx_cmd_configure(wl, &beacon_filter, sizeof(beacon_filter));
- if (ret < 0) {
- wl12xx_warning("failed to set beacon filter opt: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_beacon_filter_table(struct wl12xx *wl)
-{
- struct acx_beacon_filter_ie_table ie_table;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx beacon filter table");
-
- ie_table.header.id = ACX_BEACON_FILTER_TABLE;
- ie_table.header.len = sizeof(ie_table) - sizeof(struct acx_header);
-
- ie_table.num_ie = 0;
- memset(ie_table.table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
-
- ret = wl12xx_cmd_configure(wl, &ie_table, sizeof(ie_table));
- if (ret < 0) {
- wl12xx_warning("failed to set beacon filter table: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_sg_enable(struct wl12xx *wl)
-{
- struct acx_bt_wlan_coex pta;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx sg enable");
-
- pta.header.id = ACX_SG_ENABLE;
- pta.header.len = sizeof(pta) - sizeof(struct acx_header);
-
- pta.enable = SG_ENABLE;
-
- ret = wl12xx_cmd_configure(wl, &pta, sizeof(pta));
- if (ret < 0) {
- wl12xx_warning("failed to set softgemini enable: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_sg_cfg(struct wl12xx *wl)
-{
- struct acx_bt_wlan_coex_param param;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx sg cfg");
-
- /* BT-WLAN coext parameters */
- param.header.id = ACX_SG_CFG;
- param.header.len = sizeof(param) - sizeof(struct acx_header);
-
- param.min_rate = RATE_INDEX_24MBPS;
- param.bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF;
- param.wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF;
- param.sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF;
- param.rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF;
- param.tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF;
- param.rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF;
- param.tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF;
- param.wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF;
- param.bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF;
- param.next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF;
- param.wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF;
- param.hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF;
- param.next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF;
- param.antenna_type = PTA_ANTENNA_TYPE_DEF;
- param.signal_type = PTA_SIGNALING_TYPE_DEF;
- param.afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF;
- param.quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF;
- param.max_cts = PTA_MAX_NUM_CTS_DEF;
- param.wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF;
- param.bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF;
- param.missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF;
- param.wlan_elp_hp = PTA_ELP_HP_DEF;
- param.bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF;
- param.ack_mode_dual_ant = PTA_ACK_MODE_DEF;
- param.pa_sd_enable = PTA_ALLOW_PA_SD_DEF;
- param.pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF;
- param.bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF;
-
- ret = wl12xx_cmd_configure(wl, &param, sizeof(param));
- if (ret < 0) {
- wl12xx_warning("failed to set sg config: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_cca_threshold(struct wl12xx *wl)
-{
- struct acx_energy_detection detection;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx cca threshold");
-
- detection.header.id = ACX_CCA_THRESHOLD;
- detection.header.len = sizeof(detection) - sizeof(struct acx_header);
-
- detection.rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
- detection.tx_energy_detection = 0;
-
- ret = wl12xx_cmd_configure(wl, &detection, sizeof(detection));
- if (ret < 0) {
- wl12xx_warning("failed to set cca threshold: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl)
-{
- struct acx_beacon_broadcast bb;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx bcn dtim options");
-
- bb.header.id = ACX_BCN_DTIM_OPTIONS;
- bb.header.len = sizeof(bb) - sizeof(struct acx_header);
-
- bb.beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE;
- bb.broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE;
- bb.rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE;
- bb.ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF;
-
- ret = wl12xx_cmd_configure(wl, &bb, sizeof(bb));
- if (ret < 0) {
- wl12xx_warning("failed to set rx config: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_aid(struct wl12xx *wl, u16 aid)
-{
- struct acx_aid acx_aid;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx aid");
-
- acx_aid.header.id = ACX_AID;
- acx_aid.header.len = sizeof(acx_aid) - sizeof(struct acx_header);
-
- acx_aid.aid = aid;
-
- ret = wl12xx_cmd_configure(wl, &acx_aid, sizeof(acx_aid));
- if (ret < 0) {
- wl12xx_warning("failed to set aid: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask)
-{
- struct acx_event_mask mask;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx event mbox mask");
-
- mask.header.id = ACX_EVENT_MBOX_MASK;
- mask.header.len = sizeof(mask) - sizeof(struct acx_header);
-
- /* high event mask is unused */
- mask.high_event_mask = 0xffffffff;
-
- mask.event_mask = event_mask;
-
- ret = wl12xx_cmd_configure(wl, &mask, sizeof(mask));
- if (ret < 0) {
- wl12xx_warning("failed to set aid: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble)
-{
- struct acx_preamble ie;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx_set_preamble");
-
- memset(&ie, 0, sizeof(ie));
-
- ie.header.id = ACX_PREAMBLE_TYPE;
- ie.header.len = sizeof(ie) - sizeof(struct acx_header);
- ie.preamble = preamble;
- ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
- if (ret < 0) {
- wl12xx_warning("Setting of preamble failed: %d", ret);
- return ret;
- }
- return 0;
-}
-
-int wl12xx_acx_cts_protect(struct wl12xx *wl,
- enum acx_ctsprotect_type ctsprotect)
-{
- struct acx_ctsprotect ie;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect");
-
- memset(&ie, 0, sizeof(ie));
-
- ie.header.id = ACX_CTS_PROTECTION;
- ie.header.len = sizeof(ie) - sizeof(struct acx_header);
- ie.ctsprotect = ctsprotect;
- ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
- if (ret < 0) {
- wl12xx_warning("Setting of ctsprotect failed: %d", ret);
- return ret;
- }
- return 0;
-}
-
-int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats)
-{
- struct wl12xx_command *answer;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx statistics");
-
- answer = kmalloc(sizeof(*answer), GFP_KERNEL);
- if (!answer) {
- wl12xx_warning("could not allocate memory for acx statistics");
- ret = -ENOMEM;
- goto out;
- }
-
- ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, sizeof(*answer),
- answer);
- if (ret < 0) {
- wl12xx_warning("acx statistics failed: %d", ret);
- goto out;
- }
-
- memcpy(stats, answer->parameters, sizeof(*stats));
-
-out:
- kfree(answer);
- return ret;
-}
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
deleted file mode 100644
index 48ac08c429bd..000000000000
--- a/drivers/net/wireless/wl12xx/boot.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * This file is part of wl12xx
- *
- * Copyright (C) 2008 Nokia Corporation
- *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/gpio.h>
-
-#include "reg.h"
-#include "boot.h"
-#include "spi.h"
-#include "event.h"
-
-static void wl12xx_boot_enable_interrupts(struct wl12xx *wl)
-{
- enable_irq(wl->irq);
-}
-
-void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl)
-{
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
- wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
-}
-
-int wl12xx_boot_soft_reset(struct wl12xx *wl)
-{
- unsigned long timeout;
- u32 boot_data;
-
- /* perform soft reset */
- wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
-
- /* SOFT_RESET is self clearing */
- timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
- while (1) {
- boot_data = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
- wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
- if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
- break;
-
- if (time_after(jiffies, timeout)) {
- /* 1.2 check pWhalBus->uSelfClearTime if the
- * timeout was reached */
- wl12xx_error("soft reset timeout");
- return -1;
- }
-
- udelay(SOFT_RESET_STALL_TIME);
- }
-
- /* disable Rx/Tx */
- wl12xx_reg_write32(wl, ENABLE, 0x0);
-
- /* disable auto calibration on start*/
- wl12xx_reg_write32(wl, SPARE_A2, 0xffff);
-
- return 0;
-}
-
-int wl12xx_boot_init_seq(struct wl12xx *wl)
-{
- u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq;
-
- /*
- * col #1: INTEGER_DIVIDER
- * col #2: FRACTIONAL_DIVIDER
- * col #3: ATTN_BB
- * col #4: ALPHA_BB
- * col #5: STOP_TIME_BB
- * col #6: BB_PLL_LOOP_FILTER
- */
- static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = {
-
- { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/
- { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/
- { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/
- { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/
- { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */
- };
-
- /* read NVS params */
- scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6);
- wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6);
-
- /* read ELP_CMD */
- elp_cmd = wl12xx_reg_read32(wl, ELP_CMD);
- wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd);
-
- /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */
- ref_freq = scr_pad6 & 0x000000FF;
- wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq);
-
- wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9);
-
- /*
- * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME)
- */
- wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6);
-
- /*
- * set the clock detect feature to work in the restart wu procedure
- * (ELP_CFG_MODE[14]) and Select the clock source type
- * (ELP_CFG_MODE[13:12])
- */
- tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000;
- wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp);
-
- /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */
- elp_cmd |= 0x00000040;
- wl12xx_reg_write32(wl, ELP_CMD, elp_cmd);
-
- /* PG 1.2: Set the BB PLL stable time to be 1000usec
- * (PLL_STABLE_TIME) */
- wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20);
-
- /* PG 1.2: read clock request time */
- init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME);
-
- /*
- * PG 1.2: set the clock request time to be ref_clk_settling_time -
- * 1ms = 4ms
- */
- if (init_data > 0x21)
- tmp = init_data - 0x21;
- else
- tmp = 0;
- wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp);
-
- /* set BB PLL configurations in RF AFE */
- wl12xx_reg_write32(wl, 0x003058cc, 0x4B5);
-
- /* set RF_AFE_REG_5 */
- wl12xx_reg_write32(wl, 0x003058d4, 0x50);
-
- /* set RF_AFE_CTRL_REG_2 */
- wl12xx_reg_write32(wl, 0x00305948, 0x11c001);
-
- /*
- * change RF PLL and BB PLL divider for VCO clock and adjust VCO
- * bais current(RF_AFE_REG_13)
- */
- wl12xx_reg_write32(wl, 0x003058f4, 0x1e);
-
- /* set BB PLL configurations */
- tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000;
- wl12xx_reg_write32(wl, 0x00305840, tmp);
-
- /* set fractional divider according to Appendix C-BB PLL
- * Calculations
- */
- tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER];
- wl12xx_reg_write32(wl, 0x00305844, tmp);
-
- /* set the initial data for the sigma delta */
- wl12xx_reg_write32(wl, 0x00305848, 0x3039);
-
- /*
- * set the accumulator attenuation value, calibration loop1
- * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and
- * the VCO gain
- */
- tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) |
- (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1;
- wl12xx_reg_write32(wl, 0x00305854, tmp);
-
- /*
- * set the calibration stop time after holdoff time expires and set
- * settling time HOLD_OFF_TIME_BB
- */
- tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000;
- wl12xx_reg_write32(wl, 0x00305858, tmp);
-
- /*
- * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL
- * constant leakage current to linearize PFD to 0uA -
- * BB_ILOOPF[7:3]
- */
- tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030;
- wl12xx_reg_write32(wl, 0x003058f8, tmp);
-
- /*
- * set regulator output voltage for n divider to
- * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2],
- * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB
- * PLL auto-call to normal mode- BB_CALGAIN_3DB[8]
- */
- wl12xx_reg_write32(wl, 0x003058f0, 0x29);
-
- /* enable restart wakeup sequence (ELP_CMD[0]) */
- wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1);
-
- /* restart sequence completed */
- udelay(2000);
-
- return 0;
-}
-
-int wl12xx_boot_run_firmware(struct wl12xx *wl)
-{
- int loop, ret;
- u32 chip_id, interrupt;
-
- wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
-
- chip_id = wl12xx_reg_read32(wl, CHIP_ID_B);
-
- wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
-
- if (chip_id != wl->chip.id) {
- wl12xx_error("chip id doesn't match after firmware boot");
- return -EIO;
- }
-
- /* wait for init to complete */
- loop = 0;
- while (loop++ < INIT_LOOP) {
- udelay(INIT_LOOP_DELAY);
- interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
-
- if (interrupt == 0xffffffff) {
- wl12xx_error("error reading hardware complete "
- "init indication");
- return -EIO;
- }
- /* check that ACX_INTR_INIT_COMPLETE is enabled */
- else if (interrupt & wl->chip.intr_init_complete) {
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
- wl->chip.intr_init_complete);
- break;
- }
- }
-
- if (loop >= INIT_LOOP) {
- wl12xx_error("timeout waiting for the hardware to "
- "complete initialization");
- return -EIO;
- }
-
- /* get hardware config command mail box */
- wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
-
- /* get hardware config event mail box */
- wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
-
- /* set the working partition to its "running" mode offset */
- wl12xx_set_partition(wl,
- wl->chip.p_table[PART_WORK].mem.start,
- wl->chip.p_table[PART_WORK].mem.size,
- wl->chip.p_table[PART_WORK].reg.start,
- wl->chip.p_table[PART_WORK].reg.size);
-
- wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
- wl->cmd_box_addr, wl->event_box_addr);
-
- /*
- * in case of full asynchronous mode the firmware event must be
- * ready to receive event from the command mailbox
- */
-
- /* enable gpio interrupts */
- wl12xx_boot_enable_interrupts(wl);
-
- wl->chip.op_target_enable_interrupts(wl);
-
- /* unmask all mbox events */
- wl->event_mask = 0xffffffff;
-
- ret = wl12xx_event_unmask(wl);
- if (ret < 0) {
- wl12xx_error("EVENT mask setting failed");
- return ret;
- }
-
- wl12xx_event_mbox_config(wl);
-
- /* firmware startup completed */
- return 0;
-}
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
deleted file mode 100644
index f73ab602b7ae..000000000000
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ /dev/null
@@ -1,353 +0,0 @@
-#include "cmd.h"
-
-#include <linux/module.h>
-#include <linux/crc7.h>
-#include <linux/spi/spi.h>
-
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
-#include "reg.h"
-#include "spi.h"
-#include "ps.h"
-
-int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len)
-{
- struct wl12xx_command cmd;
- unsigned long timeout;
- size_t cmd_len;
- u32 intr;
- int ret = 0;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.id = type;
- cmd.status = 0;
- memcpy(cmd.parameters, buf, buf_len);
- cmd_len = ALIGN(buf_len, 4) + CMDMBOX_HEADER_LEN;
-
- wl12xx_ps_elp_wakeup(wl);
-
- wl12xx_spi_mem_write(wl, wl->cmd_box_addr, &cmd, cmd_len);
-
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
-
- timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT);
-
- intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
- while (!(intr & wl->chip.intr_cmd_complete)) {
- if (time_after(jiffies, timeout)) {
- wl12xx_error("command complete timeout");
- ret = -ETIMEDOUT;
- goto out;
- }
-
- msleep(1);
-
- intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
- }
-
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
- wl->chip.intr_cmd_complete);
-
-out:
- wl12xx_ps_elp_sleep(wl);
-
- return ret;
-}
-
-int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer)
-{
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd test");
-
- ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len);
- if (ret < 0) {
- wl12xx_warning("TEST command failed");
- return ret;
- }
-
- if (answer) {
- struct wl12xx_command *cmd_answer;
-
- /*
- * The test command got in, we can read the answer.
- * The answer would be a wl12xx_command, where the
- * parameter array contains the actual answer.
- */
-
- wl12xx_ps_elp_wakeup(wl);
-
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
-
- wl12xx_ps_elp_sleep(wl);
-
- cmd_answer = buf;
- if (cmd_answer->status != CMD_STATUS_SUCCESS)
- wl12xx_error("TEST command answer error: %d",
- cmd_answer->status);
- }
-
- return 0;
-}
-
-
-int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len,
- void *answer)
-{
- struct wl12xx_command *cmd;
- struct acx_header header;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd interrogate");
-
- header.id = ie_id;
- header.len = ie_len - sizeof(header);
-
- ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, &header, sizeof(header));
- if (ret < 0) {
- wl12xx_error("INTERROGATE command failed");
- return ret;
- }
-
- wl12xx_ps_elp_wakeup(wl);
-
- /* the interrogate command got in, we can read the answer */
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, answer,
- CMDMBOX_HEADER_LEN + ie_len);
-
- wl12xx_ps_elp_sleep(wl);
-
- cmd = answer;
- if (cmd->status != CMD_STATUS_SUCCESS)
- wl12xx_error("INTERROGATE command error: %d",
- cmd->status);
-
- return 0;
-
-}
-
-int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len)
-{
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd configure");
-
- ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, ie,
- ie_len);
- if (ret < 0) {
- wl12xx_warning("CONFIGURE command NOK");
- return ret;
- }
-
- return 0;
-
-}
-
-int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity,
- void *bitmap, u16 bitmap_len, u8 bitmap_control)
-{
- struct vbm_update_request vbm;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd vbm");
-
- /* Count and period will be filled by the target */
- vbm.tim.bitmap_ctrl = bitmap_control;
- if (bitmap_len > PARTIAL_VBM_MAX) {
- wl12xx_warning("cmd vbm len is %d B, truncating to %d",
- bitmap_len, PARTIAL_VBM_MAX);
- bitmap_len = PARTIAL_VBM_MAX;
- }
- memcpy(vbm.tim.pvb_field, bitmap, bitmap_len);
- vbm.tim.identity = identity;
- vbm.tim.length = bitmap_len + 3;
-
- vbm.len = cpu_to_le16(bitmap_len + 5);
-
- ret = wl12xx_cmd_send(wl, CMD_VBM, &vbm, sizeof(vbm));
- if (ret < 0) {
- wl12xx_error("VBM command failed");
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable)
-{
- int ret;
- u16 cmd_rx, cmd_tx;
-
- wl12xx_debug(DEBUG_CMD, "cmd data path");
-
- if (enable) {
- cmd_rx = CMD_ENABLE_RX;
- cmd_tx = CMD_ENABLE_TX;
- } else {
- cmd_rx = CMD_DISABLE_RX;
- cmd_tx = CMD_DISABLE_TX;
- }
-
- ret = wl12xx_cmd_send(wl, cmd_rx, &channel, sizeof(channel));
- if (ret < 0) {
- wl12xx_error("rx %s cmd for channel %d failed",
- enable ? "start" : "stop", channel);
- return ret;
- }
-
- wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d",
- enable ? "start" : "stop", channel);
-
- ret = wl12xx_cmd_send(wl, cmd_tx, &channel, sizeof(channel));
- if (ret < 0) {
- wl12xx_error("tx %s cmd for channel %d failed",
- enable ? "start" : "stop", channel);
- return ret;
- }
-
- wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d",
- enable ? "start" : "stop", channel);
-
- return 0;
-}
-
-int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval,
- u16 beacon_interval, u8 wait)
-{
- unsigned long timeout;
- struct cmd_join join = {};
- int ret, i;
- u8 *bssid;
-
- /* FIXME: this should be in main.c */
- ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE,
- DEFAULT_HW_GEN_MODULATION_TYPE,
- wl->tx_mgmt_frm_rate,
- wl->tx_mgmt_frm_mod);
- if (ret < 0)
- return ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd join");
-
- /* Reverse order BSSID */
- bssid = (u8 *)&join.bssid_lsb;
- for (i = 0; i < ETH_ALEN; i++)
- bssid[i] = wl->bssid[ETH_ALEN - i - 1];
-
- join.rx_config_options = wl->rx_config;
- join.rx_filter_options = wl->rx_filter;
-
- join.basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
- RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
-
- join.beacon_interval = beacon_interval;
- join.dtim_interval = dtim_interval;
- join.bss_type = bss_type;
- join.channel = wl->channel;
- join.ctrl = JOIN_CMD_CTRL_TX_FLUSH;
-
- ret = wl12xx_cmd_send(wl, CMD_START_JOIN, &join, sizeof(join));
- if (ret < 0) {
- wl12xx_error("failed to initiate cmd join");
- return ret;
- }
-
- timeout = msecs_to_jiffies(JOIN_TIMEOUT);
-
- /*
- * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
- * simplify locking we just sleep instead, for now
- */
- if (wait)
- msleep(10);
-
- return 0;
-}
-
-int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode)
-{
- int ret;
- struct acx_ps_params ps_params;
-
- /* FIXME: this should be in ps.c */
- ret = wl12xx_acx_wake_up_conditions(wl, wl->listen_int);
- if (ret < 0) {
- wl12xx_error("Couldnt set wake up conditions");
- return ret;
- }
-
- wl12xx_debug(DEBUG_CMD, "cmd set ps mode");
-
- ps_params.ps_mode = ps_mode;
- ps_params.send_null_data = 1;
- ps_params.retries = 5;
- ps_params.hang_over_period = 128;
- ps_params.null_data_rate = 1; /* 1 Mbps */
-
- ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, &ps_params,
- sizeof(ps_params));
- if (ret < 0) {
- wl12xx_error("cmd set_ps_mode failed");
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer)
-{
- struct cmd_read_write_memory mem_cmd, *mem_answer;
- struct wl12xx_command cmd;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd read memory");
-
- memset(&mem_cmd, 0, sizeof(mem_cmd));
- mem_cmd.addr = addr;
- mem_cmd.size = len;
-
- ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, &mem_cmd, sizeof(mem_cmd));
- if (ret < 0) {
- wl12xx_error("read memory command failed: %d", ret);
- return ret;
- }
-
- /* the read command got in, we can now read the answer */
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, &cmd,
- CMDMBOX_HEADER_LEN + sizeof(mem_cmd));
-
- if (cmd.status != CMD_STATUS_SUCCESS)
- wl12xx_error("error in read command result: %d", cmd.status);
-
- mem_answer = (struct cmd_read_write_memory *) cmd.parameters;
- memcpy(answer, mem_answer->value, len);
-
- return 0;
-}
-
-int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id,
- void *buf, size_t buf_len)
-{
- struct wl12xx_cmd_packet_template template;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id);
-
- memset(&template, 0, sizeof(template));
-
- WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE);
- buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE);
- template.size = cpu_to_le16(buf_len);
-
- if (buf)
- memcpy(template.template, buf, buf_len);
-
- ret = wl12xx_cmd_send(wl, cmd_id, &template,
- sizeof(template.size) + buf_len);
- if (ret < 0) {
- wl12xx_warning("cmd set_template failed: %d", ret);
- return ret;
- }
-
- return 0;
-}
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
deleted file mode 100644
index 2a573a6010bd..000000000000
--- a/drivers/net/wireless/wl12xx/init.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * This file is part of wl12xx
- *
- * Copyright (C) 2009 Nokia Corporation
- *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "init.h"
-#include "wl12xx_80211.h"
-#include "acx.h"
-#include "cmd.h"
-
-int wl12xx_hw_init_hwenc_config(struct wl12xx *wl)
-{
- int ret;
-
- ret = wl12xx_acx_feature_cfg(wl);
- if (ret < 0) {
- wl12xx_warning("couldn't set feature config");
- return ret;
- }
-
- ret = wl12xx_acx_default_key(wl, wl->default_key);
- if (ret < 0) {
- wl12xx_warning("couldn't set default key");
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_hw_init_templates_config(struct wl12xx *wl)
-{
- int ret;
- u8 partial_vbm[PARTIAL_VBM_MAX];
-
- /* send empty templates for fw memory reservation */
- ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL,
- sizeof(struct wl12xx_probe_req_template));
- if (ret < 0)
- return ret;
-
- ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL,
- sizeof(struct wl12xx_null_data_template));
- if (ret < 0)
- return ret;
-
- ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL,
- sizeof(struct wl12xx_ps_poll_template));
- if (ret < 0)
- return ret;
-
- ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL,
- sizeof
- (struct wl12xx_qos_null_data_template));
- if (ret < 0)
- return ret;
-
- ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL,
- sizeof
- (struct wl12xx_probe_resp_template));
- if (ret < 0)
- return ret;
-
- ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL,
- sizeof
- (struct wl12xx_beacon_template));
- if (ret < 0)
- return ret;
-
- /* tim templates, first reserve space then allocate an empty one */
- memset(partial_vbm, 0, PARTIAL_VBM_MAX);
- ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0);
- if (ret < 0)
- return ret;
-
- ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter)
-{
- int ret;
-
- ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
- if (ret < 0)
- return ret;
-
- ret = wl12xx_acx_rx_config(wl, config, filter);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_hw_init_phy_config(struct wl12xx *wl)
-{
- int ret;
-
- ret = wl12xx_acx_pd_threshold(wl);
- if (ret < 0)
- return ret;
-
- ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME);
- if (ret < 0)
- return ret;
-
- ret = wl12xx_acx_group_address_tbl(wl);
- if (ret < 0)
- return ret;
-
- ret = wl12xx_acx_service_period_timeout(wl);
- if (ret < 0)
- return ret;
-
- ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_hw_init_beacon_filter(struct wl12xx *wl)
-{
- int ret;
-
- ret = wl12xx_acx_beacon_filter_opt(wl);
- if (ret < 0)
- return ret;
-
- ret = wl12xx_acx_beacon_filter_table(wl);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_hw_init_pta(struct wl12xx *wl)
-{
- int ret;
-
- ret = wl12xx_acx_sg_enable(wl);
- if (ret < 0)
- return ret;
-
- ret = wl12xx_acx_sg_cfg(wl);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_hw_init_energy_detection(struct wl12xx *wl)
-{
- int ret;
-
- ret = wl12xx_acx_cca_threshold(wl);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl)
-{
- int ret;
-
- ret = wl12xx_acx_bcn_dtim_options(wl);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_hw_init_power_auth(struct wl12xx *wl)
-{
- return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM);
-}
diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c
deleted file mode 100644
index ce1561a41fa4..000000000000
--- a/drivers/net/wireless/wl12xx/wl1251.c
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- * This file is part of wl12xx
- *
- * Copyright (C) 2008-2009 Nokia Corporation
- *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "wl1251.h"
-#include "reg.h"
-#include "spi.h"
-#include "boot.h"
-#include "event.h"
-#include "acx.h"
-#include "tx.h"
-#include "rx.h"
-#include "ps.h"
-#include "init.h"
-
-static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = {
- [PART_DOWN] = {
- .mem = {
- .start = 0x00000000,
- .size = 0x00016800
- },
- .reg = {
- .start = REGISTERS_BASE,
- .size = REGISTERS_DOWN_SIZE
- },
- },
-
- [PART_WORK] = {
- .mem = {
- .start = 0x00028000,
- .size = 0x00014000
- },
- .reg = {
- .start = REGISTERS_BASE,
- .size = REGISTERS_WORK_SIZE
- },
- },
-
- /* WL1251 doesn't use the DRPW partition, so we don't set it here */
-};
-
-static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = {
- [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474),
- [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478),
- [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494),
- [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498),
- [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C),
- [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0),
- [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4),
- [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8),
- [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000),
- [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C),
- [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804)
-};
-
-static int wl1251_upload_firmware(struct wl12xx *wl)
-{
- struct wl12xx_partition_set *p_table = wl->chip.p_table;
- int addr, chunk_num, partition_limit;
- size_t fw_data_len;
- u8 *p;
-
- /* whal_FwCtrl_LoadFwImageSm() */
-
- wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x",
- wl12xx_reg_read32(wl, CHIP_ID_B));
-
- /* 10.0 check firmware length and set partition */
- fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) |
- (wl->fw[6] << 8) | (wl->fw[7]);
-
- wl12xx_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len,
- CHUNK_SIZE);
-
- if ((fw_data_len % 4) != 0) {
- wl12xx_error("firmware length not multiple of four");
- return -EIO;
- }
-
- wl12xx_set_partition(wl,
- p_table[PART_DOWN].mem.start,
- p_table[PART_DOWN].mem.size,
- p_table[PART_DOWN].reg.start,
- p_table[PART_DOWN].reg.size);
-
- /* 10.1 set partition limit and chunk num */
- chunk_num = 0;
- partition_limit = p_table[PART_DOWN].mem.size;
-
- while (chunk_num < fw_data_len / CHUNK_SIZE) {
- /* 10.2 update partition, if needed */
- addr = p_table[PART_DOWN].mem.start +
- (chunk_num + 2) * CHUNK_SIZE;
- if (addr > partition_limit) {
- addr = p_table[PART_DOWN].mem.start +
- chunk_num * CHUNK_SIZE;
- partition_limit = chunk_num * CHUNK_SIZE +
- p_table[PART_DOWN].mem.size;
- wl12xx_set_partition(wl,
- addr,
- p_table[PART_DOWN].mem.size,
- p_table[PART_DOWN].reg.start,
- p_table[PART_DOWN].reg.size);
- }
-
- /* 10.3 upload the chunk */
- addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE;
- p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
- wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
- p, addr);
- wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE);
-
- chunk_num++;
- }
-
- /* 10.4 upload the last chunk */
- addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE;
- p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
- wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
- fw_data_len % CHUNK_SIZE, p, addr);
- wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
-
- return 0;
-}
-
-static int wl1251_upload_nvs(struct wl12xx *wl)
-{
- size_t nvs_len, nvs_bytes_written, burst_len;
- int nvs_start, i;
- u32 dest_addr, val;
- u8 *nvs_ptr, *nvs;
-
- nvs = wl->nvs;
- if (nvs == NULL)
- return -ENODEV;
-
- nvs_ptr = nvs;
-
- nvs_len = wl->nvs_len;
- nvs_start = wl->fw_len;
-
- /*
- * Layout before the actual NVS tables:
- * 1 byte : burst length.
- * 2 bytes: destination address.
- * n bytes: data to burst copy.
- *
- * This is ended by a 0 length, then the NVS tables.
- */
-
- while (nvs_ptr[0]) {
- burst_len = nvs_ptr[0];
- dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
-
- /* We move our pointer to the data */
- nvs_ptr += 3;
-
- for (i = 0; i < burst_len; i++) {
- val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
- | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
-
- wl12xx_debug(DEBUG_BOOT,
- "nvs burst write 0x%x: 0x%x",
- dest_addr, val);
- wl12xx_mem_write32(wl, dest_addr, val);
-
- nvs_ptr += 4;
- dest_addr += 4;
- }
- }
-
- /*
- * We've reached the first zero length, the first NVS table
- * is 7 bytes further.
- */
- nvs_ptr += 7;
- nvs_len -= nvs_ptr - nvs;
- nvs_len = ALIGN(nvs_len, 4);
-
- /* Now we must set the partition correctly */
- wl12xx_set_partition(wl, nvs_start,
- wl->chip.p_table[PART_DOWN].mem.size,
- wl->chip.p_table[PART_DOWN].reg.start,
- wl->chip.p_table[PART_DOWN].reg.size);
-
- /* And finally we upload the NVS tables */
- nvs_bytes_written = 0;
- while (nvs_bytes_written < nvs_len) {
- val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
- | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
-
- val = cpu_to_le32(val);
-
- wl12xx_debug(DEBUG_BOOT,
- "nvs write table 0x%x: 0x%x",
- nvs_start, val);
- wl12xx_mem_write32(wl, nvs_start, val);
-
- nvs_ptr += 4;
- nvs_bytes_written += 4;
- nvs_start += 4;
- }
-
- return 0;
-}
-
-static int wl1251_boot(struct wl12xx *wl)
-{
- int ret = 0, minor_minor_e2_ver;
- u32 tmp, boot_data;
-
- ret = wl12xx_boot_soft_reset(wl);
- if (ret < 0)
- goto out;
-
- /* 2. start processing NVS file */
- ret = wl->chip.op_upload_nvs(wl);
- if (ret < 0)
- goto out;
-
- /* write firmware's last address (ie. it's length) to
- * ACX_EEPROMLESS_IND_REG */
- wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
-
- /* 6. read the EEPROM parameters */
- tmp = wl12xx_reg_read32(wl, SCR_PAD2);
-
- /* 7. read bootdata */
- wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8;
- wl->boot_attr.major = (tmp & 0x00FF0000) >> 16;
- tmp = wl12xx_reg_read32(wl, SCR_PAD3);
-
- /* 8. check bootdata and call restart sequence */
- wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16;
- minor_minor_e2_ver = (tmp & 0xFF000000) >> 24;
-
- wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x "
- "minorE2Ver 0x%x minor_minor_e2_ver 0x%x",
- wl->boot_attr.radio_type, wl->boot_attr.major,
- wl->boot_attr.minor, minor_minor_e2_ver);
-
- ret = wl12xx_boot_init_seq(wl);
- if (ret < 0)
- goto out;
-
- /* 9. NVS processing done */
- boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL);
-
- wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data);
-
- /* 10. check that ECPU_CONTROL_HALT bits are set in
- * pWhalBus->uBootData and start uploading firmware
- */
- if ((boot_data & ECPU_CONTROL_HALT) == 0) {
- wl12xx_error("boot failed, ECPU_CONTROL_HALT not set");
- ret = -EIO;
- goto out;
- }
-
- ret = wl->chip.op_upload_fw(wl);
- if (ret < 0)
- goto out;
-
- /* 10.5 start firmware */
- ret = wl12xx_boot_run_firmware(wl);
- if (ret < 0)
- goto out;
-
- /* Get and save the firmware version */
- wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver));
-
-out:
- return ret;
-}
-
-static int wl1251_mem_cfg(struct wl12xx *wl)
-{
- struct wl1251_acx_config_memory mem_conf;
- int ret, i;
-
- wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg");
-
- /* memory config */
- mem_conf.mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
- mem_conf.mem_config.rx_mem_block_num = 35;
- mem_conf.mem_config.tx_min_mem_block_num = 64;
- mem_conf.mem_config.num_tx_queues = MAX_TX_QUEUES;
- mem_conf.mem_config.host_if_options = HOSTIF_PKT_RING;
- mem_conf.mem_config.num_ssid_profiles = 1;
- mem_conf.mem_config.debug_buffer_size =
- cpu_to_le16(TRACE_BUFFER_MAX_SIZE);
-
- /* RX queue config */
- mem_conf.rx_queue_config.dma_address = 0;
- mem_conf.rx_queue_config.num_descs = ACX_RX_DESC_DEF;
- mem_conf.rx_queue_config.priority = DEFAULT_RXQ_PRIORITY;
- mem_conf.rx_queue_config.type = DEFAULT_RXQ_TYPE;
-
- /* TX queue config */
- for (i = 0; i < MAX_TX_QUEUES; i++) {
- mem_conf.tx_queue_config[i].num_descs = ACX_TX_DESC_DEF;
- mem_conf.tx_queue_config[i].attributes = i;
- }
-
- mem_conf.header.id = ACX_MEM_CFG;
- mem_conf.header.len = sizeof(struct wl1251_acx_config_memory) -
- sizeof(struct acx_header);
- mem_conf.header.len -=
- (MAX_TX_QUEUE_CONFIGS - mem_conf.mem_config.num_tx_queues) *
- sizeof(struct wl1251_acx_tx_queue_config);
-
- ret = wl12xx_cmd_configure(wl, &mem_conf,
- sizeof(struct wl1251_acx_config_memory));
- if (ret < 0)
- wl12xx_warning("wl1251 mem config failed: %d", ret);
-
- return ret;
-}
-
-static int wl1251_hw_init_mem_config(struct wl12xx *wl)
-{
- int ret;
-
- ret = wl1251_mem_cfg(wl);
- if (ret < 0)
- return ret;
-
- wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map),
- GFP_KERNEL);
- if (!wl->target_mem_map) {
- wl12xx_error("couldn't allocate target memory map");
- return -ENOMEM;
- }
-
- /* we now ask for the firmware built memory map */
- ret = wl12xx_acx_mem_map(wl, wl->target_mem_map,
- sizeof(struct wl1251_acx_mem_map));
- if (ret < 0) {
- wl12xx_error("couldn't retrieve firmware memory map");
- kfree(wl->target_mem_map);
- wl->target_mem_map = NULL;
- return ret;
- }
-
- return 0;
-}
-
-static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag)
-{
- u32 cpu_ctrl;
-
- /* 10.5.0 run the firmware (I) */
- cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL);
-
- /* 10.5.1 run the firmware (II) */
- cpu_ctrl &= ~flag;
- wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
-}
-
-static void wl1251_target_enable_interrupts(struct wl12xx *wl)
-{
- /* Enable target's interrupts */
- wl->intr_mask = WL1251_ACX_INTR_RX0_DATA |
- WL1251_ACX_INTR_RX1_DATA |
- WL1251_ACX_INTR_TX_RESULT |
- WL1251_ACX_INTR_EVENT_A |
- WL1251_ACX_INTR_EVENT_B |
- WL1251_ACX_INTR_INIT_COMPLETE;
- wl12xx_boot_target_enable_interrupts(wl);
-}
-
-static void wl1251_irq_work(struct work_struct *work)
-{
- u32 intr;
- struct wl12xx *wl =
- container_of(work, struct wl12xx, irq_work);
-
- mutex_lock(&wl->mutex);
-
- wl12xx_debug(DEBUG_IRQ, "IRQ work");
-
- if (wl->state == WL12XX_STATE_OFF)
- goto out;
-
- wl12xx_ps_elp_wakeup(wl);
-
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL);
-
- intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
- wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr);
-
- if (wl->data_path) {
- wl12xx_spi_mem_read(wl, wl->data_path->rx_control_addr,
- &wl->rx_counter, sizeof(u32));
-
- /* We handle a frmware bug here */
- switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
- case 0:
- wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync");
- intr &= ~WL1251_ACX_INTR_RX0_DATA;
- intr &= ~WL1251_ACX_INTR_RX1_DATA;
- break;
- case 1:
- wl12xx_debug(DEBUG_IRQ, "RX: FW +1");
- intr |= WL1251_ACX_INTR_RX0_DATA;
- intr &= ~WL1251_ACX_INTR_RX1_DATA;
- break;
- case 2:
- wl12xx_debug(DEBUG_IRQ, "RX: FW +2");
- intr |= WL1251_ACX_INTR_RX0_DATA;
- intr |= WL1251_ACX_INTR_RX1_DATA;
- break;
- default:
- wl12xx_warning("RX: FW and host out of sync: %d",
- wl->rx_counter - wl->rx_handled);
- break;
- }
-
- wl->rx_handled = wl->rx_counter;
-
-
- wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter);
- }
-
- intr &= wl->intr_mask;
-
- if (intr == 0) {
- wl12xx_debug(DEBUG_IRQ, "INTR is 0");
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
- ~(wl->intr_mask));
-
- goto out_sleep;
- }
-
- if (intr & WL1251_ACX_INTR_RX0_DATA) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
- wl12xx_rx(wl);
- }
-
- if (intr & WL1251_ACX_INTR_RX1_DATA) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
- wl12xx_rx(wl);
- }
-
- if (intr & WL1251_ACX_INTR_TX_RESULT) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
- wl12xx_tx_complete(wl);
- }
-
- if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr);
- if (intr & WL1251_ACX_INTR_EVENT_A)
- wl12xx_event_handle(wl, 0);
- else
- wl12xx_event_handle(wl, 1);
- }
-
- if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
-
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
-
-out_sleep:
- wl12xx_ps_elp_sleep(wl);
-out:
- mutex_unlock(&wl->mutex);
-}
-
-static int wl1251_hw_init_txq_fill(u8 qid,
- struct acx_tx_queue_qos_config *config,
- u32 num_blocks)
-{
- config->qid = qid;
-
- switch (qid) {
- case QOS_AC_BE:
- config->high_threshold =
- (QOS_TX_HIGH_BE_DEF * num_blocks) / 100;
- config->low_threshold =
- (QOS_TX_LOW_BE_DEF * num_blocks) / 100;
- break;
- case QOS_AC_BK:
- config->high_threshold =
- (QOS_TX_HIGH_BK_DEF * num_blocks) / 100;
- config->low_threshold =
- (QOS_TX_LOW_BK_DEF * num_blocks) / 100;
- break;
- case QOS_AC_VI:
- config->high_threshold =
- (QOS_TX_HIGH_VI_DEF * num_blocks) / 100;
- config->low_threshold =
- (QOS_TX_LOW_VI_DEF * num_blocks) / 100;
- break;
- case QOS_AC_VO:
- config->high_threshold =
- (QOS_TX_HIGH_VO_DEF * num_blocks) / 100;
- config->low_threshold =
- (QOS_TX_LOW_VO_DEF * num_blocks) / 100;
- break;
- default:
- wl12xx_error("Invalid TX queue id: %d", qid);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl)
-{
- struct acx_tx_queue_qos_config config;
- struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map;
- int ret, i;
-
- wl12xx_debug(DEBUG_ACX, "acx tx queue config");
-
- config.header.id = ACX_TX_QUEUE_CFG;
- config.header.len = sizeof(struct acx_tx_queue_qos_config) -
- sizeof(struct acx_header);
-
- for (i = 0; i < MAX_NUM_OF_AC; i++) {
- ret = wl1251_hw_init_txq_fill(i, &config,
- wl_mem_map->num_tx_mem_blocks);
- if (ret < 0)
- return ret;
-
- ret = wl12xx_cmd_configure(wl, &config, sizeof(config));
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-static int wl1251_hw_init_data_path_config(struct wl12xx *wl)
-{
- int ret;
-
- /* asking for the data path parameters */
- wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp),
- GFP_KERNEL);
- if (!wl->data_path) {
- wl12xx_error("Couldnt allocate data path parameters");
- return -ENOMEM;
- }
-
- ret = wl12xx_acx_data_path_params(wl, wl->data_path);
- if (ret < 0) {
- kfree(wl->data_path);
- wl->data_path = NULL;
- return ret;
- }
-
- return 0;
-}
-
-static int wl1251_hw_init(struct wl12xx *wl)
-{
- struct wl1251_acx_mem_map *wl_mem_map;
- int ret;
-
- ret = wl12xx_hw_init_hwenc_config(wl);
- if (ret < 0)
- return ret;
-
- /* Template settings */
- ret = wl12xx_hw_init_templates_config(wl);
- if (ret < 0)
- return ret;
-
- /* Default memory configuration */
- ret = wl1251_hw_init_mem_config(wl);
- if (ret < 0)
- return ret;
-
- /* Default data path configuration */
- ret = wl1251_hw_init_data_path_config(wl);
- if (ret < 0)
- goto out_free_memmap;
-
- /* RX config */
- ret = wl12xx_hw_init_rx_config(wl,
- RX_CFG_PROMISCUOUS | RX_CFG_TSF,
- RX_FILTER_OPTION_DEF);
- /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
- RX_FILTER_OPTION_FILTER_ALL); */
- if (ret < 0)
- goto out_free_data_path;
-
- /* TX queues config */
- ret = wl1251_hw_init_tx_queue_config(wl);
- if (ret < 0)
- goto out_free_data_path;
-
- /* PHY layer config */
- ret = wl12xx_hw_init_phy_config(wl);
- if (ret < 0)
- goto out_free_data_path;
-
- /* Beacon filtering */
- ret = wl12xx_hw_init_beacon_filter(wl);
- if (ret < 0)
- goto out_free_data_path;
-
- /* Bluetooth WLAN coexistence */
- ret = wl12xx_hw_init_pta(wl);
- if (ret < 0)
- goto out_free_data_path;
-
- /* Energy detection */
- ret = wl12xx_hw_init_energy_detection(wl);
- if (ret < 0)
- goto out_free_data_path;
-
- /* Beacons and boradcast settings */
- ret = wl12xx_hw_init_beacon_broadcast(wl);
- if (ret < 0)
- goto out_free_data_path;
-
- /* Enable data path */
- ret = wl12xx_cmd_data_path(wl, wl->channel, 1);
- if (ret < 0)
- goto out_free_data_path;
-
- /* Default power state */
- ret = wl12xx_hw_init_power_auth(wl);
- if (ret < 0)
- goto out_free_data_path;
-
- wl_mem_map = wl->target_mem_map;
- wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
- wl_mem_map->num_tx_mem_blocks,
- wl->data_path->tx_control_addr,
- wl_mem_map->num_rx_mem_blocks,
- wl->data_path->rx_control_addr);
-
- return 0;
-
- out_free_data_path:
- kfree(wl->data_path);
-
- out_free_memmap:
- kfree(wl->target_mem_map);
-
- return ret;
-}
-
-static int wl1251_plt_init(struct wl12xx *wl)
-{
- int ret;
-
- ret = wl1251_hw_init_mem_config(wl);
- if (ret < 0)
- return ret;
-
- ret = wl12xx_cmd_data_path(wl, wl->channel, 1);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-void wl1251_setup(struct wl12xx *wl)
-{
- /* FIXME: Is it better to use strncpy here or is this ok? */
- wl->chip.fw_filename = WL1251_FW_NAME;
- wl->chip.nvs_filename = WL1251_NVS_NAME;
-
- /* Now we know what chip we're using, so adjust the power on sleep
- * time accordingly */
- wl->chip.power_on_sleep = WL1251_POWER_ON_SLEEP;
-
- wl->chip.intr_cmd_complete = WL1251_ACX_INTR_CMD_COMPLETE;
- wl->chip.intr_init_complete = WL1251_ACX_INTR_INIT_COMPLETE;
-
- wl->chip.op_upload_nvs = wl1251_upload_nvs;
- wl->chip.op_upload_fw = wl1251_upload_firmware;
- wl->chip.op_boot = wl1251_boot;
- wl->chip.op_set_ecpu_ctrl = wl1251_set_ecpu_ctrl;
- wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts;
- wl->chip.op_hw_init = wl1251_hw_init;
- wl->chip.op_plt_init = wl1251_plt_init;
-
- wl->chip.p_table = wl1251_part_table;
- wl->chip.acx_reg_table = wl1251_acx_reg_table;
-
- INIT_WORK(&wl->irq_work, wl1251_irq_work);
-}
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h
index 1f4a44330394..998e4b6252bd 100644
--- a/drivers/net/wireless/wl12xx/wl1251.h
+++ b/drivers/net/wireless/wl12xx/wl1251.h
@@ -1,7 +1,8 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (c) 1998-2007 Texas Instruments Incorporated
+ * Copyright (C) 2008-2009 Nokia Corporation
*
* Contact: Kalle Valo <kalle.valo@nokia.com>
*
@@ -24,142 +25,400 @@
#ifndef __WL1251_H__
#define __WL1251_H__
+#include <linux/mutex.h>
+#include <linux/list.h>
#include <linux/bitops.h>
-
-#include "wl12xx.h"
-#include "acx.h"
-
-#define WL1251_FW_NAME "wl1251-fw.bin"
-#define WL1251_NVS_NAME "wl1251-nvs.bin"
-
-#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */
-
-void wl1251_setup(struct wl12xx *wl);
-
-
-struct wl1251_acx_memory {
- __le16 num_stations; /* number of STAs to be supported. */
- u16 reserved_1;
+#include <net/mac80211.h>
+
+#define DRIVER_NAME "wl1251"
+#define DRIVER_PREFIX DRIVER_NAME ": "
+
+enum {
+ DEBUG_NONE = 0,
+ DEBUG_IRQ = BIT(0),
+ DEBUG_SPI = BIT(1),
+ DEBUG_BOOT = BIT(2),
+ DEBUG_MAILBOX = BIT(3),
+ DEBUG_NETLINK = BIT(4),
+ DEBUG_EVENT = BIT(5),
+ DEBUG_TX = BIT(6),
+ DEBUG_RX = BIT(7),
+ DEBUG_SCAN = BIT(8),
+ DEBUG_CRYPT = BIT(9),
+ DEBUG_PSM = BIT(10),
+ DEBUG_MAC80211 = BIT(11),
+ DEBUG_CMD = BIT(12),
+ DEBUG_ACX = BIT(13),
+ DEBUG_ALL = ~0,
+};
+
+#define DEBUG_LEVEL (DEBUG_NONE)
+
+#define DEBUG_DUMP_LIMIT 1024
+
+#define wl1251_error(fmt, arg...) \
+ printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
+
+#define wl1251_warning(fmt, arg...) \
+ printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
+
+#define wl1251_notice(fmt, arg...) \
+ printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg)
+
+#define wl1251_info(fmt, arg...) \
+ printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg)
+
+#define wl1251_debug(level, fmt, arg...) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \
+ } while (0)
+
+#define wl1251_dump(level, prefix, buf, len) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, \
+ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+ 0); \
+ } while (0)
+
+#define wl1251_dump_ascii(level, prefix, buf, len) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, \
+ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+ true); \
+ } while (0)
+
+#define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
+ CFG_BSSID_FILTER_EN)
+
+#define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \
+ CFG_RX_MGMT_EN | \
+ CFG_RX_DATA_EN | \
+ CFG_RX_CTL_EN | \
+ CFG_RX_BCN_EN | \
+ CFG_RX_AUTH_EN | \
+ CFG_RX_ASSOC_EN)
+
+#define WL1251_BUSY_WORD_LEN 8
+
+struct boot_attr {
+ u32 radio_type;
+ u8 mac_clock;
+ u8 arm_clock;
+ int firmware_debug;
+ u32 minor;
+ u32 major;
+ u32 bugfix;
+};
+
+enum wl1251_state {
+ WL1251_STATE_OFF,
+ WL1251_STATE_ON,
+ WL1251_STATE_PLT,
+};
+
+enum wl1251_partition_type {
+ PART_DOWN,
+ PART_WORK,
+ PART_DRPW,
+
+ PART_TABLE_LEN
+};
+
+struct wl1251_partition {
+ u32 size;
+ u32 start;
+};
+
+struct wl1251_partition_set {
+ struct wl1251_partition mem;
+ struct wl1251_partition reg;
+};
+
+struct wl1251;
+
+struct wl1251_stats {
+ struct acx_statistics *fw_stats;
+ unsigned long fw_stats_update;
+
+ unsigned int retry_count;
+ unsigned int excessive_retries;
+};
+
+struct wl1251_debugfs {
+ struct dentry *rootdir;
+ struct dentry *fw_statistics;
+
+ struct dentry *tx_internal_desc_overflow;
+
+ struct dentry *rx_out_of_mem;
+ struct dentry *rx_hdr_overflow;
+ struct dentry *rx_hw_stuck;
+ struct dentry *rx_dropped;
+ struct dentry *rx_fcs_err;
+ struct dentry *rx_xfr_hint_trig;
+ struct dentry *rx_path_reset;
+ struct dentry *rx_reset_counter;
+
+ struct dentry *dma_rx_requested;
+ struct dentry *dma_rx_errors;
+ struct dentry *dma_tx_requested;
+ struct dentry *dma_tx_errors;
+
+ struct dentry *isr_cmd_cmplt;
+ struct dentry *isr_fiqs;
+ struct dentry *isr_rx_headers;
+ struct dentry *isr_rx_mem_overflow;
+ struct dentry *isr_rx_rdys;
+ struct dentry *isr_irqs;
+ struct dentry *isr_tx_procs;
+ struct dentry *isr_decrypt_done;
+ struct dentry *isr_dma0_done;
+ struct dentry *isr_dma1_done;
+ struct dentry *isr_tx_exch_complete;
+ struct dentry *isr_commands;
+ struct dentry *isr_rx_procs;
+ struct dentry *isr_hw_pm_mode_changes;
+ struct dentry *isr_host_acknowledges;
+ struct dentry *isr_pci_pm;
+ struct dentry *isr_wakeups;
+ struct dentry *isr_low_rssi;
+
+ struct dentry *wep_addr_key_count;
+ struct dentry *wep_default_key_count;
+ /* skipping wep.reserved */
+ struct dentry *wep_key_not_found;
+ struct dentry *wep_decrypt_fail;
+ struct dentry *wep_packets;
+ struct dentry *wep_interrupt;
+
+ struct dentry *pwr_ps_enter;
+ struct dentry *pwr_elp_enter;
+ struct dentry *pwr_missing_bcns;
+ struct dentry *pwr_wake_on_host;
+ struct dentry *pwr_wake_on_timer_exp;
+ struct dentry *pwr_tx_with_ps;
+ struct dentry *pwr_tx_without_ps;
+ struct dentry *pwr_rcvd_beacons;
+ struct dentry *pwr_power_save_off;
+ struct dentry *pwr_enable_ps;
+ struct dentry *pwr_disable_ps;
+ struct dentry *pwr_fix_tsf_ps;
+ /* skipping cont_miss_bcns_spread for now */
+ struct dentry *pwr_rcvd_awake_beacons;
+
+ struct dentry *mic_rx_pkts;
+ struct dentry *mic_calc_failure;
+
+ struct dentry *aes_encrypt_fail;
+ struct dentry *aes_decrypt_fail;
+ struct dentry *aes_encrypt_packets;
+ struct dentry *aes_decrypt_packets;
+ struct dentry *aes_encrypt_interrupt;
+ struct dentry *aes_decrypt_interrupt;
+
+ struct dentry *event_heart_beat;
+ struct dentry *event_calibration;
+ struct dentry *event_rx_mismatch;
+ struct dentry *event_rx_mem_empty;
+ struct dentry *event_rx_pool;
+ struct dentry *event_oom_late;
+ struct dentry *event_phy_transmit_error;
+ struct dentry *event_tx_stuck;
+
+ struct dentry *ps_pspoll_timeouts;
+ struct dentry *ps_upsd_timeouts;
+ struct dentry *ps_upsd_max_sptime;
+ struct dentry *ps_upsd_max_apturn;
+ struct dentry *ps_pspoll_max_apturn;
+ struct dentry *ps_pspoll_utilization;
+ struct dentry *ps_upsd_utilization;
+
+ struct dentry *rxpipe_rx_prep_beacon_drop;
+ struct dentry *rxpipe_descr_host_int_trig_rx_data;
+ struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data;
+ struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data;
+ struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
+
+ struct dentry *tx_queue_len;
+
+ struct dentry *retry_count;
+ struct dentry *excessive_retries;
+};
+
+struct wl1251_if_operations {
+ void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len);
+ void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len);
+ void (*reset)(struct wl1251 *wl);
+ void (*enable_irq)(struct wl1251 *wl);
+ void (*disable_irq)(struct wl1251 *wl);
+};
+
+struct wl1251 {
+ struct ieee80211_hw *hw;
+ bool mac80211_registered;
+
+ void *if_priv;
+ const struct wl1251_if_operations *if_ops;
+
+ void (*set_power)(bool enable);
+ int irq;
+
+ enum wl1251_state state;
+ struct mutex mutex;
+
+ int physical_mem_addr;
+ int physical_reg_addr;
+ int virtual_mem_addr;
+ int virtual_reg_addr;
+
+ int cmd_box_addr;
+ int event_box_addr;
+ struct boot_attr boot_attr;
+
+ u8 *fw;
+ size_t fw_len;
+ u8 *nvs;
+ size_t nvs_len;
+
+ u8 bssid[ETH_ALEN];
+ u8 mac_addr[ETH_ALEN];
+ u8 bss_type;
+ u8 listen_int;
+ int channel;
+
+ void *target_mem_map;
+ struct acx_data_path_params_resp *data_path;
+
+ /* Number of TX packets transferred to the FW, modulo 16 */
+ u32 data_in_count;
+
+ /* Frames scheduled for transmission, not handled yet */
+ struct sk_buff_head tx_queue;
+ bool tx_queue_stopped;
+
+ struct work_struct tx_work;
+ struct work_struct filter_work;
+
+ /* Pending TX frames */
+ struct sk_buff *tx_frames[16];
/*
- * Nmber of memory buffers for the RX mem pool.
- * The actual number may be less if there are
- * not enough blocks left for the minimum num
- * of TX ones.
+ * Index pointing to the next TX complete entry
+ * in the cyclic XT complete array we get from
+ * the FW.
*/
- u8 rx_mem_block_num;
- u8 reserved_2;
- u8 num_tx_queues; /* From 1 to 16 */
- u8 host_if_options; /* HOST_IF* */
- u8 tx_min_mem_block_num;
- u8 num_ssid_profiles;
- __le16 debug_buffer_size;
-} __attribute__ ((packed));
+ u32 next_tx_complete;
+ /* FW Rx counter */
+ u32 rx_counter;
-#define ACX_RX_DESC_MIN 1
-#define ACX_RX_DESC_MAX 127
-#define ACX_RX_DESC_DEF 32
-struct wl1251_acx_rx_queue_config {
- u8 num_descs;
- u8 pad;
- u8 type;
- u8 priority;
- __le32 dma_address;
-} __attribute__ ((packed));
+ /* Rx frames handled */
+ u32 rx_handled;
-#define ACX_TX_DESC_MIN 1
-#define ACX_TX_DESC_MAX 127
-#define ACX_TX_DESC_DEF 16
-struct wl1251_acx_tx_queue_config {
- u8 num_descs;
- u8 pad[2];
- u8 attributes;
-} __attribute__ ((packed));
+ /* Current double buffer */
+ u32 rx_current_buffer;
+ u32 rx_last_id;
-#define MAX_TX_QUEUE_CONFIGS 5
-#define MAX_TX_QUEUES 4
-struct wl1251_acx_config_memory {
- struct acx_header header;
+ /* The target interrupt mask */
+ u32 intr_mask;
+ struct work_struct irq_work;
- struct wl1251_acx_memory mem_config;
- struct wl1251_acx_rx_queue_config rx_queue_config;
- struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
-} __attribute__ ((packed));
+ /* The mbox event mask */
+ u32 event_mask;
-struct wl1251_acx_mem_map {
- struct acx_header header;
+ /* Mailbox pointers */
+ u32 mbox_ptr[2];
- void *code_start;
- void *code_end;
+ /* Are we currently scanning */
+ bool scanning;
- void *wep_defkey_start;
- void *wep_defkey_end;
+ /* Our association ID */
+ u16 aid;
- void *sta_table_start;
- void *sta_table_end;
+ /* Default key (for WEP) */
+ u32 default_key;
- void *packet_template_start;
- void *packet_template_end;
+ unsigned int tx_mgmt_frm_rate;
+ unsigned int tx_mgmt_frm_mod;
- void *queue_memory_start;
- void *queue_memory_end;
+ unsigned int rx_config;
+ unsigned int rx_filter;
- void *packet_memory_pool_start;
- void *packet_memory_pool_end;
+ /* is firmware in elp mode */
+ bool elp;
- void *debug_buffer1_start;
- void *debug_buffer1_end;
+ /* we can be in psm, but not in elp, we have to differentiate */
+ bool psm;
- void *debug_buffer2_start;
- void *debug_buffer2_end;
+ /* PSM mode requested */
+ bool psm_requested;
- /* Number of blocks FW allocated for TX packets */
- u32 num_tx_mem_blocks;
+ u16 beacon_int;
+ u8 dtim_period;
- /* Number of blocks FW allocated for RX packets */
- u32 num_rx_mem_blocks;
-} __attribute__ ((packed));
+ /* in dBm */
+ int power_level;
-/*************************************************************************
+ struct wl1251_stats stats;
+ struct wl1251_debugfs debugfs;
- Host Interrupt Register (WiLink -> Host)
+ u32 buffer_32;
+ u32 buffer_cmd;
+ u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
+ struct wl1251_rx_descriptor *rx_descriptor;
-**************************************************************************/
+ u32 chip_id;
+ char fw_ver[21];
+};
-/* RX packet is ready in Xfer buffer #0 */
-#define WL1251_ACX_INTR_RX0_DATA BIT(0)
+int wl1251_plt_start(struct wl1251 *wl);
+int wl1251_plt_stop(struct wl1251 *wl);
-/* TX result(s) are in the TX complete buffer */
-#define WL1251_ACX_INTR_TX_RESULT BIT(1)
+struct ieee80211_hw *wl1251_alloc_hw(void);
+int wl1251_free_hw(struct wl1251 *wl);
+int wl1251_init_ieee80211(struct wl1251 *wl);
+void wl1251_enable_interrupts(struct wl1251 *wl);
+void wl1251_disable_interrupts(struct wl1251 *wl);
-/* OBSOLETE */
-#define WL1251_ACX_INTR_TX_XFR BIT(2)
+#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */
+#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS
+#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
-/* RX packet is ready in Xfer buffer #1 */
-#define WL1251_ACX_INTR_RX1_DATA BIT(3)
+#define WL1251_DEFAULT_POWER_LEVEL 20
-/* Event was entered to Event MBOX #A */
-#define WL1251_ACX_INTR_EVENT_A BIT(4)
+#define WL1251_TX_QUEUE_MAX_LENGTH 20
-/* Event was entered to Event MBOX #B */
-#define WL1251_ACX_INTR_EVENT_B BIT(5)
+#define WL1251_DEFAULT_BEACON_INT 100
+#define WL1251_DEFAULT_DTIM_PERIOD 1
-/* OBSOLETE */
-#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6)
+#define WL1251_DEFAULT_CHANNEL 0
-/* Trace meassge on MBOX #A */
-#define WL1251_ACX_INTR_TRACE_A BIT(7)
+#define CHIP_ID_1251_PG10 (0x7010101)
+#define CHIP_ID_1251_PG11 (0x7020101)
+#define CHIP_ID_1251_PG12 (0x7030101)
+#define CHIP_ID_1271_PG10 (0x4030101)
+#define CHIP_ID_1271_PG20 (0x4030111)
-/* Trace meassge on MBOX #B */
-#define WL1251_ACX_INTR_TRACE_B BIT(8)
+#define WL1251_FW_NAME "wl1251-fw.bin"
+#define WL1251_NVS_NAME "wl1251-nvs.bin"
-/* Command processing completion */
-#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9)
+#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */
-/* Init sequence is done */
-#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14)
+#define WL1251_PART_DOWN_MEM_START 0x0
+#define WL1251_PART_DOWN_MEM_SIZE 0x16800
+#define WL1251_PART_DOWN_REG_START REGISTERS_BASE
+#define WL1251_PART_DOWN_REG_SIZE REGISTERS_DOWN_SIZE
-#define WL1251_ACX_INTR_ALL 0xFFFFFFFF
+#define WL1251_PART_WORK_MEM_START 0x28000
+#define WL1251_PART_WORK_MEM_SIZE 0x14000
+#define WL1251_PART_WORK_REG_START REGISTERS_BASE
+#define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c
new file mode 100644
index 000000000000..10b26c4532c9
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.c
@@ -0,0 +1,918 @@
+#include "wl1251_acx.h"
+
+#include <linux/module.h>
+#include <linux/crc7.h>
+
+#include "wl1251.h"
+#include "wl1251_reg.h"
+#include "wl1251_cmd.h"
+#include "wl1251_ps.h"
+
+int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod,
+ u8 mgt_rate, u8 mgt_mod)
+{
+ struct acx_fw_gen_frame_rates *rates;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx frame rates");
+
+ rates = kzalloc(sizeof(*rates), GFP_KERNEL);
+ if (!rates) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rates->tx_ctrl_frame_rate = ctrl_rate;
+ rates->tx_ctrl_frame_mod = ctrl_mod;
+ rates->tx_mgt_frame_rate = mgt_rate;
+ rates->tx_mgt_frame_mod = mgt_mod;
+
+ ret = wl1251_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES,
+ rates, sizeof(*rates));
+ if (ret < 0) {
+ wl1251_error("Failed to set FW rates and modulation");
+ goto out;
+ }
+
+out:
+ kfree(rates);
+ return ret;
+}
+
+
+int wl1251_acx_station_id(struct wl1251 *wl)
+{
+ struct acx_dot11_station_id *mac;
+ int ret, i;
+
+ wl1251_debug(DEBUG_ACX, "acx dot11_station_id");
+
+ mac = kzalloc(sizeof(*mac), GFP_KERNEL);
+ if (!mac) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < ETH_ALEN; i++)
+ mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i];
+
+ ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac));
+ if (ret < 0)
+ goto out;
+
+out:
+ kfree(mac);
+ return ret;
+}
+
+int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id)
+{
+ struct acx_dot11_default_key *default_key;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id);
+
+ default_key = kzalloc(sizeof(*default_key), GFP_KERNEL);
+ if (!default_key) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ default_key->id = key_id;
+
+ ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY,
+ default_key, sizeof(*default_key));
+ if (ret < 0) {
+ wl1251_error("Couldn't set default key");
+ goto out;
+ }
+
+ wl->default_key = key_id;
+
+out:
+ kfree(default_key);
+ return ret;
+}
+
+int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
+ u8 listen_interval)
+{
+ struct acx_wake_up_condition *wake_up;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx wake up conditions");
+
+ wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
+ if (!wake_up) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wake_up->wake_up_event = wake_up_event;
+ wake_up->listen_interval = listen_interval;
+
+ ret = wl1251_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
+ wake_up, sizeof(*wake_up));
+ if (ret < 0) {
+ wl1251_warning("could not set wake up conditions: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(wake_up);
+ return ret;
+}
+
+int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth)
+{
+ struct acx_sleep_auth *auth;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx sleep auth");
+
+ auth = kzalloc(sizeof(*auth), GFP_KERNEL);
+ if (!auth) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ auth->sleep_auth = sleep_auth;
+
+ ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
+ if (ret < 0)
+ return ret;
+
+out:
+ kfree(auth);
+ return ret;
+}
+
+int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len)
+{
+ struct acx_revision *rev;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx fw rev");
+
+ rev = kzalloc(sizeof(*rev), GFP_KERNEL);
+ if (!rev) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev));
+ if (ret < 0) {
+ wl1251_warning("ACX_FW_REV interrogate failed");
+ goto out;
+ }
+
+ /* be careful with the buffer sizes */
+ strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
+
+ /*
+ * if the firmware version string is exactly
+ * sizeof(rev->fw_version) long or fw_len is less than
+ * sizeof(rev->fw_version) it won't be null terminated
+ */
+ buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
+
+out:
+ kfree(rev);
+ return ret;
+}
+
+int wl1251_acx_tx_power(struct wl1251 *wl, int power)
+{
+ struct acx_current_tx_power *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr");
+
+ if (power < 0 || power > 25)
+ return -EINVAL;
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->current_tx_power = power * 10;
+
+ ret = wl1251_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("configure of tx power failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_feature_cfg(struct wl1251 *wl)
+{
+ struct acx_feature_config *feature;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx feature cfg");
+
+ feature = kzalloc(sizeof(*feature), GFP_KERNEL);
+ if (!feature) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
+ feature->data_flow_options = 0;
+ feature->options = 0;
+
+ ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG,
+ feature, sizeof(*feature));
+ if (ret < 0) {
+ wl1251_error("Couldn't set HW encryption");
+ goto out;
+ }
+
+out:
+ kfree(feature);
+ return ret;
+}
+
+int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map,
+ size_t len)
+{
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx mem map");
+
+ ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int wl1251_acx_data_path_params(struct wl1251 *wl,
+ struct acx_data_path_params_resp *resp)
+{
+ struct acx_data_path_params *params;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx data path params");
+
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE;
+ params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE;
+
+ params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM;
+ params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM;
+
+ params->tx_complete_threshold = 1;
+
+ params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE;
+
+ params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT;
+
+ ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS,
+ params, sizeof(*params));
+ if (ret < 0)
+ goto out;
+
+ /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */
+ ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS,
+ resp, sizeof(*resp));
+
+ if (ret < 0) {
+ wl1251_warning("failed to read data path parameters: %d", ret);
+ goto out;
+ } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) {
+ wl1251_warning("data path parameter acx status failed");
+ ret = -EIO;
+ goto out;
+ }
+
+out:
+ kfree(params);
+ return ret;
+}
+
+int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time)
+{
+ struct acx_rx_msdu_lifetime *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx rx msdu life time");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->lifetime = life_time;
+ ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("failed to set rx msdu life time: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter)
+{
+ struct acx_rx_config *rx_config;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx rx config");
+
+ rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL);
+ if (!rx_config) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rx_config->config_options = config;
+ rx_config->filter_options = filter;
+
+ ret = wl1251_cmd_configure(wl, ACX_RX_CFG,
+ rx_config, sizeof(*rx_config));
+ if (ret < 0) {
+ wl1251_warning("failed to set rx config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(rx_config);
+ return ret;
+}
+
+int wl1251_acx_pd_threshold(struct wl1251 *wl)
+{
+ struct acx_packet_detection *pd;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx data pd threshold");
+
+ pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* FIXME: threshold value not set */
+
+ ret = wl1251_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd));
+ if (ret < 0) {
+ wl1251_warning("failed to set pd threshold: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(pd);
+ return 0;
+}
+
+int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time)
+{
+ struct acx_slot *slot;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx slot");
+
+ slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+ if (!slot) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ slot->wone_index = STATION_WONE_INDEX;
+ slot->slot_time = slot_time;
+
+ ret = wl1251_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot));
+ if (ret < 0) {
+ wl1251_warning("failed to set slot time: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(slot);
+ return ret;
+}
+
+int wl1251_acx_group_address_tbl(struct wl1251 *wl)
+{
+ struct acx_dot11_grp_addr_tbl *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx group address tbl");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* MAC filtering */
+ acx->enabled = 0;
+ acx->num_groups = 0;
+ memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN);
+
+ ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("failed to set group addr table: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_service_period_timeout(struct wl1251 *wl)
+{
+ struct acx_rx_timeout *rx_timeout;
+ int ret;
+
+ rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL);
+ if (!rx_timeout) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1251_debug(DEBUG_ACX, "acx service period timeout");
+
+ rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF;
+ rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF;
+
+ ret = wl1251_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT,
+ rx_timeout, sizeof(*rx_timeout));
+ if (ret < 0) {
+ wl1251_warning("failed to set service period timeout: %d",
+ ret);
+ goto out;
+ }
+
+out:
+ kfree(rx_timeout);
+ return ret;
+}
+
+int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold)
+{
+ struct acx_rts_threshold *rts;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx rts threshold");
+
+ rts = kzalloc(sizeof(*rts), GFP_KERNEL);
+ if (!rts) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rts->threshold = rts_threshold;
+
+ ret = wl1251_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
+ if (ret < 0) {
+ wl1251_warning("failed to set rts threshold: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(rts);
+ return ret;
+}
+
+int wl1251_acx_beacon_filter_opt(struct wl1251 *wl)
+{
+ struct acx_beacon_filter_option *beacon_filter;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx beacon filter opt");
+
+ beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL);
+ if (!beacon_filter) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ beacon_filter->enable = 0;
+ beacon_filter->max_num_beacons = 0;
+
+ ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT,
+ beacon_filter, sizeof(*beacon_filter));
+ if (ret < 0) {
+ wl1251_warning("failed to set beacon filter opt: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(beacon_filter);
+ return ret;
+}
+
+int wl1251_acx_beacon_filter_table(struct wl1251 *wl)
+{
+ struct acx_beacon_filter_ie_table *ie_table;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx beacon filter table");
+
+ ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL);
+ if (!ie_table) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ie_table->num_ie = 0;
+ memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
+
+ ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE,
+ ie_table, sizeof(*ie_table));
+ if (ret < 0) {
+ wl1251_warning("failed to set beacon filter table: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(ie_table);
+ return ret;
+}
+
+int wl1251_acx_sg_enable(struct wl1251 *wl)
+{
+ struct acx_bt_wlan_coex *pta;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx sg enable");
+
+ pta = kzalloc(sizeof(*pta), GFP_KERNEL);
+ if (!pta) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ pta->enable = SG_ENABLE;
+
+ ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta));
+ if (ret < 0) {
+ wl1251_warning("failed to set softgemini enable: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(pta);
+ return ret;
+}
+
+int wl1251_acx_sg_cfg(struct wl1251 *wl)
+{
+ struct acx_bt_wlan_coex_param *param;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx sg cfg");
+
+ param = kzalloc(sizeof(*param), GFP_KERNEL);
+ if (!param) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* BT-WLAN coext parameters */
+ param->min_rate = RATE_INDEX_24MBPS;
+ param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF;
+ param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF;
+ param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF;
+ param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF;
+ param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF;
+ param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF;
+ param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF;
+ param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF;
+ param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF;
+ param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF;
+ param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF;
+ param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF;
+ param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF;
+ param->antenna_type = PTA_ANTENNA_TYPE_DEF;
+ param->signal_type = PTA_SIGNALING_TYPE_DEF;
+ param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF;
+ param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF;
+ param->max_cts = PTA_MAX_NUM_CTS_DEF;
+ param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF;
+ param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF;
+ param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF;
+ param->wlan_elp_hp = PTA_ELP_HP_DEF;
+ param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF;
+ param->ack_mode_dual_ant = PTA_ACK_MODE_DEF;
+ param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF;
+ param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF;
+ param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF;
+
+ ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
+ if (ret < 0) {
+ wl1251_warning("failed to set sg config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(param);
+ return ret;
+}
+
+int wl1251_acx_cca_threshold(struct wl1251 *wl)
+{
+ struct acx_energy_detection *detection;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx cca threshold");
+
+ detection = kzalloc(sizeof(*detection), GFP_KERNEL);
+ if (!detection) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
+ detection->tx_energy_detection = 0;
+
+ ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD,
+ detection, sizeof(*detection));
+ if (ret < 0) {
+ wl1251_warning("failed to set cca threshold: %d", ret);
+ return ret;
+ }
+
+out:
+ kfree(detection);
+ return ret;
+}
+
+int wl1251_acx_bcn_dtim_options(struct wl1251 *wl)
+{
+ struct acx_beacon_broadcast *bb;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx bcn dtim options");
+
+ bb = kzalloc(sizeof(*bb), GFP_KERNEL);
+ if (!bb) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE;
+ bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE;
+ bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE;
+ bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF;
+
+ ret = wl1251_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb));
+ if (ret < 0) {
+ wl1251_warning("failed to set rx config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(bb);
+ return ret;
+}
+
+int wl1251_acx_aid(struct wl1251 *wl, u16 aid)
+{
+ struct acx_aid *acx_aid;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx aid");
+
+ acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL);
+ if (!acx_aid) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx_aid->aid = aid;
+
+ ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
+ if (ret < 0) {
+ wl1251_warning("failed to set aid: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx_aid);
+ return ret;
+}
+
+int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask)
+{
+ struct acx_event_mask *mask;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx event mbox mask");
+
+ mask = kzalloc(sizeof(*mask), GFP_KERNEL);
+ if (!mask) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* high event mask is unused */
+ mask->high_event_mask = 0xffffffff;
+
+ mask->event_mask = event_mask;
+
+ ret = wl1251_cmd_configure(wl, ACX_EVENT_MBOX_MASK,
+ mask, sizeof(*mask));
+ if (ret < 0) {
+ wl1251_warning("failed to set acx_event_mbox_mask: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(mask);
+ return ret;
+}
+
+int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble)
+{
+ struct acx_preamble *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx_set_preamble");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->preamble = preamble;
+
+ ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("Setting of preamble failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_cts_protect(struct wl1251 *wl,
+ enum acx_ctsprotect_type ctsprotect)
+{
+ struct acx_ctsprotect *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->ctsprotect = ctsprotect;
+
+ ret = wl1251_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("Setting of ctsprotect failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime)
+{
+ struct acx_tsf_info *tsf_info;
+ int ret;
+
+ tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
+ if (!tsf_info) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO,
+ tsf_info, sizeof(*tsf_info));
+ if (ret < 0) {
+ wl1251_warning("ACX_FW_REV interrogate failed");
+ goto out;
+ }
+
+ *mactime = tsf_info->current_tsf_lsb |
+ (tsf_info->current_tsf_msb << 31);
+
+out:
+ kfree(tsf_info);
+ return ret;
+}
+
+int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats)
+{
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx statistics");
+
+ ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats,
+ sizeof(*stats));
+ if (ret < 0) {
+ wl1251_warning("acx statistics failed: %d", ret);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+int wl1251_acx_rate_policies(struct wl1251 *wl)
+{
+ struct acx_rate_policy *acx;
+ int ret = 0;
+
+ wl1251_debug(DEBUG_ACX, "acx rate policies");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* configure one default (one-size-fits-all) rate class */
+ acx->rate_class_cnt = 1;
+ acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED;
+ acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT;
+ acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT;
+ acx->rate_class[0].aflags = 0;
+
+ ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("Setting of rate policies failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_mem_cfg(struct wl1251 *wl)
+{
+ struct wl1251_acx_config_memory *mem_conf;
+ int ret, i;
+
+ wl1251_debug(DEBUG_ACX, "acx mem cfg");
+
+ mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
+ if (!mem_conf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* memory config */
+ mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
+ mem_conf->mem_config.rx_mem_block_num = 35;
+ mem_conf->mem_config.tx_min_mem_block_num = 64;
+ mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES;
+ mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING;
+ mem_conf->mem_config.num_ssid_profiles = 1;
+ mem_conf->mem_config.debug_buffer_size =
+ cpu_to_le16(TRACE_BUFFER_MAX_SIZE);
+
+ /* RX queue config */
+ mem_conf->rx_queue_config.dma_address = 0;
+ mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF;
+ mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY;
+ mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE;
+
+ /* TX queue config */
+ for (i = 0; i < MAX_TX_QUEUES; i++) {
+ mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF;
+ mem_conf->tx_queue_config[i].attributes = i;
+ }
+
+ ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
+ sizeof(*mem_conf));
+ if (ret < 0) {
+ wl1251_warning("wl1251 mem config failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(mem_conf);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h
index fb2d2340993c..cafb91459504 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,14 +22,20 @@
*
*/
-#ifndef __WL12XX_ACX_H__
-#define __WL12XX_ACX_H__
+#ifndef __WL1251_ACX_H__
+#define __WL1251_ACX_H__
-#include "wl12xx.h"
+#include "wl1251.h"
+#include "wl1251_cmd.h"
/* Target's information element */
struct acx_header {
+ struct wl1251_cmd_header cmd;
+
+ /* acx (or information element) header */
u16 id;
+
+ /* payload length (not including headers */
u16 len;
};
@@ -85,15 +91,15 @@ struct acx_revision {
u32 hw_version;
} __attribute__ ((packed));
-enum wl12xx_psm_mode {
+enum wl1251_psm_mode {
/* Active mode */
- WL12XX_PSM_CAM = 0,
+ WL1251_PSM_CAM = 0,
/* Power save mode */
- WL12XX_PSM_PS = 1,
+ WL1251_PSM_PS = 1,
/* Extreme low power */
- WL12XX_PSM_ELP = 2,
+ WL1251_PSM_ELP = 2,
};
struct acx_sleep_auth {
@@ -107,25 +113,6 @@ struct acx_sleep_auth {
u8 padding[3];
} __attribute__ ((packed));
-#define TIM_ELE_ID 5
-#define PARTIAL_VBM_MAX 251
-
-struct tim {
- u8 identity;
- u8 length;
- u8 dtim_count;
- u8 dtim_period;
- u8 bitmap_ctrl;
- u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
-} __attribute__ ((packed));
-
-/* Virtual Bit Map update */
-struct vbm_update_request {
- __le16 len;
- u8 padding[2];
- struct tim tim;
-} __attribute__ ((packed));
-
enum {
HOSTIF_PCI_MASTER_HOST_INDIRECT,
HOSTIF_PCI_MASTER_HOST_DIRECT,
@@ -202,7 +189,7 @@ struct acx_data_path_params_resp {
#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF
#define RX_MSDU_LIFETIME_DEF 512000
-struct rx_msdu_lifetime {
+struct acx_rx_msdu_lifetime {
struct acx_header header;
/*
@@ -368,7 +355,7 @@ struct acx_slot {
#define ADDRESS_GROUP_MAX (8)
#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX)
-struct multicast_grp_addr_start {
+struct acx_dot11_grp_addr_tbl {
struct acx_header header;
u8 enabled;
@@ -730,22 +717,13 @@ struct acx_fw_gen_frame_rates {
} __attribute__ ((packed));
/* STA MAC */
-struct dot11_station_id {
+struct acx_dot11_station_id {
struct acx_header header;
u8 mac[ETH_ALEN];
u8 pad[2];
} __attribute__ ((packed));
-/* HW encryption keys */
-#define NUM_ACCESS_CATEGORIES_COPY 4
-#define MAX_KEY_SIZE 32
-
-/* When set, disable HW encryption */
-#define DF_ENCRYPTION_DISABLE 0x01
-/* When set, disable HW decryption */
-#define DF_SNIFF_MODE_ENABLE 0x80
-
struct acx_feature_config {
struct acx_header header;
@@ -753,67 +731,6 @@ struct acx_feature_config {
u32 data_flow_options;
} __attribute__ ((packed));
-enum acx_key_action {
- KEY_ADD_OR_REPLACE = 1,
- KEY_REMOVE = 2,
- KEY_SET_ID = 3,
- MAX_KEY_ACTION = 0xffff,
-};
-
-enum acx_key_type {
- KEY_WEP_DEFAULT = 0,
- KEY_WEP_ADDR = 1,
- KEY_AES_GROUP = 4,
- KEY_AES_PAIRWISE = 5,
- KEY_WEP_GROUP = 6,
- KEY_TKIP_MIC_GROUP = 10,
- KEY_TKIP_MIC_PAIRWISE = 11,
-};
-
-/*
- *
- * key_type_e key size key format
- * ---------- --------- ----------
- * 0x00 5, 13, 29 Key data
- * 0x01 5, 13, 29 Key data
- * 0x04 16 16 bytes of key data
- * 0x05 16 16 bytes of key data
- * 0x0a 32 16 bytes of TKIP key data
- * 8 bytes of RX MIC key data
- * 8 bytes of TX MIC key data
- * 0x0b 32 16 bytes of TKIP key data
- * 8 bytes of RX MIC key data
- * 8 bytes of TX MIC key data
- *
- */
-
-struct acx_set_key {
- /* Ignored for default WEP key */
- u8 addr[ETH_ALEN];
-
- /* key_action_e */
- u16 key_action;
-
- u16 reserved_1;
-
- /* key size in bytes */
- u8 key_size;
-
- /* key_type_e */
- u8 key_type;
- u8 ssid_profile;
-
- /*
- * TKIP, AES: frame's key id field.
- * For WEP default key: key id;
- */
- u8 id;
- u8 reserved_2[6];
- u8 key[MAX_KEY_SIZE];
- u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
- u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __attribute__ ((packed));
-
struct acx_current_tx_power {
struct acx_header header;
@@ -839,26 +756,6 @@ struct acx_tsf_info {
u8 pad[3];
} __attribute__ ((packed));
-/* 802.11 PS */
-enum acx_ps_mode {
- STATION_ACTIVE_MODE,
- STATION_POWER_SAVE_MODE
-};
-
-struct acx_ps_params {
- u8 ps_mode; /* STATION_* */
- u8 send_null_data; /* Do we have to send NULL data packet ? */
- u8 retries; /* Number of retires for the initial NULL data packet */
-
- /*
- * TUs during which the target stays awake after switching
- * to power save mode.
- */
- u8 hang_over_period;
- u16 null_data_rate;
- u8 pad[2];
-} __attribute__ ((packed));
-
enum acx_wake_up_event {
WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/
WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/
@@ -892,6 +789,7 @@ enum acx_preamble_type {
struct acx_preamble {
struct acx_header header;
+
/*
* When set, the WiLink transmits the frames with a short preamble and
* when cleared, the WiLink transmits the frames with a long preamble.
@@ -1133,6 +1031,150 @@ struct acx_statistics {
struct acx_rxpipe_statistics rxpipe;
} __attribute__ ((packed));
+#define ACX_MAX_RATE_CLASSES 8
+#define ACX_RATE_MASK_UNSPECIFIED 0
+#define ACX_RATE_RETRY_LIMIT 10
+
+struct acx_rate_class {
+ u32 enabled_rates;
+ u8 short_retry_limit;
+ u8 long_retry_limit;
+ u8 aflags;
+ u8 reserved;
+};
+
+struct acx_rate_policy {
+ struct acx_header header;
+
+ u32 rate_class_cnt;
+ struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES];
+} __attribute__ ((packed));
+
+struct wl1251_acx_memory {
+ __le16 num_stations; /* number of STAs to be supported. */
+ u16 reserved_1;
+
+ /*
+ * Nmber of memory buffers for the RX mem pool.
+ * The actual number may be less if there are
+ * not enough blocks left for the minimum num
+ * of TX ones.
+ */
+ u8 rx_mem_block_num;
+ u8 reserved_2;
+ u8 num_tx_queues; /* From 1 to 16 */
+ u8 host_if_options; /* HOST_IF* */
+ u8 tx_min_mem_block_num;
+ u8 num_ssid_profiles;
+ __le16 debug_buffer_size;
+} __attribute__ ((packed));
+
+
+#define ACX_RX_DESC_MIN 1
+#define ACX_RX_DESC_MAX 127
+#define ACX_RX_DESC_DEF 32
+struct wl1251_acx_rx_queue_config {
+ u8 num_descs;
+ u8 pad;
+ u8 type;
+ u8 priority;
+ __le32 dma_address;
+} __attribute__ ((packed));
+
+#define ACX_TX_DESC_MIN 1
+#define ACX_TX_DESC_MAX 127
+#define ACX_TX_DESC_DEF 16
+struct wl1251_acx_tx_queue_config {
+ u8 num_descs;
+ u8 pad[2];
+ u8 attributes;
+} __attribute__ ((packed));
+
+#define MAX_TX_QUEUE_CONFIGS 5
+#define MAX_TX_QUEUES 4
+struct wl1251_acx_config_memory {
+ struct acx_header header;
+
+ struct wl1251_acx_memory mem_config;
+ struct wl1251_acx_rx_queue_config rx_queue_config;
+ struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
+} __attribute__ ((packed));
+
+struct wl1251_acx_mem_map {
+ struct acx_header header;
+
+ void *code_start;
+ void *code_end;
+
+ void *wep_defkey_start;
+ void *wep_defkey_end;
+
+ void *sta_table_start;
+ void *sta_table_end;
+
+ void *packet_template_start;
+ void *packet_template_end;
+
+ void *queue_memory_start;
+ void *queue_memory_end;
+
+ void *packet_memory_pool_start;
+ void *packet_memory_pool_end;
+
+ void *debug_buffer1_start;
+ void *debug_buffer1_end;
+
+ void *debug_buffer2_start;
+ void *debug_buffer2_end;
+
+ /* Number of blocks FW allocated for TX packets */
+ u32 num_tx_mem_blocks;
+
+ /* Number of blocks FW allocated for RX packets */
+ u32 num_rx_mem_blocks;
+} __attribute__ ((packed));
+
+/*************************************************************************
+
+ Host Interrupt Register (WiLink -> Host)
+
+**************************************************************************/
+
+/* RX packet is ready in Xfer buffer #0 */
+#define WL1251_ACX_INTR_RX0_DATA BIT(0)
+
+/* TX result(s) are in the TX complete buffer */
+#define WL1251_ACX_INTR_TX_RESULT BIT(1)
+
+/* OBSOLETE */
+#define WL1251_ACX_INTR_TX_XFR BIT(2)
+
+/* RX packet is ready in Xfer buffer #1 */
+#define WL1251_ACX_INTR_RX1_DATA BIT(3)
+
+/* Event was entered to Event MBOX #A */
+#define WL1251_ACX_INTR_EVENT_A BIT(4)
+
+/* Event was entered to Event MBOX #B */
+#define WL1251_ACX_INTR_EVENT_B BIT(5)
+
+/* OBSOLETE */
+#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6)
+
+/* Trace meassge on MBOX #A */
+#define WL1251_ACX_INTR_TRACE_A BIT(7)
+
+/* Trace meassge on MBOX #B */
+#define WL1251_ACX_INTR_TRACE_B BIT(8)
+
+/* Command processing completion */
+#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9)
+
+/* Init sequence is done */
+#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14)
+
+#define WL1251_ACX_INTR_ALL 0xFFFFFFFF
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
@@ -1210,36 +1252,41 @@ enum {
};
-int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod,
+int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod,
u8 mgt_rate, u8 mgt_mod);
-int wl12xx_acx_station_id(struct wl12xx *wl);
-int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id);
-int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval);
-int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth);
-int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len);
-int wl12xx_acx_tx_power(struct wl12xx *wl, int power);
-int wl12xx_acx_feature_cfg(struct wl12xx *wl);
-int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len);
-int wl12xx_acx_data_path_params(struct wl12xx *wl,
+int wl1251_acx_station_id(struct wl1251 *wl);
+int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id);
+int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
+ u8 listen_interval);
+int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth);
+int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len);
+int wl1251_acx_tx_power(struct wl1251 *wl, int power);
+int wl1251_acx_feature_cfg(struct wl1251 *wl);
+int wl1251_acx_mem_map(struct wl1251 *wl,
+ struct acx_header *mem_map, size_t len);
+int wl1251_acx_data_path_params(struct wl1251 *wl,
struct acx_data_path_params_resp *data_path);
-int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time);
-int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter);
-int wl12xx_acx_pd_threshold(struct wl12xx *wl);
-int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time);
-int wl12xx_acx_group_address_tbl(struct wl12xx *wl);
-int wl12xx_acx_service_period_timeout(struct wl12xx *wl);
-int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold);
-int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl);
-int wl12xx_acx_beacon_filter_table(struct wl12xx *wl);
-int wl12xx_acx_sg_enable(struct wl12xx *wl);
-int wl12xx_acx_sg_cfg(struct wl12xx *wl);
-int wl12xx_acx_cca_threshold(struct wl12xx *wl);
-int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl);
-int wl12xx_acx_aid(struct wl12xx *wl, u16 aid);
-int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask);
-int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble);
-int wl12xx_acx_cts_protect(struct wl12xx *wl,
+int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time);
+int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter);
+int wl1251_acx_pd_threshold(struct wl1251 *wl);
+int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time);
+int wl1251_acx_group_address_tbl(struct wl1251 *wl);
+int wl1251_acx_service_period_timeout(struct wl1251 *wl);
+int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold);
+int wl1251_acx_beacon_filter_opt(struct wl1251 *wl);
+int wl1251_acx_beacon_filter_table(struct wl1251 *wl);
+int wl1251_acx_sg_enable(struct wl1251 *wl);
+int wl1251_acx_sg_cfg(struct wl1251 *wl);
+int wl1251_acx_cca_threshold(struct wl1251 *wl);
+int wl1251_acx_bcn_dtim_options(struct wl1251 *wl);
+int wl1251_acx_aid(struct wl1251 *wl, u16 aid);
+int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask);
+int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble);
+int wl1251_acx_cts_protect(struct wl1251 *wl,
enum acx_ctsprotect_type ctsprotect);
-int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats);
+int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats);
+int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
+int wl1251_acx_rate_policies(struct wl1251 *wl);
+int wl1251_acx_mem_cfg(struct wl1251 *wl);
-#endif /* __WL12XX_ACX_H__ */
+#endif /* __WL1251_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c
new file mode 100644
index 000000000000..452d748e42c6
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_boot.c
@@ -0,0 +1,530 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/gpio.h>
+
+#include "wl1251_reg.h"
+#include "wl1251_boot.h"
+#include "wl1251_io.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
+#include "wl1251_acx.h"
+
+void wl1251_boot_target_enable_interrupts(struct wl1251 *wl)
+{
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
+ wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
+}
+
+int wl1251_boot_soft_reset(struct wl1251 *wl)
+{
+ unsigned long timeout;
+ u32 boot_data;
+
+ /* perform soft reset */
+ wl1251_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
+
+ /* SOFT_RESET is self clearing */
+ timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
+ while (1) {
+ boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
+ wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
+ if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
+ break;
+
+ if (time_after(jiffies, timeout)) {
+ /* 1.2 check pWhalBus->uSelfClearTime if the
+ * timeout was reached */
+ wl1251_error("soft reset timeout");
+ return -1;
+ }
+
+ udelay(SOFT_RESET_STALL_TIME);
+ }
+
+ /* disable Rx/Tx */
+ wl1251_reg_write32(wl, ENABLE, 0x0);
+
+ /* disable auto calibration on start*/
+ wl1251_reg_write32(wl, SPARE_A2, 0xffff);
+
+ return 0;
+}
+
+int wl1251_boot_init_seq(struct wl1251 *wl)
+{
+ u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq;
+
+ /*
+ * col #1: INTEGER_DIVIDER
+ * col #2: FRACTIONAL_DIVIDER
+ * col #3: ATTN_BB
+ * col #4: ALPHA_BB
+ * col #5: STOP_TIME_BB
+ * col #6: BB_PLL_LOOP_FILTER
+ */
+ static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = {
+
+ { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/
+ { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/
+ { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/
+ { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/
+ { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */
+ };
+
+ /* read NVS params */
+ scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6);
+ wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6);
+
+ /* read ELP_CMD */
+ elp_cmd = wl1251_reg_read32(wl, ELP_CMD);
+ wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd);
+
+ /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */
+ ref_freq = scr_pad6 & 0x000000FF;
+ wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq);
+
+ wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9);
+
+ /*
+ * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME)
+ */
+ wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6);
+
+ /*
+ * set the clock detect feature to work in the restart wu procedure
+ * (ELP_CFG_MODE[14]) and Select the clock source type
+ * (ELP_CFG_MODE[13:12])
+ */
+ tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000;
+ wl1251_reg_write32(wl, ELP_CFG_MODE, tmp);
+
+ /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */
+ elp_cmd |= 0x00000040;
+ wl1251_reg_write32(wl, ELP_CMD, elp_cmd);
+
+ /* PG 1.2: Set the BB PLL stable time to be 1000usec
+ * (PLL_STABLE_TIME) */
+ wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20);
+
+ /* PG 1.2: read clock request time */
+ init_data = wl1251_reg_read32(wl, CLK_REQ_TIME);
+
+ /*
+ * PG 1.2: set the clock request time to be ref_clk_settling_time -
+ * 1ms = 4ms
+ */
+ if (init_data > 0x21)
+ tmp = init_data - 0x21;
+ else
+ tmp = 0;
+ wl1251_reg_write32(wl, CLK_REQ_TIME, tmp);
+
+ /* set BB PLL configurations in RF AFE */
+ wl1251_reg_write32(wl, 0x003058cc, 0x4B5);
+
+ /* set RF_AFE_REG_5 */
+ wl1251_reg_write32(wl, 0x003058d4, 0x50);
+
+ /* set RF_AFE_CTRL_REG_2 */
+ wl1251_reg_write32(wl, 0x00305948, 0x11c001);
+
+ /*
+ * change RF PLL and BB PLL divider for VCO clock and adjust VCO
+ * bais current(RF_AFE_REG_13)
+ */
+ wl1251_reg_write32(wl, 0x003058f4, 0x1e);
+
+ /* set BB PLL configurations */
+ tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000;
+ wl1251_reg_write32(wl, 0x00305840, tmp);
+
+ /* set fractional divider according to Appendix C-BB PLL
+ * Calculations
+ */
+ tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER];
+ wl1251_reg_write32(wl, 0x00305844, tmp);
+
+ /* set the initial data for the sigma delta */
+ wl1251_reg_write32(wl, 0x00305848, 0x3039);
+
+ /*
+ * set the accumulator attenuation value, calibration loop1
+ * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and
+ * the VCO gain
+ */
+ tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) |
+ (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1;
+ wl1251_reg_write32(wl, 0x00305854, tmp);
+
+ /*
+ * set the calibration stop time after holdoff time expires and set
+ * settling time HOLD_OFF_TIME_BB
+ */
+ tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000;
+ wl1251_reg_write32(wl, 0x00305858, tmp);
+
+ /*
+ * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL
+ * constant leakage current to linearize PFD to 0uA -
+ * BB_ILOOPF[7:3]
+ */
+ tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030;
+ wl1251_reg_write32(wl, 0x003058f8, tmp);
+
+ /*
+ * set regulator output voltage for n divider to
+ * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2],
+ * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB
+ * PLL auto-call to normal mode- BB_CALGAIN_3DB[8]
+ */
+ wl1251_reg_write32(wl, 0x003058f0, 0x29);
+
+ /* enable restart wakeup sequence (ELP_CMD[0]) */
+ wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1);
+
+ /* restart sequence completed */
+ udelay(2000);
+
+ return 0;
+}
+
+static void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag)
+{
+ u32 cpu_ctrl;
+
+ /* 10.5.0 run the firmware (I) */
+ cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+
+ /* 10.5.1 run the firmware (II) */
+ cpu_ctrl &= ~flag;
+ wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
+}
+
+int wl1251_boot_run_firmware(struct wl1251 *wl)
+{
+ int loop, ret;
+ u32 chip_id, interrupt;
+
+ wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
+
+ chip_id = wl1251_reg_read32(wl, CHIP_ID_B);
+
+ wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
+
+ if (chip_id != wl->chip_id) {
+ wl1251_error("chip id doesn't match after firmware boot");
+ return -EIO;
+ }
+
+ /* wait for init to complete */
+ loop = 0;
+ while (loop++ < INIT_LOOP) {
+ udelay(INIT_LOOP_DELAY);
+ interrupt = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+
+ if (interrupt == 0xffffffff) {
+ wl1251_error("error reading hardware complete "
+ "init indication");
+ return -EIO;
+ }
+ /* check that ACX_INTR_INIT_COMPLETE is enabled */
+ else if (interrupt & WL1251_ACX_INTR_INIT_COMPLETE) {
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ WL1251_ACX_INTR_INIT_COMPLETE);
+ break;
+ }
+ }
+
+ if (loop >= INIT_LOOP) {
+ wl1251_error("timeout waiting for the hardware to "
+ "complete initialization");
+ return -EIO;
+ }
+
+ /* get hardware config command mail box */
+ wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
+
+ /* get hardware config event mail box */
+ wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+
+ /* set the working partition to its "running" mode offset */
+ wl1251_set_partition(wl, WL1251_PART_WORK_MEM_START,
+ WL1251_PART_WORK_MEM_SIZE,
+ WL1251_PART_WORK_REG_START,
+ WL1251_PART_WORK_REG_SIZE);
+
+ wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
+ wl->cmd_box_addr, wl->event_box_addr);
+
+ wl1251_acx_fw_version(wl, wl->fw_ver, sizeof(wl->fw_ver));
+
+ /*
+ * in case of full asynchronous mode the firmware event must be
+ * ready to receive event from the command mailbox
+ */
+
+ /* enable gpio interrupts */
+ wl1251_enable_interrupts(wl);
+
+ /* Enable target's interrupts */
+ wl->intr_mask = WL1251_ACX_INTR_RX0_DATA |
+ WL1251_ACX_INTR_RX1_DATA |
+ WL1251_ACX_INTR_TX_RESULT |
+ WL1251_ACX_INTR_EVENT_A |
+ WL1251_ACX_INTR_EVENT_B |
+ WL1251_ACX_INTR_INIT_COMPLETE;
+ wl1251_boot_target_enable_interrupts(wl);
+
+ /* unmask all mbox events */
+ wl->event_mask = 0xffffffff;
+
+ ret = wl1251_event_unmask(wl);
+ if (ret < 0) {
+ wl1251_error("EVENT mask setting failed");
+ return ret;
+ }
+
+ wl1251_event_mbox_config(wl);
+
+ /* firmware startup completed */
+ return 0;
+}
+
+static int wl1251_boot_upload_firmware(struct wl1251 *wl)
+{
+ int addr, chunk_num, partition_limit;
+ size_t fw_data_len;
+ u8 *p;
+
+ /* whal_FwCtrl_LoadFwImageSm() */
+
+ wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x",
+ wl1251_reg_read32(wl, CHIP_ID_B));
+
+ /* 10.0 check firmware length and set partition */
+ fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) |
+ (wl->fw[6] << 8) | (wl->fw[7]);
+
+ wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len,
+ CHUNK_SIZE);
+
+ if ((fw_data_len % 4) != 0) {
+ wl1251_error("firmware length not multiple of four");
+ return -EIO;
+ }
+
+ wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START,
+ WL1251_PART_DOWN_MEM_SIZE,
+ WL1251_PART_DOWN_REG_START,
+ WL1251_PART_DOWN_REG_SIZE);
+
+ /* 10.1 set partition limit and chunk num */
+ chunk_num = 0;
+ partition_limit = WL1251_PART_DOWN_MEM_SIZE;
+
+ while (chunk_num < fw_data_len / CHUNK_SIZE) {
+ /* 10.2 update partition, if needed */
+ addr = WL1251_PART_DOWN_MEM_START +
+ (chunk_num + 2) * CHUNK_SIZE;
+ if (addr > partition_limit) {
+ addr = WL1251_PART_DOWN_MEM_START +
+ chunk_num * CHUNK_SIZE;
+ partition_limit = chunk_num * CHUNK_SIZE +
+ WL1251_PART_DOWN_MEM_SIZE;
+ wl1251_set_partition(wl,
+ addr,
+ WL1251_PART_DOWN_MEM_SIZE,
+ WL1251_PART_DOWN_REG_START,
+ WL1251_PART_DOWN_REG_SIZE);
+ }
+
+ /* 10.3 upload the chunk */
+ addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE;
+ p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
+ wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
+ p, addr);
+ wl1251_mem_write(wl, addr, p, CHUNK_SIZE);
+
+ chunk_num++;
+ }
+
+ /* 10.4 upload the last chunk */
+ addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE;
+ p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
+ wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
+ fw_data_len % CHUNK_SIZE, p, addr);
+ wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
+
+ return 0;
+}
+
+static int wl1251_boot_upload_nvs(struct wl1251 *wl)
+{
+ size_t nvs_len, nvs_bytes_written, burst_len;
+ int nvs_start, i;
+ u32 dest_addr, val;
+ u8 *nvs_ptr, *nvs;
+
+ nvs = wl->nvs;
+ if (nvs == NULL)
+ return -ENODEV;
+
+ nvs_ptr = nvs;
+
+ nvs_len = wl->nvs_len;
+ nvs_start = wl->fw_len;
+
+ /*
+ * Layout before the actual NVS tables:
+ * 1 byte : burst length.
+ * 2 bytes: destination address.
+ * n bytes: data to burst copy.
+ *
+ * This is ended by a 0 length, then the NVS tables.
+ */
+
+ while (nvs_ptr[0]) {
+ burst_len = nvs_ptr[0];
+ dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
+
+ /* We move our pointer to the data */
+ nvs_ptr += 3;
+
+ for (i = 0; i < burst_len; i++) {
+ val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
+ | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
+
+ wl1251_debug(DEBUG_BOOT,
+ "nvs burst write 0x%x: 0x%x",
+ dest_addr, val);
+ wl1251_mem_write32(wl, dest_addr, val);
+
+ nvs_ptr += 4;
+ dest_addr += 4;
+ }
+ }
+
+ /*
+ * We've reached the first zero length, the first NVS table
+ * is 7 bytes further.
+ */
+ nvs_ptr += 7;
+ nvs_len -= nvs_ptr - nvs;
+ nvs_len = ALIGN(nvs_len, 4);
+
+ /* Now we must set the partition correctly */
+ wl1251_set_partition(wl, nvs_start,
+ WL1251_PART_DOWN_MEM_SIZE,
+ WL1251_PART_DOWN_REG_START,
+ WL1251_PART_DOWN_REG_SIZE);
+
+ /* And finally we upload the NVS tables */
+ nvs_bytes_written = 0;
+ while (nvs_bytes_written < nvs_len) {
+ val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
+ | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
+
+ val = cpu_to_le32(val);
+
+ wl1251_debug(DEBUG_BOOT,
+ "nvs write table 0x%x: 0x%x",
+ nvs_start, val);
+ wl1251_mem_write32(wl, nvs_start, val);
+
+ nvs_ptr += 4;
+ nvs_bytes_written += 4;
+ nvs_start += 4;
+ }
+
+ return 0;
+}
+
+int wl1251_boot(struct wl1251 *wl)
+{
+ int ret = 0, minor_minor_e2_ver;
+ u32 tmp, boot_data;
+
+ /* halt embedded ARM CPU while loading firmware */
+ wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, ECPU_CONTROL_HALT);
+
+ ret = wl1251_boot_soft_reset(wl);
+ if (ret < 0)
+ goto out;
+
+ /* 2. start processing NVS file */
+ ret = wl1251_boot_upload_nvs(wl);
+ if (ret < 0)
+ goto out;
+
+ /* write firmware's last address (ie. it's length) to
+ * ACX_EEPROMLESS_IND_REG */
+ wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
+
+ /* 6. read the EEPROM parameters */
+ tmp = wl1251_reg_read32(wl, SCR_PAD2);
+
+ /* 7. read bootdata */
+ wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8;
+ wl->boot_attr.major = (tmp & 0x00FF0000) >> 16;
+ tmp = wl1251_reg_read32(wl, SCR_PAD3);
+
+ /* 8. check bootdata and call restart sequence */
+ wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16;
+ minor_minor_e2_ver = (tmp & 0xFF000000) >> 24;
+
+ wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x "
+ "minorE2Ver 0x%x minor_minor_e2_ver 0x%x",
+ wl->boot_attr.radio_type, wl->boot_attr.major,
+ wl->boot_attr.minor, minor_minor_e2_ver);
+
+ ret = wl1251_boot_init_seq(wl);
+ if (ret < 0)
+ goto out;
+
+ /* 9. NVS processing done */
+ boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+
+ wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data);
+
+ /* 10. check that ECPU_CONTROL_HALT bits are set in
+ * pWhalBus->uBootData and start uploading firmware
+ */
+ if ((boot_data & ECPU_CONTROL_HALT) == 0) {
+ wl1251_error("boot failed, ECPU_CONTROL_HALT not set");
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = wl1251_boot_upload_firmware(wl);
+ if (ret < 0)
+ goto out;
+
+ /* 10.5 start firmware */
+ ret = wl1251_boot_run_firmware(wl);
+ if (ret < 0)
+ goto out;
+
+out:
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h
index 4fa73132baae..90063697e8f2 100644
--- a/drivers/net/wireless/wl12xx/boot.h
+++ b/drivers/net/wireless/wl12xx/wl1251_boot.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -24,12 +24,13 @@
#ifndef __BOOT_H__
#define __BOOT_H__
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_boot_soft_reset(struct wl12xx *wl);
-int wl12xx_boot_init_seq(struct wl12xx *wl);
-int wl12xx_boot_run_firmware(struct wl12xx *wl);
-void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl);
+int wl1251_boot_soft_reset(struct wl1251 *wl);
+int wl1251_boot_init_seq(struct wl1251 *wl);
+int wl1251_boot_run_firmware(struct wl1251 *wl);
+void wl1251_boot_target_enable_interrupts(struct wl1251 *wl);
+int wl1251_boot(struct wl1251 *wl);
/* number of times we try to read the INIT interrupt */
#define INIT_LOOP 20000
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c
new file mode 100644
index 000000000000..770f260726bd
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c
@@ -0,0 +1,412 @@
+#include "wl1251_cmd.h"
+
+#include <linux/module.h>
+#include <linux/crc7.h>
+
+#include "wl1251.h"
+#include "wl1251_reg.h"
+#include "wl1251_io.h"
+#include "wl1251_ps.h"
+#include "wl1251_acx.h"
+
+/**
+ * send command to firmware
+ *
+ * @wl: wl struct
+ * @id: command id
+ * @buf: buffer containing the command, must work with dma
+ * @len: length of the buffer
+ */
+int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+ struct wl1251_cmd_header *cmd;
+ unsigned long timeout;
+ u32 intr;
+ int ret = 0;
+
+ cmd = buf;
+ cmd->id = id;
+ cmd->status = 0;
+
+ WARN_ON(len % 4 != 0);
+
+ wl1251_mem_write(wl, wl->cmd_box_addr, buf, len);
+
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
+
+ timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT);
+
+ intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ while (!(intr & WL1251_ACX_INTR_CMD_COMPLETE)) {
+ if (time_after(jiffies, timeout)) {
+ wl1251_error("command complete timeout");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ msleep(1);
+
+ intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ }
+
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ WL1251_ACX_INTR_CMD_COMPLETE);
+
+out:
+ return ret;
+}
+
+/**
+ * send test command to firmware
+ *
+ * @wl: wl struct
+ * @buf: buffer containing the command, with all headers, must work with dma
+ * @len: length of the buffer
+ * @answer: is answer needed
+ */
+int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer)
+{
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd test");
+
+ ret = wl1251_cmd_send(wl, CMD_TEST, buf, buf_len);
+
+ if (ret < 0) {
+ wl1251_warning("TEST command failed");
+ return ret;
+ }
+
+ if (answer) {
+ struct wl1251_command *cmd_answer;
+
+ /*
+ * The test command got in, we can read the answer.
+ * The answer would be a wl1251_command, where the
+ * parameter array contains the actual answer.
+ */
+ wl1251_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
+
+ cmd_answer = buf;
+
+ if (cmd_answer->header.status != CMD_STATUS_SUCCESS)
+ wl1251_error("TEST command answer error: %d",
+ cmd_answer->header.status);
+ }
+
+ return 0;
+}
+
+/**
+ * read acx from firmware
+ *
+ * @wl: wl struct
+ * @id: acx id
+ * @buf: buffer for the response, including all headers, must work with dma
+ * @len: lenght of buf
+ */
+int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+ struct acx_header *acx = buf;
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd interrogate");
+
+ acx->id = id;
+
+ /* payload length, does not include any headers */
+ acx->len = len - sizeof(*acx);
+
+ ret = wl1251_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_error("INTERROGATE command failed");
+ goto out;
+ }
+
+ /* the interrogate command got in, we can read the answer */
+ wl1251_mem_read(wl, wl->cmd_box_addr, buf, len);
+
+ acx = buf;
+ if (acx->cmd.status != CMD_STATUS_SUCCESS)
+ wl1251_error("INTERROGATE command error: %d",
+ acx->cmd.status);
+
+out:
+ return ret;
+}
+
+/**
+ * write acx value to firmware
+ *
+ * @wl: wl struct
+ * @id: acx id
+ * @buf: buffer containing acx, including all headers, must work with dma
+ * @len: length of buf
+ */
+int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+ struct acx_header *acx = buf;
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd configure");
+
+ acx->id = id;
+
+ /* payload length, does not include any headers */
+ acx->len = len - sizeof(*acx);
+
+ ret = wl1251_cmd_send(wl, CMD_CONFIGURE, acx, len);
+ if (ret < 0) {
+ wl1251_warning("CONFIGURE command NOK");
+ return ret;
+ }
+
+ return 0;
+}
+
+int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
+ void *bitmap, u16 bitmap_len, u8 bitmap_control)
+{
+ struct wl1251_cmd_vbm_update *vbm;
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd vbm");
+
+ vbm = kzalloc(sizeof(*vbm), GFP_KERNEL);
+ if (!vbm) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Count and period will be filled by the target */
+ vbm->tim.bitmap_ctrl = bitmap_control;
+ if (bitmap_len > PARTIAL_VBM_MAX) {
+ wl1251_warning("cmd vbm len is %d B, truncating to %d",
+ bitmap_len, PARTIAL_VBM_MAX);
+ bitmap_len = PARTIAL_VBM_MAX;
+ }
+ memcpy(vbm->tim.pvb_field, bitmap, bitmap_len);
+ vbm->tim.identity = identity;
+ vbm->tim.length = bitmap_len + 3;
+
+ vbm->len = cpu_to_le16(bitmap_len + 5);
+
+ ret = wl1251_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm));
+ if (ret < 0) {
+ wl1251_error("VBM command failed");
+ goto out;
+ }
+
+out:
+ kfree(vbm);
+ return 0;
+}
+
+int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
+{
+ struct cmd_enabledisable_path *cmd;
+ int ret;
+ u16 cmd_rx, cmd_tx;
+
+ wl1251_debug(DEBUG_CMD, "cmd data path");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->channel = channel;
+
+ if (enable) {
+ cmd_rx = CMD_ENABLE_RX;
+ cmd_tx = CMD_ENABLE_TX;
+ } else {
+ cmd_rx = CMD_DISABLE_RX;
+ cmd_tx = CMD_DISABLE_TX;
+ }
+
+ ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("rx %s cmd for channel %d failed",
+ enable ? "start" : "stop", channel);
+ goto out;
+ }
+
+ wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d",
+ enable ? "start" : "stop", channel);
+
+ ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("tx %s cmd for channel %d failed",
+ enable ? "start" : "stop", channel);
+ return ret;
+ }
+
+ wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d",
+ enable ? "start" : "stop", channel);
+
+out:
+ kfree(cmd);
+ return ret;
+}
+
+int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel,
+ u16 beacon_interval, u8 dtim_interval)
+{
+ struct cmd_join *join;
+ int ret, i;
+ u8 *bssid;
+
+ join = kzalloc(sizeof(*join), GFP_KERNEL);
+ if (!join) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d",
+ bss_type == BSS_TYPE_IBSS ? " ibss" : "",
+ channel, beacon_interval, dtim_interval);
+
+ /* Reverse order BSSID */
+ bssid = (u8 *) &join->bssid_lsb;
+ for (i = 0; i < ETH_ALEN; i++)
+ bssid[i] = wl->bssid[ETH_ALEN - i - 1];
+
+ join->rx_config_options = wl->rx_config;
+ join->rx_filter_options = wl->rx_filter;
+
+ /*
+ * FIXME: disable temporarily all filters because after commit
+ * 9cef8737 "mac80211: fix managed mode BSSID handling" broke
+ * association. The filter logic needs to be implemented properly
+ * and once that is done, this hack can be removed.
+ */
+ join->rx_config_options = 0;
+ join->rx_filter_options = WL1251_DEFAULT_RX_FILTER;
+
+ join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
+ RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
+
+ join->beacon_interval = beacon_interval;
+ join->dtim_interval = dtim_interval;
+ join->bss_type = bss_type;
+ join->channel = channel;
+ join->ctrl = JOIN_CMD_CTRL_TX_FLUSH;
+
+ ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
+ if (ret < 0) {
+ wl1251_error("failed to initiate cmd join");
+ goto out;
+ }
+
+out:
+ kfree(join);
+ return ret;
+}
+
+int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode)
+{
+ struct wl1251_cmd_ps_params *ps_params = NULL;
+ int ret = 0;
+
+ wl1251_debug(DEBUG_CMD, "cmd set ps mode");
+
+ ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
+ if (!ps_params) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ps_params->ps_mode = ps_mode;
+ ps_params->send_null_data = 1;
+ ps_params->retries = 5;
+ ps_params->hang_over_period = 128;
+ ps_params->null_data_rate = 1; /* 1 Mbps */
+
+ ret = wl1251_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
+ sizeof(*ps_params));
+ if (ret < 0) {
+ wl1251_error("cmd set_ps_mode failed");
+ goto out;
+ }
+
+out:
+ kfree(ps_params);
+ return ret;
+}
+
+int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
+ size_t len)
+{
+ struct cmd_read_write_memory *cmd;
+ int ret = 0;
+
+ wl1251_debug(DEBUG_CMD, "cmd read memory");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ WARN_ON(len > MAX_READ_SIZE);
+ len = min_t(size_t, len, MAX_READ_SIZE);
+
+ cmd->addr = addr;
+ cmd->size = len;
+
+ ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("read memory command failed: %d", ret);
+ goto out;
+ }
+
+ /* the read command got in, we can now read the answer */
+ wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
+
+ if (cmd->header.status != CMD_STATUS_SUCCESS)
+ wl1251_error("error in read command result: %d",
+ cmd->header.status);
+
+ memcpy(answer, cmd->value, len);
+
+out:
+ kfree(cmd);
+ return ret;
+}
+
+int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
+ void *buf, size_t buf_len)
+{
+ struct wl1251_cmd_packet_template *cmd;
+ size_t cmd_len;
+ int ret = 0;
+
+ wl1251_debug(DEBUG_CMD, "cmd template %d", cmd_id);
+
+ WARN_ON(buf_len > WL1251_MAX_TEMPLATE_SIZE);
+ buf_len = min_t(size_t, buf_len, WL1251_MAX_TEMPLATE_SIZE);
+ cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4);
+
+ cmd = kzalloc(cmd_len, GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->size = cpu_to_le16(buf_len);
+
+ if (buf)
+ memcpy(cmd->data, buf, buf_len);
+
+ ret = wl1251_cmd_send(wl, cmd_id, cmd, cmd_len);
+ if (ret < 0) {
+ wl1251_warning("cmd set_template failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(cmd);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h
index aa307dcd081f..dff798ad0ef5 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,37 +22,32 @@
*
*/
-#ifndef __WL12XX_CMD_H__
-#define __WL12XX_CMD_H__
+#ifndef __WL1251_CMD_H__
+#define __WL1251_CMD_H__
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len);
-int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer);
-int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len,
- void *answer);
-int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len);
-int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity,
+struct acx_header;
+
+int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len);
+int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer);
+int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len);
+int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len);
+int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
void *bitmap, u16 bitmap_len, u8 bitmap_control);
-int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable);
-int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval,
- u16 beacon_interval, u8 wait);
-int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode);
-int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer);
-int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id,
+int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable);
+int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel,
+ u16 beacon_interval, u8 dtim_interval);
+int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode);
+int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
+ size_t len);
+int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
void *buf, size_t buf_len);
/* unit ms */
-#define WL12XX_COMMAND_TIMEOUT 2000
-
-#define WL12XX_MAX_TEMPLATE_SIZE 300
+#define WL1251_COMMAND_TIMEOUT 2000
-struct wl12xx_cmd_packet_template {
- __le16 size;
- u8 template[WL12XX_MAX_TEMPLATE_SIZE];
-} __attribute__ ((packed));
-
-enum wl12xx_commands {
+enum wl1251_commands {
CMD_RESET = 0,
CMD_INTERROGATE = 1, /*use this to read information elements*/
CMD_CONFIGURE = 2, /*use this to write information elements*/
@@ -100,9 +95,15 @@ enum wl12xx_commands {
#define MAX_CMD_PARAMS 572
-struct wl12xx_command {
+struct wl1251_cmd_header {
u16 id;
u16 status;
+ /* payload */
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct wl1251_command {
+ struct wl1251_cmd_header header;
u8 parameters[MAX_CMD_PARAMS];
};
@@ -144,6 +145,8 @@ enum {
#define MAX_READ_SIZE 256
struct cmd_read_write_memory {
+ struct wl1251_cmd_header header;
+
/* The address of the memory to read from or write to.*/
u32 addr;
@@ -211,6 +214,8 @@ struct basic_scan_channel_parameters {
#define SCAN_MAX_NUM_OF_CHANNELS 16
struct cmd_scan {
+ struct wl1251_cmd_header header;
+
struct basic_scan_parameters params;
struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
} __attribute__ ((packed));
@@ -227,6 +232,8 @@ enum {
struct cmd_join {
+ struct wl1251_cmd_header header;
+
u32 bssid_lsb;
u16 bssid_msb;
u16 beacon_interval; /* in TBTTs */
@@ -261,5 +268,140 @@ struct cmd_join {
u8 reserved;
} __attribute__ ((packed));
+struct cmd_enabledisable_path {
+ struct wl1251_cmd_header header;
+
+ u8 channel;
+ u8 padding[3];
+} __attribute__ ((packed));
+
+#define WL1251_MAX_TEMPLATE_SIZE 300
+
+struct wl1251_cmd_packet_template {
+ struct wl1251_cmd_header header;
+
+ __le16 size;
+ u8 data[0];
+} __attribute__ ((packed));
+
+#define TIM_ELE_ID 5
+#define PARTIAL_VBM_MAX 251
+
+struct wl1251_tim {
+ u8 identity;
+ u8 length;
+ u8 dtim_count;
+ u8 dtim_period;
+ u8 bitmap_ctrl;
+ u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
+} __attribute__ ((packed));
+
+/* Virtual Bit Map update */
+struct wl1251_cmd_vbm_update {
+ struct wl1251_cmd_header header;
+ __le16 len;
+ u8 padding[2];
+ struct wl1251_tim tim;
+} __attribute__ ((packed));
+
+enum wl1251_cmd_ps_mode {
+ STATION_ACTIVE_MODE,
+ STATION_POWER_SAVE_MODE
+};
+
+struct wl1251_cmd_ps_params {
+ struct wl1251_cmd_header header;
+
+ u8 ps_mode; /* STATION_* */
+ u8 send_null_data; /* Do we have to send NULL data packet ? */
+ u8 retries; /* Number of retires for the initial NULL data packet */
+
+ /*
+ * TUs during which the target stays awake after switching
+ * to power save mode.
+ */
+ u8 hang_over_period;
+ u16 null_data_rate;
+ u8 pad[2];
+} __attribute__ ((packed));
+
+struct wl1251_cmd_trigger_scan_to {
+ struct wl1251_cmd_header header;
+
+ u32 timeout;
+};
+
+/* HW encryption keys */
+#define NUM_ACCESS_CATEGORIES_COPY 4
+#define MAX_KEY_SIZE 32
+
+/* When set, disable HW encryption */
+#define DF_ENCRYPTION_DISABLE 0x01
+/* When set, disable HW decryption */
+#define DF_SNIFF_MODE_ENABLE 0x80
+
+enum wl1251_cmd_key_action {
+ KEY_ADD_OR_REPLACE = 1,
+ KEY_REMOVE = 2,
+ KEY_SET_ID = 3,
+ MAX_KEY_ACTION = 0xffff,
+};
+
+enum wl1251_cmd_key_type {
+ KEY_WEP_DEFAULT = 0,
+ KEY_WEP_ADDR = 1,
+ KEY_AES_GROUP = 4,
+ KEY_AES_PAIRWISE = 5,
+ KEY_WEP_GROUP = 6,
+ KEY_TKIP_MIC_GROUP = 10,
+ KEY_TKIP_MIC_PAIRWISE = 11,
+};
+
+/*
+ *
+ * key_type_e key size key format
+ * ---------- --------- ----------
+ * 0x00 5, 13, 29 Key data
+ * 0x01 5, 13, 29 Key data
+ * 0x04 16 16 bytes of key data
+ * 0x05 16 16 bytes of key data
+ * 0x0a 32 16 bytes of TKIP key data
+ * 8 bytes of RX MIC key data
+ * 8 bytes of TX MIC key data
+ * 0x0b 32 16 bytes of TKIP key data
+ * 8 bytes of RX MIC key data
+ * 8 bytes of TX MIC key data
+ *
+ */
+
+struct wl1251_cmd_set_keys {
+ struct wl1251_cmd_header header;
+
+ /* Ignored for default WEP key */
+ u8 addr[ETH_ALEN];
+
+ /* key_action_e */
+ u16 key_action;
+
+ u16 reserved_1;
+
+ /* key size in bytes */
+ u8 key_size;
+
+ /* key_type_e */
+ u8 key_type;
+ u8 ssid_profile;
+
+ /*
+ * TKIP, AES: frame's key id field.
+ * For WEP default key: key id;
+ */
+ u8 id;
+ u8 reserved_2[6];
+ u8 key[MAX_KEY_SIZE];
+ u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
+ u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
+} __attribute__ ((packed));
+
-#endif /* __WL12XX_CMD_H__ */
+#endif /* __WL1251_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c
index cdb368ce4dae..a00723059f83 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -21,15 +21,16 @@
*
*/
-#include "debugfs.h"
+#include "wl1251_debugfs.h"
#include <linux/skbuff.h>
-#include "wl12xx.h"
-#include "acx.h"
+#include "wl1251.h"
+#include "wl1251_acx.h"
+#include "wl1251_ps.h"
/* ms */
-#define WL12XX_DEBUGFS_STATS_LIFETIME 1000
+#define WL1251_DEBUGFS_STATS_LIFETIME 1000
/* debugfs macros idea from mac80211 */
@@ -37,7 +38,7 @@
static ssize_t name## _read(struct file *file, char __user *userbuf, \
size_t count, loff_t *ppos) \
{ \
- struct wl12xx *wl = file->private_data; \
+ struct wl1251 *wl = file->private_data; \
char buf[buflen]; \
int res; \
\
@@ -47,7 +48,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \
\
static const struct file_operations name## _ops = { \
.read = name## _read, \
- .open = wl12xx_open_file_generic, \
+ .open = wl1251_open_file_generic, \
};
#define DEBUGFS_ADD(name, parent) \
@@ -70,11 +71,11 @@ static ssize_t sub## _ ##name## _read(struct file *file, \
char __user *userbuf, \
size_t count, loff_t *ppos) \
{ \
- struct wl12xx *wl = file->private_data; \
+ struct wl1251 *wl = file->private_data; \
char buf[buflen]; \
int res; \
\
- wl12xx_debugfs_update_stats(wl); \
+ wl1251_debugfs_update_stats(wl); \
\
res = scnprintf(buf, buflen, fmt "\n", \
wl->stats.fw_stats->sub.name); \
@@ -83,7 +84,7 @@ static ssize_t sub## _ ##name## _read(struct file *file, \
\
static const struct file_operations sub## _ ##name## _ops = { \
.read = sub## _ ##name## _read, \
- .open = wl12xx_open_file_generic, \
+ .open = wl1251_open_file_generic, \
};
#define DEBUGFS_FWSTATS_ADD(sub, name) \
@@ -92,21 +93,30 @@ static const struct file_operations sub## _ ##name## _ops = { \
#define DEBUGFS_FWSTATS_DEL(sub, name) \
DEBUGFS_DEL(sub## _ ##name)
-static void wl12xx_debugfs_update_stats(struct wl12xx *wl)
+static void wl1251_debugfs_update_stats(struct wl1251 *wl)
{
+ int ret;
+
mutex_lock(&wl->mutex);
- if (wl->state == WL12XX_STATE_ON &&
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ if (wl->state == WL1251_STATE_ON &&
time_after(jiffies, wl->stats.fw_stats_update +
- msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) {
- wl12xx_acx_statistics(wl, wl->stats.fw_stats);
+ msecs_to_jiffies(WL1251_DEBUGFS_STATS_LIFETIME))) {
+ wl1251_acx_statistics(wl, wl->stats.fw_stats);
wl->stats.fw_stats_update = jiffies;
}
+ wl1251_ps_elp_sleep(wl);
+
+out:
mutex_unlock(&wl->mutex);
}
-static int wl12xx_open_file_generic(struct inode *inode, struct file *file)
+static int wl1251_open_file_generic(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
@@ -211,7 +221,7 @@ DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u",
static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
- struct wl12xx *wl = file->private_data;
+ struct wl1251 *wl = file->private_data;
u32 queue_len;
char buf[20];
int res;
@@ -224,10 +234,10 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
static const struct file_operations tx_queue_len_ops = {
.read = tx_queue_len_read,
- .open = wl12xx_open_file_generic,
+ .open = wl1251_open_file_generic,
};
-static void wl12xx_debugfs_delete_files(struct wl12xx *wl)
+static void wl1251_debugfs_delete_files(struct wl1251 *wl)
{
DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
@@ -325,7 +335,7 @@ static void wl12xx_debugfs_delete_files(struct wl12xx *wl)
DEBUGFS_DEL(excessive_retries);
}
-static int wl12xx_debugfs_add_files(struct wl12xx *wl)
+static int wl1251_debugfs_add_files(struct wl1251 *wl)
{
int ret = 0;
@@ -426,19 +436,19 @@ static int wl12xx_debugfs_add_files(struct wl12xx *wl)
out:
if (ret < 0)
- wl12xx_debugfs_delete_files(wl);
+ wl1251_debugfs_delete_files(wl);
return ret;
}
-void wl12xx_debugfs_reset(struct wl12xx *wl)
+void wl1251_debugfs_reset(struct wl1251 *wl)
{
memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
wl->stats.retry_count = 0;
wl->stats.excessive_retries = 0;
}
-int wl12xx_debugfs_init(struct wl12xx *wl)
+int wl1251_debugfs_init(struct wl1251 *wl)
{
int ret;
@@ -469,7 +479,7 @@ int wl12xx_debugfs_init(struct wl12xx *wl)
wl->stats.fw_stats_update = jiffies;
- ret = wl12xx_debugfs_add_files(wl);
+ ret = wl1251_debugfs_add_files(wl);
if (ret < 0)
goto err_file;
@@ -492,9 +502,9 @@ err:
return ret;
}
-void wl12xx_debugfs_exit(struct wl12xx *wl)
+void wl1251_debugfs_exit(struct wl1251 *wl)
{
- wl12xx_debugfs_delete_files(wl);
+ wl1251_debugfs_delete_files(wl);
kfree(wl->stats.fw_stats);
wl->stats.fw_stats = NULL;
diff --git a/drivers/net/wireless/wl12xx/debugfs.h b/drivers/net/wireless/wl12xx/wl1251_debugfs.h
index 562cdcbcc874..6dc3d080853c 100644
--- a/drivers/net/wireless/wl12xx/debugfs.h
+++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -21,13 +21,13 @@
*
*/
-#ifndef WL12XX_DEBUGFS_H
-#define WL12XX_DEBUGFS_H
+#ifndef WL1251_DEBUGFS_H
+#define WL1251_DEBUGFS_H
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_debugfs_init(struct wl12xx *wl);
-void wl12xx_debugfs_exit(struct wl12xx *wl);
-void wl12xx_debugfs_reset(struct wl12xx *wl);
+int wl1251_debugfs_init(struct wl1251 *wl);
+void wl1251_debugfs_exit(struct wl1251 *wl);
+void wl1251_debugfs_reset(struct wl1251 *wl);
-#endif /* WL12XX_DEBUGFS_H */
+#endif /* WL1251_DEBUGFS_H */
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/wl1251_event.c
index 99529ca89a7e..00076c4a8a21 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/wl1251_event.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,16 +22,16 @@
*
*/
-#include "wl12xx.h"
-#include "reg.h"
-#include "spi.h"
-#include "event.h"
-#include "ps.h"
+#include "wl1251.h"
+#include "wl1251_reg.h"
+#include "wl1251_io.h"
+#include "wl1251_event.h"
+#include "wl1251_ps.h"
-static int wl12xx_event_scan_complete(struct wl12xx *wl,
+static int wl1251_event_scan_complete(struct wl1251 *wl,
struct event_mailbox *mbox)
{
- wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
+ wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
mbox->scheduled_scan_status,
mbox->scheduled_scan_channels);
@@ -39,40 +39,41 @@ static int wl12xx_event_scan_complete(struct wl12xx *wl,
mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, false);
mutex_lock(&wl->mutex);
+ wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed");
wl->scanning = false;
}
return 0;
}
-static void wl12xx_event_mbox_dump(struct event_mailbox *mbox)
+static void wl1251_event_mbox_dump(struct event_mailbox *mbox)
{
- wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:");
- wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
- wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
+ wl1251_debug(DEBUG_EVENT, "MBOX DUMP:");
+ wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
+ wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
}
-static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox)
+static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
{
int ret;
u32 vector;
- wl12xx_event_mbox_dump(mbox);
+ wl1251_event_mbox_dump(mbox);
vector = mbox->events_vector & ~(mbox->events_mask);
- wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector);
+ wl1251_debug(DEBUG_EVENT, "vector: 0x%x", vector);
if (vector & SCAN_COMPLETE_EVENT_ID) {
- ret = wl12xx_event_scan_complete(wl, mbox);
+ ret = wl1251_event_scan_complete(wl, mbox);
if (ret < 0)
return ret;
}
if (vector & BSS_LOSE_EVENT_ID) {
- wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
+ wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
if (wl->psm_requested && wl->psm) {
- ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
if (ret < 0)
return ret;
}
@@ -81,47 +82,47 @@ static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox)
return 0;
}
-int wl12xx_event_unmask(struct wl12xx *wl)
+int wl1251_event_unmask(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask));
+ ret = wl1251_acx_event_mbox_mask(wl, ~(wl->event_mask));
if (ret < 0)
return ret;
return 0;
}
-void wl12xx_event_mbox_config(struct wl12xx *wl)
+void wl1251_event_mbox_config(struct wl1251 *wl)
{
- wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
- wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
+ wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
wl->mbox_ptr[0], wl->mbox_ptr[1]);
}
-int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num)
+int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num)
{
struct event_mailbox mbox;
int ret;
- wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
+ wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
if (mbox_num > 1)
return -EINVAL;
/* first we read the mbox descriptor */
- wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
+ wl1251_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
sizeof(struct event_mailbox));
/* process the descriptor */
- ret = wl12xx_event_process(wl, &mbox);
+ ret = wl1251_event_process(wl, &mbox);
if (ret < 0)
return ret;
/* then we let the firmware know it can go on...*/
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
return 0;
}
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/wl1251_event.h
index 1f4c2f7438a7..be0ac54d6246 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/wl1251_event.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,8 +22,8 @@
*
*/
-#ifndef __WL12XX_EVENT_H__
-#define __WL12XX_EVENT_H__
+#ifndef __WL1251_EVENT_H__
+#define __WL1251_EVENT_H__
/*
* Mbox events
@@ -114,8 +114,8 @@ struct event_mailbox {
u8 padding[19];
} __attribute__ ((packed));
-int wl12xx_event_unmask(struct wl12xx *wl);
-void wl12xx_event_mbox_config(struct wl12xx *wl);
-int wl12xx_event_handle(struct wl12xx *wl, u8 mbox);
+int wl1251_event_unmask(struct wl1251 *wl);
+void wl1251_event_mbox_config(struct wl1251 *wl);
+int wl1251_event_handle(struct wl1251 *wl, u8 mbox);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c
new file mode 100644
index 000000000000..b2ee4f468fc4
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_init.c
@@ -0,0 +1,413 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "wl1251_init.h"
+#include "wl12xx_80211.h"
+#include "wl1251_acx.h"
+#include "wl1251_cmd.h"
+#include "wl1251_reg.h"
+
+int wl1251_hw_init_hwenc_config(struct wl1251 *wl)
+{
+ int ret;
+
+ ret = wl1251_acx_feature_cfg(wl);
+ if (ret < 0) {
+ wl1251_warning("couldn't set feature config");
+ return ret;
+ }
+
+ ret = wl1251_acx_default_key(wl, wl->default_key);
+ if (ret < 0) {
+ wl1251_warning("couldn't set default key");
+ return ret;
+ }
+
+ return 0;
+}
+
+int wl1251_hw_init_templates_config(struct wl1251 *wl)
+{
+ int ret;
+ u8 partial_vbm[PARTIAL_VBM_MAX];
+
+ /* send empty templates for fw memory reservation */
+ ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL,
+ sizeof(struct wl12xx_probe_req_template));
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL,
+ sizeof(struct wl12xx_null_data_template));
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL,
+ sizeof(struct wl12xx_ps_poll_template));
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL,
+ sizeof
+ (struct wl12xx_qos_null_data_template));
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL,
+ sizeof
+ (struct wl12xx_probe_resp_template));
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL,
+ sizeof
+ (struct wl12xx_beacon_template));
+ if (ret < 0)
+ return ret;
+
+ /* tim templates, first reserve space then allocate an empty one */
+ memset(partial_vbm, 0, PARTIAL_VBM_MAX);
+ ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter)
+{
+ int ret;
+
+ ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_acx_rx_config(wl, config, filter);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int wl1251_hw_init_phy_config(struct wl1251 *wl)
+{
+ int ret;
+
+ ret = wl1251_acx_pd_threshold(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_acx_group_address_tbl(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_acx_service_period_timeout(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int wl1251_hw_init_beacon_filter(struct wl1251 *wl)
+{
+ int ret;
+
+ ret = wl1251_acx_beacon_filter_opt(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_acx_beacon_filter_table(wl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int wl1251_hw_init_pta(struct wl1251 *wl)
+{
+ int ret;
+
+ ret = wl1251_acx_sg_enable(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_acx_sg_cfg(wl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int wl1251_hw_init_energy_detection(struct wl1251 *wl)
+{
+ int ret;
+
+ ret = wl1251_acx_cca_threshold(wl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl)
+{
+ int ret;
+
+ ret = wl1251_acx_bcn_dtim_options(wl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int wl1251_hw_init_power_auth(struct wl1251 *wl)
+{
+ return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
+}
+
+int wl1251_hw_init_mem_config(struct wl1251 *wl)
+{
+ int ret;
+
+ ret = wl1251_acx_mem_cfg(wl);
+ if (ret < 0)
+ return ret;
+
+ wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map),
+ GFP_KERNEL);
+ if (!wl->target_mem_map) {
+ wl1251_error("couldn't allocate target memory map");
+ return -ENOMEM;
+ }
+
+ /* we now ask for the firmware built memory map */
+ ret = wl1251_acx_mem_map(wl, wl->target_mem_map,
+ sizeof(struct wl1251_acx_mem_map));
+ if (ret < 0) {
+ wl1251_error("couldn't retrieve firmware memory map");
+ kfree(wl->target_mem_map);
+ wl->target_mem_map = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
+static int wl1251_hw_init_txq_fill(u8 qid,
+ struct acx_tx_queue_qos_config *config,
+ u32 num_blocks)
+{
+ config->qid = qid;
+
+ switch (qid) {
+ case QOS_AC_BE:
+ config->high_threshold =
+ (QOS_TX_HIGH_BE_DEF * num_blocks) / 100;
+ config->low_threshold =
+ (QOS_TX_LOW_BE_DEF * num_blocks) / 100;
+ break;
+ case QOS_AC_BK:
+ config->high_threshold =
+ (QOS_TX_HIGH_BK_DEF * num_blocks) / 100;
+ config->low_threshold =
+ (QOS_TX_LOW_BK_DEF * num_blocks) / 100;
+ break;
+ case QOS_AC_VI:
+ config->high_threshold =
+ (QOS_TX_HIGH_VI_DEF * num_blocks) / 100;
+ config->low_threshold =
+ (QOS_TX_LOW_VI_DEF * num_blocks) / 100;
+ break;
+ case QOS_AC_VO:
+ config->high_threshold =
+ (QOS_TX_HIGH_VO_DEF * num_blocks) / 100;
+ config->low_threshold =
+ (QOS_TX_LOW_VO_DEF * num_blocks) / 100;
+ break;
+ default:
+ wl1251_error("Invalid TX queue id: %d", qid);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
+{
+ struct acx_tx_queue_qos_config *config;
+ struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map;
+ int ret, i;
+
+ wl1251_debug(DEBUG_ACX, "acx tx queue config");
+
+ config = kzalloc(sizeof(*config), GFP_KERNEL);
+ if (!config) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < MAX_NUM_OF_AC; i++) {
+ ret = wl1251_hw_init_txq_fill(i, config,
+ wl_mem_map->num_tx_mem_blocks);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG,
+ config, sizeof(*config));
+ if (ret < 0)
+ goto out;
+ }
+
+out:
+ kfree(config);
+ return ret;
+}
+
+static int wl1251_hw_init_data_path_config(struct wl1251 *wl)
+{
+ int ret;
+
+ /* asking for the data path parameters */
+ wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp),
+ GFP_KERNEL);
+ if (!wl->data_path) {
+ wl1251_error("Couldnt allocate data path parameters");
+ return -ENOMEM;
+ }
+
+ ret = wl1251_acx_data_path_params(wl, wl->data_path);
+ if (ret < 0) {
+ kfree(wl->data_path);
+ wl->data_path = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
+
+int wl1251_hw_init(struct wl1251 *wl)
+{
+ struct wl1251_acx_mem_map *wl_mem_map;
+ int ret;
+
+ ret = wl1251_hw_init_hwenc_config(wl);
+ if (ret < 0)
+ return ret;
+
+ /* Template settings */
+ ret = wl1251_hw_init_templates_config(wl);
+ if (ret < 0)
+ return ret;
+
+ /* Default memory configuration */
+ ret = wl1251_hw_init_mem_config(wl);
+ if (ret < 0)
+ return ret;
+
+ /* Default data path configuration */
+ ret = wl1251_hw_init_data_path_config(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* RX config */
+ ret = wl1251_hw_init_rx_config(wl,
+ RX_CFG_PROMISCUOUS | RX_CFG_TSF,
+ RX_FILTER_OPTION_DEF);
+ /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
+ RX_FILTER_OPTION_FILTER_ALL); */
+ if (ret < 0)
+ goto out_free_data_path;
+
+ /* TX queues config */
+ ret = wl1251_hw_init_tx_queue_config(wl);
+ if (ret < 0)
+ goto out_free_data_path;
+
+ /* PHY layer config */
+ ret = wl1251_hw_init_phy_config(wl);
+ if (ret < 0)
+ goto out_free_data_path;
+
+ /* Beacon filtering */
+ ret = wl1251_hw_init_beacon_filter(wl);
+ if (ret < 0)
+ goto out_free_data_path;
+
+ /* Bluetooth WLAN coexistence */
+ ret = wl1251_hw_init_pta(wl);
+ if (ret < 0)
+ goto out_free_data_path;
+
+ /* Energy detection */
+ ret = wl1251_hw_init_energy_detection(wl);
+ if (ret < 0)
+ goto out_free_data_path;
+
+ /* Beacons and boradcast settings */
+ ret = wl1251_hw_init_beacon_broadcast(wl);
+ if (ret < 0)
+ goto out_free_data_path;
+
+ /* Enable data path */
+ ret = wl1251_cmd_data_path(wl, wl->channel, 1);
+ if (ret < 0)
+ goto out_free_data_path;
+
+ /* Default power state */
+ ret = wl1251_hw_init_power_auth(wl);
+ if (ret < 0)
+ goto out_free_data_path;
+
+ wl_mem_map = wl->target_mem_map;
+ wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
+ wl_mem_map->num_tx_mem_blocks,
+ wl->data_path->tx_control_addr,
+ wl_mem_map->num_rx_mem_blocks,
+ wl->data_path->rx_control_addr);
+
+ return 0;
+
+ out_free_data_path:
+ kfree(wl->data_path);
+
+ out_free_memmap:
+ kfree(wl->target_mem_map);
+
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h
new file mode 100644
index 000000000000..b3b25ec885ea
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_init.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1251_INIT_H__
+#define __WL1251_INIT_H__
+
+#include "wl1251.h"
+
+int wl1251_hw_init_hwenc_config(struct wl1251 *wl);
+int wl1251_hw_init_templates_config(struct wl1251 *wl);
+int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter);
+int wl1251_hw_init_phy_config(struct wl1251 *wl);
+int wl1251_hw_init_beacon_filter(struct wl1251 *wl);
+int wl1251_hw_init_pta(struct wl1251 *wl);
+int wl1251_hw_init_energy_detection(struct wl1251 *wl);
+int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl);
+int wl1251_hw_init_power_auth(struct wl1251 *wl);
+int wl1251_hw_init_mem_config(struct wl1251 *wl);
+int wl1251_hw_init(struct wl1251 *wl);
+
+#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 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "wl1251.h"
+#include "wl1251_reg.h"
+#include "wl1251_io.h"
+
+/* FIXME: this is static data nowadays and the table can be removed */
+static enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = {
+ [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474),
+ [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478),
+ [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494),
+ [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498),
+ [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C),
+ [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0),
+ [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4),
+ [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8),
+ [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000),
+ [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C),
+ [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804)
+};
+
+static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr)
+{
+ /* If the address is lower than REGISTERS_BASE, it means that this is
+ * a chip-specific register address, so look it up in the registers
+ * table */
+ if (addr < REGISTERS_BASE) {
+ /* Make sure we don't go over the table */
+ if (addr >= ACX_REG_TABLE_LEN) {
+ wl1251_error("address out of range (%d)", addr);
+ return -EINVAL;
+ }
+ addr = wl1251_io_reg_table[addr];
+ }
+
+ return addr - wl->physical_reg_addr + wl->virtual_reg_addr;
+}
+
+static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr)
+{
+ return addr - wl->physical_mem_addr + wl->virtual_mem_addr;
+}
+
+void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len)
+{
+ int physical;
+
+ physical = wl1251_translate_mem_addr(wl, addr);
+
+ wl->if_ops->read(wl, physical, buf, len);
+}
+
+void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len)
+{
+ int physical;
+
+ physical = wl1251_translate_mem_addr(wl, addr);
+
+ wl->if_ops->write(wl, physical, buf, len);
+}
+
+u32 wl1251_mem_read32(struct wl1251 *wl, int addr)
+{
+ return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr));
+}
+
+void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val)
+{
+ wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val);
+}
+
+u32 wl1251_reg_read32(struct wl1251 *wl, int addr)
+{
+ return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr));
+}
+
+void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val)
+{
+ wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val);
+}
+
+/* Set the partitions to access the chip addresses.
+ *
+ * There are two VIRTUAL partitions (the memory partition and the
+ * registers partition), which are mapped to two different areas of the
+ * PHYSICAL (hardware) memory. This function also makes other checks to
+ * ensure that the partitions are not overlapping. In the diagram below, the
+ * memory partition comes before the register partition, but the opposite is
+ * also supported.
+ *
+ * PHYSICAL address
+ * space
+ *
+ * | |
+ * ...+----+--> mem_start
+ * VIRTUAL address ... | |
+ * space ... | | [PART_0]
+ * ... | |
+ * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size
+ * | | ... | |
+ * |MEM | ... | |
+ * | | ... | |
+ * part_size <--+----+... | | {unused area)
+ * | | ... | |
+ * |REG | ... | |
+ * part_size | | ... | |
+ * + <--+----+... ...+----+--> reg_start
+ * reg_size ... | |
+ * ... | | [PART_1]
+ * ... | |
+ * ...+----+--> reg_start + reg_size
+ * | |
+ *
+ */
+void wl1251_set_partition(struct wl1251 *wl,
+ u32 mem_start, u32 mem_size,
+ u32 reg_start, u32 reg_size)
+{
+ struct wl1251_partition partition[2];
+
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ mem_start, mem_size);
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ reg_start, reg_size);
+
+ /* Make sure that the two partitions together don't exceed the
+ * address range */
+ if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) {
+ wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
+ " address range. Truncating partition[0].");
+ mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size;
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ mem_start, mem_size);
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ reg_start, reg_size);
+ }
+
+ if ((mem_start < reg_start) &&
+ ((mem_start + mem_size) > reg_start)) {
+ /* Guarantee that the memory partition doesn't overlap the
+ * registers partition */
+ wl1251_debug(DEBUG_SPI, "End of partition[0] is "
+ "overlapping partition[1]. Adjusted.");
+ mem_size = reg_start - mem_start;
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ mem_start, mem_size);
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ reg_start, reg_size);
+ } else if ((reg_start < mem_start) &&
+ ((reg_start + reg_size) > mem_start)) {
+ /* Guarantee that the register partition doesn't overlap the
+ * memory partition */
+ wl1251_debug(DEBUG_SPI, "End of partition[1] is"
+ " overlapping partition[0]. Adjusted.");
+ reg_size = mem_start - reg_start;
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ mem_start, mem_size);
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ reg_start, reg_size);
+ }
+
+ partition[0].start = mem_start;
+ partition[0].size = mem_size;
+ partition[1].start = reg_start;
+ partition[1].size = reg_size;
+
+ wl->physical_mem_addr = mem_start;
+ wl->physical_reg_addr = reg_start;
+
+ wl->virtual_mem_addr = 0;
+ wl->virtual_reg_addr = mem_size;
+
+ wl->if_ops->write(wl, HW_ACCESS_PART0_SIZE_ADDR, partition,
+ sizeof(partition));
+}
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 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef __WL1251_IO_H__
+#define __WL1251_IO_H__
+
+#include "wl1251.h"
+
+#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
+
+#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0
+#define HW_ACCESS_PART0_START_ADDR 0x1FFC4
+#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8
+#define HW_ACCESS_PART1_START_ADDR 0x1FFCC
+
+#define HW_ACCESS_REGISTER_SIZE 4
+
+#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000
+
+static inline u32 wl1251_read32(struct wl1251 *wl, int addr)
+{
+ u32 response;
+
+ wl->if_ops->read(wl, addr, &response, sizeof(u32));
+
+ return response;
+}
+
+static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val)
+{
+ wl->if_ops->write(wl, addr, &val, sizeof(u32));
+}
+
+/* Memory target IO, address is translated to partition 0 */
+void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len);
+void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len);
+u32 wl1251_mem_read32(struct wl1251 *wl, int addr);
+void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val);
+/* Registers IO */
+u32 wl1251_reg_read32(struct wl1251 *wl, int addr);
+void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val);
+
+void wl1251_set_partition(struct wl1251 *wl,
+ u32 part_start, u32 part_size,
+ u32 reg_start, u32 reg_size);
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 603d6114882e..5809ef5b18f8 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008-2009 Nokia Corporation
*
@@ -26,65 +26,57 @@
#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/irq.h>
-#include <linux/spi/spi.h>
#include <linux/crc32.h>
#include <linux/etherdevice.h>
-#include <linux/spi/wl12xx.h>
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
-#include "reg.h"
#include "wl1251.h"
-#include "spi.h"
-#include "event.h"
-#include "tx.h"
-#include "rx.h"
-#include "ps.h"
-#include "init.h"
-#include "debugfs.h"
-
-static void wl12xx_disable_interrupts(struct wl12xx *wl)
+#include "wl12xx_80211.h"
+#include "wl1251_reg.h"
+#include "wl1251_io.h"
+#include "wl1251_cmd.h"
+#include "wl1251_event.h"
+#include "wl1251_tx.h"
+#include "wl1251_rx.h"
+#include "wl1251_ps.h"
+#include "wl1251_init.h"
+#include "wl1251_debugfs.h"
+#include "wl1251_boot.h"
+
+void wl1251_enable_interrupts(struct wl1251 *wl)
{
- disable_irq(wl->irq);
+ wl->if_ops->enable_irq(wl);
}
-static void wl12xx_power_off(struct wl12xx *wl)
+void wl1251_disable_interrupts(struct wl1251 *wl)
{
- wl->set_power(false);
+ wl->if_ops->disable_irq(wl);
}
-static void wl12xx_power_on(struct wl12xx *wl)
+static void wl1251_power_off(struct wl1251 *wl)
{
- wl->set_power(true);
+ wl->set_power(false);
}
-static irqreturn_t wl12xx_irq(int irq, void *cookie)
+static void wl1251_power_on(struct wl1251 *wl)
{
- struct wl12xx *wl;
-
- wl12xx_debug(DEBUG_IRQ, "IRQ");
-
- wl = cookie;
-
- schedule_work(&wl->irq_work);
-
- return IRQ_HANDLED;
+ wl->set_power(true);
}
-static int wl12xx_fetch_firmware(struct wl12xx *wl)
+static int wl1251_fetch_firmware(struct wl1251 *wl)
{
const struct firmware *fw;
+ struct device *dev = wiphy_dev(wl->hw->wiphy);
int ret;
- ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev);
+ ret = request_firmware(&fw, WL1251_FW_NAME, dev);
if (ret < 0) {
- wl12xx_error("could not get firmware: %d", ret);
+ wl1251_error("could not get firmware: %d", ret);
return ret;
}
if (fw->size % 4) {
- wl12xx_error("firmware size is not multiple of 32 bits: %zu",
+ wl1251_error("firmware size is not multiple of 32 bits: %zu",
fw->size);
ret = -EILSEQ;
goto out;
@@ -94,7 +86,7 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl)
wl->fw = kmalloc(wl->fw_len, GFP_KERNEL);
if (!wl->fw) {
- wl12xx_error("could not allocate memory for the firmware");
+ wl1251_error("could not allocate memory for the firmware");
ret = -ENOMEM;
goto out;
}
@@ -109,20 +101,21 @@ out:
return ret;
}
-static int wl12xx_fetch_nvs(struct wl12xx *wl)
+static int wl1251_fetch_nvs(struct wl1251 *wl)
{
const struct firmware *fw;
+ struct device *dev = wiphy_dev(wl->hw->wiphy);
int ret;
- ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev);
+ ret = request_firmware(&fw, WL1251_NVS_NAME, dev);
if (ret < 0) {
- wl12xx_error("could not get nvs file: %d", ret);
+ wl1251_error("could not get nvs file: %d", ret);
return ret;
}
if (fw->size % 4) {
- wl12xx_error("nvs size is not multiple of 32 bits: %zu",
+ wl1251_error("nvs size is not multiple of 32 bits: %zu",
fw->size);
ret = -EILSEQ;
goto out;
@@ -132,7 +125,7 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl)
wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
if (!wl->nvs) {
- wl12xx_error("could not allocate memory for the nvs file");
+ wl1251_error("could not allocate memory for the nvs file");
ret = -ENOMEM;
goto out;
}
@@ -147,74 +140,66 @@ out:
return ret;
}
-static void wl12xx_fw_wakeup(struct wl12xx *wl)
+static void wl1251_fw_wakeup(struct wl1251 *wl)
{
u32 elp_reg;
elp_reg = ELPCTRL_WAKE_UP;
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
- elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
- if (!(elp_reg & ELPCTRL_WLAN_READY)) {
- wl12xx_warning("WLAN not ready");
- elp_reg = ELPCTRL_WAKE_UP_WLAN_READY;
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
- }
+ if (!(elp_reg & ELPCTRL_WLAN_READY))
+ wl1251_warning("WLAN not ready");
}
-static int wl12xx_chip_wakeup(struct wl12xx *wl)
+static int wl1251_chip_wakeup(struct wl1251 *wl)
{
int ret = 0;
- wl12xx_power_on(wl);
- msleep(wl->chip.power_on_sleep);
- wl12xx_spi_reset(wl);
- wl12xx_spi_init(wl);
+ wl1251_power_on(wl);
+ msleep(WL1251_POWER_ON_SLEEP);
+ wl->if_ops->reset(wl);
/* We don't need a real memory partition here, because we only want
* to use the registers at this point. */
- wl12xx_set_partition(wl,
+ wl1251_set_partition(wl,
0x00000000,
0x00000000,
REGISTERS_BASE,
REGISTERS_DOWN_SIZE);
/* ELP module wake up */
- wl12xx_fw_wakeup(wl);
+ wl1251_fw_wakeup(wl);
/* whal_FwCtrl_BootSm() */
/* 0. read chip id from CHIP_ID */
- wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B);
+ wl->chip_id = wl1251_reg_read32(wl, CHIP_ID_B);
/* 1. check if chip id is valid */
- switch (wl->chip.id) {
+ switch (wl->chip_id) {
case CHIP_ID_1251_PG12:
- wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)",
- wl->chip.id);
-
- wl1251_setup(wl);
-
+ wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)",
+ wl->chip_id);
break;
- case CHIP_ID_1271_PG10:
case CHIP_ID_1251_PG10:
case CHIP_ID_1251_PG11:
default:
- wl12xx_error("unsupported chip id: 0x%x", wl->chip.id);
+ wl1251_error("unsupported chip id: 0x%x", wl->chip_id);
ret = -ENODEV;
goto out;
}
if (wl->fw == NULL) {
- ret = wl12xx_fetch_firmware(wl);
+ ret = wl1251_fetch_firmware(wl);
if (ret < 0)
goto out;
}
/* No NVS from netlink, try to get it from the filesystem */
if (wl->nvs == NULL) {
- ret = wl12xx_fetch_nvs(wl);
+ ret = wl1251_fetch_nvs(wl);
if (ret < 0)
goto out;
}
@@ -223,88 +208,180 @@ out:
return ret;
}
-static void wl12xx_filter_work(struct work_struct *work)
+static void wl1251_irq_work(struct work_struct *work)
{
- struct wl12xx *wl =
- container_of(work, struct wl12xx, filter_work);
+ u32 intr;
+ struct wl1251 *wl =
+ container_of(work, struct wl1251, irq_work);
int ret;
mutex_lock(&wl->mutex);
- if (wl->state == WL12XX_STATE_OFF)
+ wl1251_debug(DEBUG_IRQ, "IRQ work");
+
+ if (wl->state == WL1251_STATE_OFF)
goto out;
- ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+ ret = wl1251_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
-out:
- mutex_unlock(&wl->mutex);
-}
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL);
+
+ intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
+ wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr);
+
+ if (wl->data_path) {
+ wl->rx_counter =
+ wl1251_mem_read32(wl, wl->data_path->rx_control_addr);
+
+ /* We handle a frmware bug here */
+ switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
+ case 0:
+ wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync");
+ intr &= ~WL1251_ACX_INTR_RX0_DATA;
+ intr &= ~WL1251_ACX_INTR_RX1_DATA;
+ break;
+ case 1:
+ wl1251_debug(DEBUG_IRQ, "RX: FW +1");
+ intr |= WL1251_ACX_INTR_RX0_DATA;
+ intr &= ~WL1251_ACX_INTR_RX1_DATA;
+ break;
+ case 2:
+ wl1251_debug(DEBUG_IRQ, "RX: FW +2");
+ intr |= WL1251_ACX_INTR_RX0_DATA;
+ intr |= WL1251_ACX_INTR_RX1_DATA;
+ break;
+ default:
+ wl1251_warning("RX: FW and host out of sync: %d",
+ wl->rx_counter - wl->rx_handled);
+ break;
+ }
-int wl12xx_plt_start(struct wl12xx *wl)
-{
- int ret;
+ wl->rx_handled = wl->rx_counter;
- wl12xx_notice("power up");
- if (wl->state != WL12XX_STATE_OFF) {
- wl12xx_error("cannot go into PLT state because not "
- "in off state: %d", wl->state);
- return -EBUSY;
+ wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter);
}
- wl->state = WL12XX_STATE_PLT;
+ intr &= wl->intr_mask;
- ret = wl12xx_chip_wakeup(wl);
- if (ret < 0)
- return ret;
+ if (intr == 0) {
+ wl1251_debug(DEBUG_IRQ, "INTR is 0");
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+ ~(wl->intr_mask));
+
+ goto out_sleep;
+ }
- ret = wl->chip.op_boot(wl);
+ if (intr & WL1251_ACX_INTR_RX0_DATA) {
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
+ wl1251_rx(wl);
+ }
+
+ if (intr & WL1251_ACX_INTR_RX1_DATA) {
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
+ wl1251_rx(wl);
+ }
+
+ if (intr & WL1251_ACX_INTR_TX_RESULT) {
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
+ wl1251_tx_complete(wl);
+ }
+
+ if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) {
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr);
+ if (intr & WL1251_ACX_INTR_EVENT_A)
+ wl1251_event_handle(wl, 0);
+ else
+ wl1251_event_handle(wl, 1);
+ }
+
+ if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
+
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
+
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel,
+ u16 beacon_interval, u8 dtim_period)
+{
+ int ret;
+
+ ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE,
+ DEFAULT_HW_GEN_MODULATION_TYPE,
+ wl->tx_mgmt_frm_rate,
+ wl->tx_mgmt_frm_mod);
if (ret < 0)
- return ret;
+ goto out;
- wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
- ret = wl->chip.op_plt_init(wl);
+ ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval,
+ dtim_period);
if (ret < 0)
- return ret;
+ goto out;
- return 0;
+ /*
+ * FIXME: we should wait for JOIN_EVENT_COMPLETE_ID but to simplify
+ * locking we just sleep instead, for now
+ */
+ msleep(10);
+
+out:
+ return ret;
}
-int wl12xx_plt_stop(struct wl12xx *wl)
+static void wl1251_filter_work(struct work_struct *work)
{
- wl12xx_notice("power down");
+ struct wl1251 *wl =
+ container_of(work, struct wl1251, filter_work);
+ int ret;
- if (wl->state != WL12XX_STATE_PLT) {
- wl12xx_error("cannot power down because not in PLT "
- "state: %d", wl->state);
- return -EBUSY;
- }
+ mutex_lock(&wl->mutex);
- wl12xx_disable_interrupts(wl);
- wl12xx_power_off(wl);
+ if (wl->state == WL1251_STATE_OFF)
+ goto out;
- wl->state = WL12XX_STATE_OFF;
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
- return 0;
-}
+ ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int,
+ wl->dtim_period);
+ if (ret < 0)
+ goto out_sleep;
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
-static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
skb_queue_tail(&wl->tx_queue, skb);
- schedule_work(&wl->tx_work);
+ /*
+ * The chip specific setup must run before the first TX packet -
+ * before that, the tx_work will not be initialized!
+ */
+
+ ieee80211_queue_work(wl->hw, &wl->tx_work);
/*
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
- if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) {
+ if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) {
ieee80211_stop_queues(wl->hw);
/*
@@ -318,62 +395,62 @@ static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
-static int wl12xx_op_start(struct ieee80211_hw *hw)
+static int wl1251_op_start(struct ieee80211_hw *hw)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
int ret = 0;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 start");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 start");
mutex_lock(&wl->mutex);
- if (wl->state != WL12XX_STATE_OFF) {
- wl12xx_error("cannot start because not in off state: %d",
+ if (wl->state != WL1251_STATE_OFF) {
+ wl1251_error("cannot start because not in off state: %d",
wl->state);
ret = -EBUSY;
goto out;
}
- ret = wl12xx_chip_wakeup(wl);
+ ret = wl1251_chip_wakeup(wl);
if (ret < 0)
- return ret;
+ goto out;
- ret = wl->chip.op_boot(wl);
+ ret = wl1251_boot(wl);
if (ret < 0)
goto out;
- ret = wl->chip.op_hw_init(wl);
+ ret = wl1251_hw_init(wl);
if (ret < 0)
goto out;
- ret = wl12xx_acx_station_id(wl);
+ ret = wl1251_acx_station_id(wl);
if (ret < 0)
goto out;
- wl->state = WL12XX_STATE_ON;
+ wl->state = WL1251_STATE_ON;
- wl12xx_info("firmware booted (%s)", wl->chip.fw_ver);
+ wl1251_info("firmware booted (%s)", wl->fw_ver);
out:
if (ret < 0)
- wl12xx_power_off(wl);
+ wl1251_power_off(wl);
mutex_unlock(&wl->mutex);
return ret;
}
-static void wl12xx_op_stop(struct ieee80211_hw *hw)
+static void wl1251_op_stop(struct ieee80211_hw *hw)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
- wl12xx_info("down");
+ wl1251_info("down");
- wl12xx_debug(DEBUG_MAC80211, "mac80211 stop");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 stop");
mutex_lock(&wl->mutex);
- WARN_ON(wl->state != WL12XX_STATE_ON);
+ WARN_ON(wl->state != WL1251_STATE_ON);
if (wl->scanning) {
mutex_unlock(&wl->mutex);
@@ -382,9 +459,9 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
wl->scanning = false;
}
- wl->state = WL12XX_STATE_OFF;
+ wl->state = WL1251_STATE_OFF;
- wl12xx_disable_interrupts(wl);
+ wl1251_disable_interrupts(wl);
mutex_unlock(&wl->mutex);
@@ -395,9 +472,8 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
mutex_lock(&wl->mutex);
/* let's notify MAC80211 about the remaining pending TX frames */
- wl12xx_tx_flush(wl);
-
- wl12xx_power_off(wl);
+ wl1251_tx_flush(wl);
+ wl1251_power_off(wl);
memset(wl->bssid, 0, ETH_ALEN);
wl->listen_int = 1;
@@ -412,22 +488,22 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
wl->elp = false;
wl->psm = 0;
wl->tx_queue_stopped = false;
- wl->power_level = WL12XX_DEFAULT_POWER_LEVEL;
+ wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
+ wl->channel = WL1251_DEFAULT_CHANNEL;
- wl12xx_debugfs_reset(wl);
+ wl1251_debugfs_reset(wl);
mutex_unlock(&wl->mutex);
}
-static int wl12xx_op_add_interface(struct ieee80211_hw *hw,
+static int wl1251_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
- struct wl12xx *wl = hw->priv;
- DECLARE_MAC_BUF(mac);
+ struct wl1251 *wl = hw->priv;
int ret = 0;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s",
- conf->type, print_mac(mac, conf->mac_addr));
+ wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
+ conf->type, conf->mac_addr);
mutex_lock(&wl->mutex);
@@ -446,7 +522,7 @@ static int wl12xx_op_add_interface(struct ieee80211_hw *hw,
if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) {
memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
- ret = wl12xx_acx_station_id(wl);
+ ret = wl1251_acx_station_id(wl);
if (ret < 0)
goto out;
}
@@ -456,13 +532,13 @@ out:
return ret;
}
-static void wl12xx_op_remove_interface(struct ieee80211_hw *hw,
+static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
- wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface");
}
-static int wl12xx_build_null_data(struct wl12xx *wl)
+static int wl1251_build_null_data(struct wl1251 *wl)
{
struct wl12xx_null_data_template template;
@@ -478,12 +554,12 @@ static int wl12xx_build_null_data(struct wl12xx *wl)
template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
IEEE80211_STYPE_NULLFUNC);
- return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template,
+ return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template,
sizeof(template));
}
-static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid)
+static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid)
{
struct wl12xx_ps_poll_template template;
@@ -492,41 +568,45 @@ static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid)
template.aid = aid;
template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
- return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template,
+ return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template,
sizeof(template));
}
-static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed)
+static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
int channel, ret = 0;
channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
- wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
+ wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
channel,
conf->flags & IEEE80211_CONF_PS ? "on" : "off",
conf->power_level);
mutex_lock(&wl->mutex);
- if (channel != wl->channel) {
- /* FIXME: use beacon interval provided by mac80211 */
- ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
- if (ret < 0)
- goto out;
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+ if (channel != wl->channel) {
wl->channel = channel;
+
+ ret = wl1251_join(wl, wl->bss_type, wl->channel,
+ wl->beacon_int, wl->dtim_period);
+ if (ret < 0)
+ goto out_sleep;
}
- ret = wl12xx_build_null_data(wl);
+ ret = wl1251_build_null_data(wl);
if (ret < 0)
- goto out;
+ goto out_sleep;
if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
- wl12xx_info("psm enabled");
+ wl1251_debug(DEBUG_PSM, "psm enabled");
wl->psm_requested = true;
@@ -535,49 +615,51 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed)
* If we're not, we'll enter it when joining an SSID,
* through the bss_info_changed() hook.
*/
- ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+ ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
} else if (!(conf->flags & IEEE80211_CONF_PS) &&
wl->psm_requested) {
- wl12xx_info("psm disabled");
+ wl1251_debug(DEBUG_PSM, "psm disabled");
wl->psm_requested = false;
if (wl->psm)
- ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
}
if (conf->power_level != wl->power_level) {
- ret = wl12xx_acx_tx_power(wl, conf->power_level);
+ ret = wl1251_acx_tx_power(wl, conf->power_level);
if (ret < 0)
goto out;
wl->power_level = conf->power_level;
}
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
out:
mutex_unlock(&wl->mutex);
+
return ret;
}
-#define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
+#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
FIF_ALLMULTI | \
FIF_FCSFAIL | \
FIF_BCN_PRBRESP_PROMISC | \
FIF_CONTROL | \
FIF_OTHER_BSS)
-static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
+static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed,
- unsigned int *total,
- int mc_count,
- struct dev_addr_list *mc_list)
+ unsigned int *total,u64 multicast)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter");
- *total &= WL12XX_SUPPORTED_FILTERS;
- changed &= WL12XX_SUPPORTED_FILTERS;
+ *total &= WL1251_SUPPORTED_FILTERS;
+ changed &= WL1251_SUPPORTED_FILTERS;
if (changed == 0)
/* no filters which we support changed */
@@ -585,8 +667,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
/* FIXME: wl->rx_config and wl->rx_filter are not protected */
- wl->rx_config = WL12XX_DEFAULT_RX_CONFIG;
- wl->rx_filter = WL12XX_DEFAULT_RX_FILTER;
+ wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
+ wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
if (*total & FIF_PROMISC_IN_BSS) {
wl->rx_config |= CFG_BSSID_FILTER_EN;
@@ -618,7 +700,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
}
/* HW encryption */
-static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key,
+static int wl1251_set_key_type(struct wl1251 *wl,
+ struct wl1251_cmd_set_keys *key,
enum set_key_cmd cmd,
struct ieee80211_key_conf *mac80211_key,
const u8 *addr)
@@ -648,95 +731,116 @@ static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key,
mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
break;
default:
- wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg);
+ wl1251_error("Unknown key algo 0x%x", mac80211_key->alg);
return -EOPNOTSUPP;
}
return 0;
}
-static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
- struct wl12xx *wl = hw->priv;
- struct acx_set_key wl_key;
+ struct wl1251 *wl = hw->priv;
+ struct wl1251_cmd_set_keys *wl_cmd;
const u8 *addr;
int ret;
static const u8 bcast_addr[ETH_ALEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- wl12xx_debug(DEBUG_MAC80211, "mac80211 set key");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 set key");
- memset(&wl_key, 0, sizeof(wl_key));
+ wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL);
+ if (!wl_cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
addr = sta ? sta->addr : bcast_addr;
- wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
- wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
- wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
+ wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
+ wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
+ wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
key->alg, key->keyidx, key->keylen, key->flags);
- wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen);
+ wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen);
+
+ if (is_zero_ether_addr(addr)) {
+ /* We dont support TX only encryption */
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out_unlock;
+
switch (cmd) {
case SET_KEY:
- wl_key.key_action = KEY_ADD_OR_REPLACE;
+ wl_cmd->key_action = KEY_ADD_OR_REPLACE;
break;
case DISABLE_KEY:
- wl_key.key_action = KEY_REMOVE;
+ wl_cmd->key_action = KEY_REMOVE;
break;
default:
- wl12xx_error("Unsupported key cmd 0x%x", cmd);
+ wl1251_error("Unsupported key cmd 0x%x", cmd);
break;
}
- ret = wl12xx_set_key_type(wl, &wl_key, cmd, key, addr);
+ ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr);
if (ret < 0) {
- wl12xx_error("Set KEY type failed");
- goto out;
+ wl1251_error("Set KEY type failed");
+ goto out_sleep;
}
- if (wl_key.key_type != KEY_WEP_DEFAULT)
- memcpy(wl_key.addr, addr, ETH_ALEN);
+ if (wl_cmd->key_type != KEY_WEP_DEFAULT)
+ memcpy(wl_cmd->addr, addr, ETH_ALEN);
- if ((wl_key.key_type == KEY_TKIP_MIC_GROUP) ||
- (wl_key.key_type == KEY_TKIP_MIC_PAIRWISE)) {
+ if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) ||
+ (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) {
/*
* We get the key in the following form:
* TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
* but the target is expecting:
* TKIP - RX MIC - TX MIC
*/
- memcpy(wl_key.key, key->key, 16);
- memcpy(wl_key.key + 16, key->key + 24, 8);
- memcpy(wl_key.key + 24, key->key + 16, 8);
+ memcpy(wl_cmd->key, key->key, 16);
+ memcpy(wl_cmd->key + 16, key->key + 24, 8);
+ memcpy(wl_cmd->key + 24, key->key + 16, 8);
} else {
- memcpy(wl_key.key, key->key, key->keylen);
+ memcpy(wl_cmd->key, key->key, key->keylen);
}
- wl_key.key_size = key->keylen;
+ wl_cmd->key_size = key->keylen;
- wl_key.id = key->keyidx;
- wl_key.ssid_profile = 0;
+ wl_cmd->id = key->keyidx;
+ wl_cmd->ssid_profile = 0;
- wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", &wl_key, sizeof(wl_key));
+ wl1251_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd));
- if (wl12xx_cmd_send(wl, CMD_SET_KEYS, &wl_key, sizeof(wl_key)) < 0) {
- wl12xx_error("Set KEY failed");
- ret = -EOPNOTSUPP;
- goto out;
+ ret = wl1251_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd));
+ if (ret < 0) {
+ wl1251_warning("could not set keys");
+ goto out_sleep;
}
-out:
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
+out_unlock:
mutex_unlock(&wl->mutex);
+
+out:
+ kfree(wl_cmd);
+
return ret;
}
-static int wl12xx_build_basic_rates(char *rates)
+static int wl1251_build_basic_rates(char *rates)
{
u8 index = 0;
@@ -748,7 +852,7 @@ static int wl12xx_build_basic_rates(char *rates)
return index;
}
-static int wl12xx_build_extended_rates(char *rates)
+static int wl1251_build_extended_rates(char *rates)
{
u8 index = 0;
@@ -765,7 +869,7 @@ static int wl12xx_build_extended_rates(char *rates)
}
-static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len)
+static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len)
{
struct wl12xx_probe_req_template template;
struct wl12xx_ie_rates *rates;
@@ -792,31 +896,30 @@ static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len)
/* Basic Rates */
rates = (struct wl12xx_ie_rates *)ptr;
rates->header.id = WLAN_EID_SUPP_RATES;
- rates->header.len = wl12xx_build_basic_rates(rates->rates);
+ rates->header.len = wl1251_build_basic_rates(rates->rates);
size += sizeof(struct wl12xx_ie_header) + rates->header.len;
ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;
/* Extended rates */
rates = (struct wl12xx_ie_rates *)ptr;
rates->header.id = WLAN_EID_EXT_SUPP_RATES;
- rates->header.len = wl12xx_build_extended_rates(rates->rates);
+ rates->header.len = wl1251_build_extended_rates(rates->rates);
size += sizeof(struct wl12xx_ie_header) + rates->header.len;
- wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
+ wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
- return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template,
+ return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template,
size);
}
-static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len,
+static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len,
u8 active_scan, u8 high_prio, u8 num_channels,
u8 probe_requests)
{
+ struct wl1251_cmd_trigger_scan_to *trigger = NULL;
+ struct cmd_scan *params = NULL;
int i, ret;
- u32 split_scan = 0;
u16 scan_options = 0;
- struct cmd_scan *params;
- struct wl12xx_command *cmd_answer;
if (wl->scanning)
return -EINVAL;
@@ -864,33 +967,38 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len,
memset(params->params.ssid, 0, 32);
}
- ret = wl12xx_build_probe_req(wl, ssid, len);
+ ret = wl1251_build_probe_req(wl, ssid, len);
if (ret < 0) {
- wl12xx_error("PROBE request template failed");
+ wl1251_error("PROBE request template failed");
goto out;
}
- ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, &split_scan,
- sizeof(u32));
+ trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
+ if (!trigger)
+ goto out;
+
+ trigger->timeout = 0;
+
+ ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
+ sizeof(*trigger));
if (ret < 0) {
- wl12xx_error("Split SCAN failed");
+ wl1251_error("trigger scan to failed for hw scan");
goto out;
}
- wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
+ wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
wl->scanning = true;
- ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
+ ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
if (ret < 0)
- wl12xx_error("SCAN failed");
+ wl1251_error("SCAN failed");
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
+ wl1251_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
- cmd_answer = (struct wl12xx_command *) params;
- if (cmd_answer->status != CMD_STATUS_SUCCESS) {
- wl12xx_error("TEST command answer error: %d",
- cmd_answer->status);
+ if (params->header.status != CMD_STATUS_SUCCESS) {
+ wl1251_error("TEST command answer error: %d",
+ params->header.status);
wl->scanning = false;
ret = -EIO;
goto out;
@@ -902,15 +1010,15 @@ out:
}
-static int wl12xx_op_hw_scan(struct ieee80211_hw *hw,
+static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
struct cfg80211_scan_request *req)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
int ret;
u8 *ssid = NULL;
size_t ssid_len = 0;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan");
if (req->n_ssids) {
ssid = req->ssids[0].ssid;
@@ -918,85 +1026,117 @@ static int wl12xx_op_hw_scan(struct ieee80211_hw *hw,
}
mutex_lock(&wl->mutex);
- ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
+
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
+
+ wl1251_ps_elp_sleep(wl);
+
+out:
mutex_unlock(&wl->mutex);
return ret;
}
-static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
int ret;
- ret = wl12xx_acx_rts_threshold(wl, (u16) value);
+ mutex_lock(&wl->mutex);
+
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+ ret = wl1251_acx_rts_threshold(wl, (u16) value);
if (ret < 0)
- wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret);
+ wl1251_warning("wl1251_op_set_rts_threshold failed: %d", ret);
+
+ wl1251_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
return ret;
}
-static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
+static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changed)
{
- enum acx_ps_mode mode;
- struct wl12xx *wl = hw->priv;
+ enum wl1251_cmd_ps_mode mode;
+ struct wl1251 *wl = hw->priv;
struct sk_buff *beacon;
int ret;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed");
mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
+ wl->beacon_int = bss_conf->beacon_int;
+ wl->dtim_period = bss_conf->dtim_period;
+
+ /* FIXME: call join */
+
wl->aid = bss_conf->aid;
- ret = wl12xx_build_ps_poll(wl, wl->aid);
+ ret = wl1251_build_ps_poll(wl, wl->aid);
if (ret < 0)
- goto out;
+ goto out_sleep;
- ret = wl12xx_acx_aid(wl, wl->aid);
+ ret = wl1251_acx_aid(wl, wl->aid);
if (ret < 0)
- goto out;
+ goto out_sleep;
/* If we want to go in PSM but we're not there yet */
if (wl->psm_requested && !wl->psm) {
mode = STATION_POWER_SAVE_MODE;
- ret = wl12xx_ps_set_mode(wl, mode);
+ ret = wl1251_ps_set_mode(wl, mode);
if (ret < 0)
- goto out;
+ goto out_sleep;
}
+ } else {
+ /* use defaults when not associated */
+ wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
+ wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD;
}
}
if (changed & BSS_CHANGED_ERP_SLOT) {
if (bss_conf->use_short_slot)
- ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT);
+ ret = wl1251_acx_slot(wl, SLOT_TIME_SHORT);
else
- ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG);
+ ret = wl1251_acx_slot(wl, SLOT_TIME_LONG);
if (ret < 0) {
- wl12xx_warning("Set slot time failed %d", ret);
- goto out;
+ wl1251_warning("Set slot time failed %d", ret);
+ goto out_sleep;
}
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
if (bss_conf->use_short_preamble)
- wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
+ wl1251_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
else
- wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
+ wl1251_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
if (bss_conf->use_cts_prot)
- ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE);
+ ret = wl1251_acx_cts_protect(wl, CTSPROTECT_ENABLE);
else
- ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE);
+ ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE);
if (ret < 0) {
- wl12xx_warning("Set ctsprotect failed %d", ret);
+ wl1251_warning("Set ctsprotect failed %d", ret);
goto out;
}
}
@@ -1004,20 +1144,23 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BSSID) {
memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
- ret = wl12xx_build_null_data(wl);
+ ret = wl1251_build_null_data(wl);
if (ret < 0)
goto out;
if (wl->bss_type != BSS_TYPE_IBSS) {
- ret = wl12xx_cmd_join(wl, wl->bss_type, 5, 100, 1);
+ ret = wl1251_join(wl, wl->bss_type, wl->channel,
+ wl->beacon_int, wl->dtim_period);
if (ret < 0)
- goto out;
+ goto out_sleep;
+ wl1251_warning("Set ctsprotect failed %d", ret);
+ goto out_sleep;
}
}
if (changed & BSS_CHANGED_BEACON) {
beacon = ieee80211_beacon_get(hw, vif);
- ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data,
+ ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data,
beacon->len);
if (ret < 0) {
@@ -1025,7 +1168,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
goto out;
}
- ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data,
+ ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data,
beacon->len);
dev_kfree_skb(beacon);
@@ -1033,19 +1176,23 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+ ret = wl1251_join(wl, wl->bss_type, wl->beacon_int,
+ wl->channel, wl->dtim_period);
if (ret < 0)
goto out;
}
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
out:
mutex_unlock(&wl->mutex);
}
/* can't be const, mac80211 writes to this */
-static struct ieee80211_rate wl12xx_rates[] = {
+static struct ieee80211_rate wl1251_rates[] = {
{ .bitrate = 10,
.hw_value = 0x1,
.hw_value_short = 0x1, },
@@ -1088,7 +1235,7 @@ static struct ieee80211_rate wl12xx_rates[] = {
};
/* can't be const, mac80211 writes to this */
-static struct ieee80211_channel wl12xx_channels[] = {
+static struct ieee80211_channel wl1251_channels[] = {
{ .hw_value = 1, .center_freq = 2412},
{ .hw_value = 2, .center_freq = 2417},
{ .hw_value = 3, .center_freq = 2422},
@@ -1105,28 +1252,28 @@ static struct ieee80211_channel wl12xx_channels[] = {
};
/* can't be const, mac80211 writes to this */
-static struct ieee80211_supported_band wl12xx_band_2ghz = {
- .channels = wl12xx_channels,
- .n_channels = ARRAY_SIZE(wl12xx_channels),
- .bitrates = wl12xx_rates,
- .n_bitrates = ARRAY_SIZE(wl12xx_rates),
+static struct ieee80211_supported_band wl1251_band_2ghz = {
+ .channels = wl1251_channels,
+ .n_channels = ARRAY_SIZE(wl1251_channels),
+ .bitrates = wl1251_rates,
+ .n_bitrates = ARRAY_SIZE(wl1251_rates),
};
-static const struct ieee80211_ops wl12xx_ops = {
- .start = wl12xx_op_start,
- .stop = wl12xx_op_stop,
- .add_interface = wl12xx_op_add_interface,
- .remove_interface = wl12xx_op_remove_interface,
- .config = wl12xx_op_config,
- .configure_filter = wl12xx_op_configure_filter,
- .tx = wl12xx_op_tx,
- .set_key = wl12xx_op_set_key,
- .hw_scan = wl12xx_op_hw_scan,
- .bss_info_changed = wl12xx_op_bss_info_changed,
- .set_rts_threshold = wl12xx_op_set_rts_threshold,
+static const struct ieee80211_ops wl1251_ops = {
+ .start = wl1251_op_start,
+ .stop = wl1251_op_stop,
+ .add_interface = wl1251_op_add_interface,
+ .remove_interface = wl1251_op_remove_interface,
+ .config = wl1251_op_config,
+ .configure_filter = wl1251_op_configure_filter,
+ .tx = wl1251_op_tx,
+ .set_key = wl1251_op_set_key,
+ .hw_scan = wl1251_op_hw_scan,
+ .bss_info_changed = wl1251_op_bss_info_changed,
+ .set_rts_threshold = wl1251_op_set_rts_threshold,
};
-static int wl12xx_register_hw(struct wl12xx *wl)
+static int wl1251_register_hw(struct wl1251 *wl)
{
int ret;
@@ -1137,22 +1284,24 @@ static int wl12xx_register_hw(struct wl12xx *wl)
ret = ieee80211_register_hw(wl->hw);
if (ret < 0) {
- wl12xx_error("unable to register mac80211 hw: %d", ret);
+ wl1251_error("unable to register mac80211 hw: %d", ret);
return ret;
}
wl->mac80211_registered = true;
- wl12xx_notice("loaded");
+ wl1251_notice("loaded");
return 0;
}
-static int wl12xx_init_ieee80211(struct wl12xx *wl)
+int wl1251_init_ieee80211(struct wl1251 *wl)
{
+ int ret;
+
/* The tx descriptor buffer and the TKIP space */
wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc)
- + WL12XX_TKIP_IV_SPACE;
+ + WL1251_TKIP_IV_SPACE;
/* unit us */
/* FIXME: find a proper value */
@@ -1163,48 +1312,46 @@ static int wl12xx_init_ieee80211(struct wl12xx *wl)
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
wl->hw->wiphy->max_scan_ssids = 1;
- wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz;
+ wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz;
- SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
+ ret = wl1251_register_hw(wl);
+ if (ret)
+ goto out;
- return 0;
+ wl1251_debugfs_init(wl);
+ wl1251_notice("initialized");
+
+ ret = 0;
+
+out:
+ return ret;
}
+EXPORT_SYMBOL_GPL(wl1251_init_ieee80211);
-#define WL12XX_DEFAULT_CHANNEL 1
-static int __devinit wl12xx_probe(struct spi_device *spi)
+struct ieee80211_hw *wl1251_alloc_hw(void)
{
- struct wl12xx_platform_data *pdata;
struct ieee80211_hw *hw;
- struct wl12xx *wl;
- int ret, i;
+ struct wl1251 *wl;
+ int i;
static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
- pdata = spi->dev.platform_data;
- if (!pdata) {
- wl12xx_error("no platform data");
- return -ENODEV;
- }
-
- hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops);
+ hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops);
if (!hw) {
- wl12xx_error("could not alloc ieee80211_hw");
- return -ENOMEM;
+ wl1251_error("could not alloc ieee80211_hw");
+ return ERR_PTR(-ENOMEM);
}
wl = hw->priv;
memset(wl, 0, sizeof(*wl));
wl->hw = hw;
- dev_set_drvdata(&spi->dev, wl);
- wl->spi = spi;
wl->data_in_count = 0;
skb_queue_head_init(&wl->tx_queue);
- INIT_WORK(&wl->tx_work, wl12xx_tx_work);
- INIT_WORK(&wl->filter_work, wl12xx_filter_work);
- wl->channel = WL12XX_DEFAULT_CHANNEL;
+ INIT_WORK(&wl->filter_work, wl1251_filter_work);
+ wl->channel = WL1251_DEFAULT_CHANNEL;
wl->scanning = false;
wl->default_key = 0;
wl->listen_int = 1;
@@ -1212,23 +1359,24 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
wl->rx_handled = 0;
wl->rx_current_buffer = 0;
wl->rx_last_id = 0;
- wl->rx_config = WL12XX_DEFAULT_RX_CONFIG;
- wl->rx_filter = WL12XX_DEFAULT_RX_FILTER;
+ wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
+ wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
wl->elp = false;
wl->psm = 0;
wl->psm_requested = false;
wl->tx_queue_stopped = false;
- wl->power_level = WL12XX_DEFAULT_POWER_LEVEL;
-
- /* We use the default power on sleep time until we know which chip
- * we're using */
- wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP;
+ wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
+ wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
+ wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD;
for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
wl->tx_frames[i] = NULL;
wl->next_tx_complete = 0;
+ INIT_WORK(&wl->irq_work, wl1251_irq_work);
+ INIT_WORK(&wl->tx_work, wl1251_tx_work);
+
/*
* In case our MAC address is not correctly set,
* we use a random but Nokia MAC.
@@ -1236,123 +1384,45 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
memcpy(wl->mac_addr, nokia_oui, 3);
get_random_bytes(wl->mac_addr + 3, 3);
- wl->state = WL12XX_STATE_OFF;
+ wl->state = WL1251_STATE_OFF;
mutex_init(&wl->mutex);
wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE;
wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE;
- /* This is the only SPI value that we need to set here, the rest
- * comes from the board-peripherals file */
- spi->bits_per_word = 32;
-
- ret = spi_setup(spi);
- if (ret < 0) {
- wl12xx_error("spi_setup failed");
- goto out_free;
- }
-
- wl->set_power = pdata->set_power;
- if (!wl->set_power) {
- wl12xx_error("set power function missing in platform data");
- return -ENODEV;
- }
-
- wl->irq = spi->irq;
- if (wl->irq < 0) {
- wl12xx_error("irq missing in platform data");
- return -ENODEV;
- }
-
- ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl);
- if (ret < 0) {
- wl12xx_error("request_irq() failed: %d", ret);
- goto out_free;
+ wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL);
+ if (!wl->rx_descriptor) {
+ wl1251_error("could not allocate memory for rx descriptor");
+ ieee80211_free_hw(hw);
+ return ERR_PTR(-ENOMEM);
}
- set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
-
- disable_irq(wl->irq);
-
- ret = wl12xx_init_ieee80211(wl);
- if (ret)
- goto out_irq;
-
- ret = wl12xx_register_hw(wl);
- if (ret)
- goto out_irq;
-
- wl12xx_debugfs_init(wl);
-
- wl12xx_notice("initialized");
-
- return 0;
-
- out_irq:
- free_irq(wl->irq, wl);
-
- out_free:
- ieee80211_free_hw(hw);
-
- return ret;
+ return hw;
}
+EXPORT_SYMBOL_GPL(wl1251_alloc_hw);
-static int __devexit wl12xx_remove(struct spi_device *spi)
+int wl1251_free_hw(struct wl1251 *wl)
{
- struct wl12xx *wl = dev_get_drvdata(&spi->dev);
-
ieee80211_unregister_hw(wl->hw);
- wl12xx_debugfs_exit(wl);
+ wl1251_debugfs_exit(wl);
- free_irq(wl->irq, wl);
kfree(wl->target_mem_map);
kfree(wl->data_path);
kfree(wl->fw);
wl->fw = NULL;
kfree(wl->nvs);
wl->nvs = NULL;
- ieee80211_free_hw(wl->hw);
-
- return 0;
-}
-
-static struct spi_driver wl12xx_spi_driver = {
- .driver = {
- .name = "wl12xx",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
+ kfree(wl->rx_descriptor);
+ wl->rx_descriptor = NULL;
- .probe = wl12xx_probe,
- .remove = __devexit_p(wl12xx_remove),
-};
-
-static int __init wl12xx_init(void)
-{
- int ret;
-
- ret = spi_register_driver(&wl12xx_spi_driver);
- if (ret < 0) {
- wl12xx_error("failed to register spi driver: %d", ret);
- goto out;
- }
-
-out:
- return ret;
-}
-
-static void __exit wl12xx_exit(void)
-{
- spi_unregister_driver(&wl12xx_spi_driver);
+ ieee80211_free_hw(wl->hw);
- wl12xx_notice("unloaded");
+ return 0;
}
+EXPORT_SYMBOL_GPL(wl1251_free_hw);
-module_init(wl12xx_init);
-module_exit(wl12xx_exit);
-
+MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core");
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kalle Valo <Kalle.Valo@nokia.com>, "
- "Luciano Coelho <luciano.coelho@nokia.com>");
+MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/wl1251_netlink.h
index c8b6cd0b7c3e..ee36695e134e 100644
--- a/drivers/net/wireless/wl12xx/init.h
+++ b/drivers/net/wireless/wl12xx/wl1251_netlink.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -21,20 +21,10 @@
*
*/
-#ifndef __WL12XX_INIT_H__
-#define __WL12XX_INIT_H__
+#ifndef __WL1251_NETLINK_H__
+#define __WL1251_NETLINK_H__
-#include "wl12xx.h"
+int wl1251_nl_register(void);
+void wl1251_nl_unregister(void);
-int wl12xx_hw_init_hwenc_config(struct wl12xx *wl);
-int wl12xx_hw_init_templates_config(struct wl12xx *wl);
-int wl12xx_hw_init_mem_config(struct wl12xx *wl);
-int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter);
-int wl12xx_hw_init_phy_config(struct wl12xx *wl);
-int wl12xx_hw_init_beacon_filter(struct wl12xx *wl);
-int wl12xx_hw_init_pta(struct wl12xx *wl);
-int wl12xx_hw_init_energy_detection(struct wl12xx *wl);
-int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl);
-int wl12xx_hw_init_power_auth(struct wl12xx *wl);
-
-#endif
+#endif /* __WL1251_NETLINK_H__ */
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c
index 83a10117330b..c53e28727ed4 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/wl1251_ps.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -21,26 +21,27 @@
*
*/
-#include "reg.h"
-#include "ps.h"
-#include "spi.h"
+#include "wl1251_reg.h"
+#include "wl1251_ps.h"
+#include "wl1251_cmd.h"
+#include "wl1251_io.h"
-#define WL12XX_WAKEUP_TIMEOUT 2000
+#define WL1251_WAKEUP_TIMEOUT 2000
/* Routines to toggle sleep mode while in ELP */
-void wl12xx_ps_elp_sleep(struct wl12xx *wl)
+void wl1251_ps_elp_sleep(struct wl1251 *wl)
{
if (wl->elp || !wl->psm)
return;
- wl12xx_debug(DEBUG_PSM, "chip to elp");
+ wl1251_debug(DEBUG_PSM, "chip to elp");
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
wl->elp = true;
}
-int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
+int wl1251_ps_elp_wakeup(struct wl1251 *wl)
{
unsigned long timeout;
u32 elp_reg;
@@ -48,13 +49,13 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
if (!wl->elp)
return 0;
- wl12xx_debug(DEBUG_PSM, "waking up chip from elp");
+ wl1251_debug(DEBUG_PSM, "waking up chip from elp");
- timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT);
+ timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
- elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
/*
* FIXME: we should wait for irq from chip but, as a temporary
@@ -62,40 +63,36 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
*/
while (!(elp_reg & ELPCTRL_WLAN_READY)) {
if (time_after(jiffies, timeout)) {
- wl12xx_error("elp wakeup timeout");
+ wl1251_error("elp wakeup timeout");
return -ETIMEDOUT;
}
msleep(1);
- elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
}
- wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms",
+ wl1251_debug(DEBUG_PSM, "wakeup time: %u ms",
jiffies_to_msecs(jiffies) -
- (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT));
+ (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT));
wl->elp = false;
return 0;
}
-static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
+static int wl1251_ps_set_elp(struct wl1251 *wl, bool enable)
{
int ret;
if (enable) {
- wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp");
+ wl1251_debug(DEBUG_PSM, "sleep auth psm/elp");
- /*
- * FIXME: we should PSM_ELP, but because of firmware wakeup
- * problems let's use only PSM_PS
- */
- ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_PS);
+ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
if (ret < 0)
return ret;
- wl12xx_ps_elp_sleep(wl);
+ wl1251_ps_elp_sleep(wl);
} else {
- wl12xx_debug(DEBUG_PSM, "sleep auth cam");
+ wl1251_debug(DEBUG_PSM, "sleep auth cam");
/*
* When the target is in ELP, we can only
@@ -104,9 +101,9 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
* changing the power authorization.
*/
- wl12xx_ps_elp_wakeup(wl);
+ wl1251_ps_elp_wakeup(wl);
- ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM);
+ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
if (ret < 0)
return ret;
}
@@ -114,18 +111,25 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
return 0;
}
-int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode)
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
{
int ret;
switch (mode) {
case STATION_POWER_SAVE_MODE:
- wl12xx_debug(DEBUG_PSM, "entering psm");
- ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
+ wl1251_debug(DEBUG_PSM, "entering psm");
+
+ ret = wl1251_acx_wake_up_conditions(wl,
+ WAKE_UP_EVENT_DTIM_BITMAP,
+ wl->listen_int);
if (ret < 0)
return ret;
- ret = wl12xx_ps_set_elp(wl, true);
+ ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_ps_set_elp(wl, true);
if (ret < 0)
return ret;
@@ -133,12 +137,18 @@ int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode)
break;
case STATION_ACTIVE_MODE:
default:
- wl12xx_debug(DEBUG_PSM, "leaving psm");
- ret = wl12xx_ps_set_elp(wl, false);
+ wl1251_debug(DEBUG_PSM, "leaving psm");
+ ret = wl1251_ps_set_elp(wl, false);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_acx_wake_up_conditions(wl,
+ WAKE_UP_EVENT_DTIM_BITMAP,
+ wl->listen_int);
if (ret < 0)
return ret;
- ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h
index 5d7c52553830..db036fe12f25 100644
--- a/drivers/net/wireless/wl12xx/ps.h
+++ b/drivers/net/wireless/wl12xx/wl1251_ps.h
@@ -1,8 +1,8 @@
-#ifndef __WL12XX_PS_H__
-#define __WL12XX_PS_H__
+#ifndef __WL1251_PS_H__
+#define __WL1251_PS_H__
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -25,12 +25,12 @@
*
*/
-#include "wl12xx.h"
-#include "acx.h"
+#include "wl1251.h"
+#include "wl1251_acx.h"
-int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode);
-void wl12xx_ps_elp_sleep(struct wl12xx *wl);
-int wl12xx_ps_elp_wakeup(struct wl12xx *wl);
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode);
+void wl1251_ps_elp_sleep(struct wl1251 *wl);
+int wl1251_ps_elp_wakeup(struct wl1251 *wl);
-#endif /* __WL12XX_PS_H__ */
+#endif /* __WL1251_PS_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h
new file mode 100644
index 000000000000..06e1bd94a739
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_reg.h
@@ -0,0 +1,644 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (c) 1998-2007 Texas Instruments Incorporated
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __REG_H__
+#define __REG_H__
+
+#include <linux/bitops.h>
+
+#define REGISTERS_BASE 0x00300000
+#define DRPW_BASE 0x00310000
+
+#define REGISTERS_DOWN_SIZE 0x00008800
+#define REGISTERS_WORK_SIZE 0x0000b000
+
+#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC
+
+/* ELP register commands */
+#define ELPCTRL_WAKE_UP 0x1
+#define ELPCTRL_WAKE_UP_WLAN_READY 0x5
+#define ELPCTRL_SLEEP 0x0
+/* ELP WLAN_READY bit */
+#define ELPCTRL_WLAN_READY 0x2
+
+/* Device Configuration registers*/
+#define SOR_CFG (REGISTERS_BASE + 0x0800)
+#define ECPU_CTRL (REGISTERS_BASE + 0x0804)
+#define HI_CFG (REGISTERS_BASE + 0x0808)
+#define EE_START (REGISTERS_BASE + 0x080C)
+
+#define CHIP_ID_B (REGISTERS_BASE + 0x5674)
+
+#define CHIP_ID_1251_PG10 (0x7010101)
+#define CHIP_ID_1251_PG11 (0x7020101)
+#define CHIP_ID_1251_PG12 (0x7030101)
+
+#define ENABLE (REGISTERS_BASE + 0x5450)
+
+/* Power Management registers */
+#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804)
+#define ELP_CMD (REGISTERS_BASE + 0x5808)
+#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810)
+#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814)
+#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818)
+
+#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820)
+
+/* Scratch Pad registers*/
+#define SCR_PAD0 (REGISTERS_BASE + 0x5608)
+#define SCR_PAD1 (REGISTERS_BASE + 0x560C)
+#define SCR_PAD2 (REGISTERS_BASE + 0x5610)
+#define SCR_PAD3 (REGISTERS_BASE + 0x5614)
+#define SCR_PAD4 (REGISTERS_BASE + 0x5618)
+#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C)
+#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620)
+#define SCR_PAD5 (REGISTERS_BASE + 0x5624)
+#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628)
+#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C)
+#define SCR_PAD6 (REGISTERS_BASE + 0x5630)
+#define SCR_PAD7 (REGISTERS_BASE + 0x5634)
+#define SCR_PAD8 (REGISTERS_BASE + 0x5638)
+#define SCR_PAD9 (REGISTERS_BASE + 0x563C)
+
+/* Spare registers*/
+#define SPARE_A1 (REGISTERS_BASE + 0x0994)
+#define SPARE_A2 (REGISTERS_BASE + 0x0998)
+#define SPARE_A3 (REGISTERS_BASE + 0x099C)
+#define SPARE_A4 (REGISTERS_BASE + 0x09A0)
+#define SPARE_A5 (REGISTERS_BASE + 0x09A4)
+#define SPARE_A6 (REGISTERS_BASE + 0x09A8)
+#define SPARE_A7 (REGISTERS_BASE + 0x09AC)
+#define SPARE_A8 (REGISTERS_BASE + 0x09B0)
+#define SPARE_B1 (REGISTERS_BASE + 0x5420)
+#define SPARE_B2 (REGISTERS_BASE + 0x5424)
+#define SPARE_B3 (REGISTERS_BASE + 0x5428)
+#define SPARE_B4 (REGISTERS_BASE + 0x542C)
+#define SPARE_B5 (REGISTERS_BASE + 0x5430)
+#define SPARE_B6 (REGISTERS_BASE + 0x5434)
+#define SPARE_B7 (REGISTERS_BASE + 0x5438)
+#define SPARE_B8 (REGISTERS_BASE + 0x543C)
+
+enum wl12xx_acx_int_reg {
+ ACX_REG_INTERRUPT_TRIG,
+ ACX_REG_INTERRUPT_TRIG_H,
+
+/*=============================================
+ Host Interrupt Mask Register - 32bit (RW)
+ ------------------------------------------
+ Setting a bit in this register masks the
+ corresponding interrupt to the host.
+ 0 - RX0 - Rx first dubble buffer Data Interrupt
+ 1 - TXD - Tx Data Interrupt
+ 2 - TXXFR - Tx Transfer Interrupt
+ 3 - RX1 - Rx second dubble buffer Data Interrupt
+ 4 - RXXFR - Rx Transfer Interrupt
+ 5 - EVENT_A - Event Mailbox interrupt
+ 6 - EVENT_B - Event Mailbox interrupt
+ 7 - WNONHST - Wake On Host Interrupt
+ 8 - TRACE_A - Debug Trace interrupt
+ 9 - TRACE_B - Debug Trace interrupt
+ 10 - CDCMP - Command Complete Interrupt
+ 11 -
+ 12 -
+ 13 -
+ 14 - ICOMP - Initialization Complete Interrupt
+ 16 - SG SE - Soft Gemini - Sense enable interrupt
+ 17 - SG SD - Soft Gemini - Sense disable interrupt
+ 18 - -
+ 19 - -
+ 20 - -
+ 21- -
+ Default: 0x0001
+*==============================================*/
+ ACX_REG_INTERRUPT_MASK,
+
+/*=============================================
+ Host Interrupt Mask Set 16bit, (Write only)
+ ------------------------------------------
+ Setting a bit in this register sets
+ the corresponding bin in ACX_HINT_MASK register
+ without effecting the mask
+ state of other bits (0 = no effect).
+==============================================*/
+ ACX_REG_HINT_MASK_SET,
+
+/*=============================================
+ Host Interrupt Mask Clear 16bit,(Write only)
+ ------------------------------------------
+ Setting a bit in this register clears
+ the corresponding bin in ACX_HINT_MASK register
+ without effecting the mask
+ state of other bits (0 = no effect).
+=============================================*/
+ ACX_REG_HINT_MASK_CLR,
+
+/*=============================================
+ Host Interrupt Status Nondestructive Read
+ 16bit,(Read only)
+ ------------------------------------------
+ The host can read this register to determine
+ which interrupts are active.
+ Reading this register doesn't
+ effect its content.
+=============================================*/
+ ACX_REG_INTERRUPT_NO_CLEAR,
+
+/*=============================================
+ Host Interrupt Status Clear on Read Register
+ 16bit,(Read only)
+ ------------------------------------------
+ The host can read this register to determine
+ which interrupts are active.
+ Reading this register clears it,
+ thus making all interrupts inactive.
+==============================================*/
+ ACX_REG_INTERRUPT_CLEAR,
+
+/*=============================================
+ Host Interrupt Acknowledge Register
+ 16bit,(Write only)
+ ------------------------------------------
+ The host can set individual bits in this
+ register to clear (acknowledge) the corresp.
+ interrupt status bits in the HINT_STS_CLR and
+ HINT_STS_ND registers, thus making the
+ assotiated interrupt inactive. (0-no effect)
+==============================================*/
+ ACX_REG_INTERRUPT_ACK,
+
+/*===============================================
+ Host Software Reset - 32bit RW
+ ------------------------------------------
+ [31:1] Reserved
+ 0 SOFT_RESET Soft Reset - When this bit is set,
+ it holds the Wlan hardware in a soft reset state.
+ This reset disables all MAC and baseband processor
+ clocks except the CardBus/PCI interface clock.
+ It also initializes all MAC state machines except
+ the host interface. It does not reload the
+ contents of the EEPROM. When this bit is cleared
+ (not self-clearing), the Wlan hardware
+ exits the software reset state.
+===============================================*/
+ ACX_REG_SLV_SOFT_RESET,
+
+/*===============================================
+ EEPROM Burst Read Start - 32bit RW
+ ------------------------------------------
+ [31:1] Reserved
+ 0 ACX_EE_START - EEPROM Burst Read Start 0
+ Setting this bit starts a burst read from
+ the external EEPROM.
+ If this bit is set (after reset) before an EEPROM read/write,
+ the burst read starts at EEPROM address 0.
+ Otherwise, it starts at the address
+ following the address of the previous access.
+ TheWlan hardware hardware clears this bit automatically.
+
+ Default: 0x00000000
+*================================================*/
+ ACX_REG_EE_START,
+
+/* Embedded ARM CPU Control */
+
+/*===============================================
+ Halt eCPU - 32bit RW
+ ------------------------------------------
+ 0 HALT_ECPU Halt Embedded CPU - This bit is the
+ compliment of bit 1 (MDATA2) in the SOR_CFG register.
+ During a hardware reset, this bit holds
+ the inverse of MDATA2.
+ When downloading firmware from the host,
+ set this bit (pull down MDATA2).
+ The host clears this bit after downloading the firmware into
+ zero-wait-state SSRAM.
+ When loading firmware from Flash, clear this bit (pull up MDATA2)
+ so that the eCPU can run the bootloader code in Flash
+ HALT_ECPU eCPU State
+ --------------------
+ 1 halt eCPU
+ 0 enable eCPU
+ ===============================================*/
+ ACX_REG_ECPU_CONTROL,
+
+ ACX_REG_TABLE_LEN
+};
+
+#define ACX_SLV_SOFT_RESET_BIT BIT(0)
+#define ACX_REG_EEPROM_START_BIT BIT(0)
+
+/* Command/Information Mailbox Pointers */
+
+/*===============================================
+ Command Mailbox Pointer - 32bit RW
+ ------------------------------------------
+ This register holds the start address of
+ the command mailbox located in the Wlan hardware memory.
+ The host must read this pointer after a reset to
+ find the location of the command mailbox.
+ The Wlan hardware initializes the command mailbox
+ pointer with the default address of the command mailbox.
+ The command mailbox pointer is not valid until after
+ the host receives the Init Complete interrupt from
+ the Wlan hardware.
+ ===============================================*/
+#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0)
+
+/*===============================================
+ Information Mailbox Pointer - 32bit RW
+ ------------------------------------------
+ This register holds the start address of
+ the information mailbox located in the Wlan hardware memory.
+ The host must read this pointer after a reset to find
+ the location of the information mailbox.
+ The Wlan hardware initializes the information mailbox pointer
+ with the default address of the information mailbox.
+ The information mailbox pointer is not valid
+ until after the host receives the Init Complete interrupt from
+ the Wlan hardware.
+ ===============================================*/
+#define REG_EVENT_MAILBOX_PTR (SCR_PAD1)
+
+
+/* Misc */
+
+#define REG_ENABLE_TX_RX (ENABLE)
+/*
+ * Rx configuration (filter) information element
+ * ---------------------------------------------
+ */
+#define REG_RX_CONFIG (RX_CFG)
+#define REG_RX_FILTER (RX_FILTER_CFG)
+
+
+#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002
+
+/* promiscuous - receives all valid frames */
+#define RX_CFG_PROMISCUOUS 0x0008
+
+/* receives frames from any BSSID */
+#define RX_CFG_BSSID 0x0020
+
+/* receives frames destined to any MAC address */
+#define RX_CFG_MAC 0x0010
+
+#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010
+#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000
+#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020
+#define RX_CFG_ENABLE_ANY_BSSID 0x0000
+
+/* discards all broadcast frames */
+#define RX_CFG_DISABLE_BCAST 0x0200
+
+#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400
+#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800
+#define RX_CFG_COPY_RX_STATUS 0x2000
+#define RX_CFG_TSF 0x10000
+
+#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \
+ RX_CFG_ENABLE_ONLY_MY_BSSID)
+
+#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\
+ | RX_CFG_ENABLE_ANY_BSSID)
+
+#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \
+ RX_CFG_ENABLE_ANY_BSSID)
+
+#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\
+ | RX_CFG_ENABLE_ONLY_MY_BSSID)
+
+#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \
+ | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \
+ | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF)
+
+#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC)
+
+#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \
+ RX_CFG_ENABLE_ONLY_MY_DEST_MAC)
+
+#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \
+ RX_CFG_ENABLE_ONLY_MY_DEST_MAC)
+
+#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\
+ | CFG_RX_CTL_EN | CFG_RX_BCN_EN\
+ | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
+
+#define RX_FILTER_OPTION_FILTER_ALL 0
+
+#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\
+ | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN)
+
+#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\
+ | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\
+ | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\
+ | CFG_RX_PRSP_EN)
+
+
+/*===============================================
+ EEPROM Read/Write Request 32bit RW
+ ------------------------------------------
+ 1 EE_READ - EEPROM Read Request 1 - Setting this bit
+ loads a single byte of data into the EE_DATA
+ register from the EEPROM location specified in
+ the EE_ADDR register.
+ The Wlan hardware hardware clears this bit automatically.
+ EE_DATA is valid when this bit is cleared.
+
+ 0 EE_WRITE - EEPROM Write Request - Setting this bit
+ writes a single byte of data from the EE_DATA register into the
+ EEPROM location specified in the EE_ADDR register.
+ The Wlan hardware hardware clears this bit automatically.
+*===============================================*/
+#define ACX_EE_CTL_REG EE_CTL
+#define EE_WRITE 0x00000001ul
+#define EE_READ 0x00000002ul
+
+/*===============================================
+ EEPROM Address - 32bit RW
+ ------------------------------------------
+ This register specifies the address
+ within the EEPROM from/to which to read/write data.
+ ===============================================*/
+#define ACX_EE_ADDR_REG EE_ADDR
+
+/*===============================================
+ EEPROM Data - 32bit RW
+ ------------------------------------------
+ This register either holds the read 8 bits of
+ data from the EEPROM or the write data
+ to be written to the EEPROM.
+ ===============================================*/
+#define ACX_EE_DATA_REG EE_DATA
+
+/*===============================================
+ EEPROM Base Address - 32bit RW
+ ------------------------------------------
+ This register holds the upper nine bits
+ [23:15] of the 24-bit Wlan hardware memory
+ address for burst reads from EEPROM accesses.
+ The EEPROM provides the lower 15 bits of this address.
+ The MSB of the address from the EEPROM is ignored.
+ ===============================================*/
+#define ACX_EE_CFG EE_CFG
+
+/*===============================================
+ GPIO Output Values -32bit, RW
+ ------------------------------------------
+ [31:16] Reserved
+ [15: 0] Specify the output values (at the output driver inputs) for
+ GPIO[15:0], respectively.
+ ===============================================*/
+#define ACX_GPIO_OUT_REG GPIO_OUT
+#define ACX_MAX_GPIO_LINES 15
+
+/*===============================================
+ Contention window -32bit, RW
+ ------------------------------------------
+ [31:26] Reserved
+ [25:16] Max (0x3ff)
+ [15:07] Reserved
+ [06:00] Current contention window value - default is 0x1F
+ ===============================================*/
+#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG
+#define ACX_CONT_WIND_MIN_MASK 0x0000007f
+#define ACX_CONT_WIND_MAX 0x03ff0000
+
+/*===============================================
+ HI_CFG Interface Configuration Register Values
+ ------------------------------------------
+ ===============================================*/
+#define HI_CFG_UART_ENABLE 0x00000004
+#define HI_CFG_RST232_ENABLE 0x00000008
+#define HI_CFG_CLOCK_REQ_SELECT 0x00000010
+#define HI_CFG_HOST_INT_ENABLE 0x00000020
+#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040
+#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080
+#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100
+#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200
+#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400
+
+/*
+ * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile
+ * for platforms using active high interrupt level
+ */
+#ifdef USE_ACTIVE_HIGH
+#define HI_CFG_DEF_VAL \
+ (HI_CFG_UART_ENABLE | \
+ HI_CFG_RST232_ENABLE | \
+ HI_CFG_CLOCK_REQ_SELECT | \
+ HI_CFG_HOST_INT_ENABLE)
+#else
+#define HI_CFG_DEF_VAL \
+ (HI_CFG_UART_ENABLE | \
+ HI_CFG_RST232_ENABLE | \
+ HI_CFG_CLOCK_REQ_SELECT | \
+ HI_CFG_HOST_INT_ENABLE)
+
+#endif
+
+#define REF_FREQ_19_2 0
+#define REF_FREQ_26_0 1
+#define REF_FREQ_38_4 2
+#define REF_FREQ_40_0 3
+#define REF_FREQ_33_6 4
+#define REF_FREQ_NUM 5
+
+#define LUT_PARAM_INTEGER_DIVIDER 0
+#define LUT_PARAM_FRACTIONAL_DIVIDER 1
+#define LUT_PARAM_ATTN_BB 2
+#define LUT_PARAM_ALPHA_BB 3
+#define LUT_PARAM_STOP_TIME_BB 4
+#define LUT_PARAM_BB_PLL_LOOP_FILTER 5
+#define LUT_PARAM_NUM 6
+
+#define ACX_EEPROMLESS_IND_REG (SCR_PAD4)
+#define USE_EEPROM 0
+#define SOFT_RESET_MAX_TIME 1000000
+#define SOFT_RESET_STALL_TIME 1000
+#define NVS_DATA_BUNDARY_ALIGNMENT 4
+
+
+/* Firmware image load chunk size */
+#define CHUNK_SIZE 512
+
+/* Firmware image header size */
+#define FW_HDR_SIZE 8
+
+#define ECPU_CONTROL_HALT 0x00000101
+
+
+/******************************************************************************
+
+ CHANNELS, BAND & REG DOMAINS definitions
+
+******************************************************************************/
+
+
+enum {
+ RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */
+ RADIO_BAND_5GHZ = 1, /* 5 Ghz band */
+ RADIO_BAND_JAPAN_4_9_GHZ = 2,
+ DEFAULT_BAND = RADIO_BAND_2_4GHZ,
+ INVALID_BAND = 0xFE,
+ MAX_RADIO_BANDS = 0xFF
+};
+
+enum {
+ NO_RATE = 0,
+ RATE_1MBPS = 0x0A,
+ RATE_2MBPS = 0x14,
+ RATE_5_5MBPS = 0x37,
+ RATE_6MBPS = 0x0B,
+ RATE_9MBPS = 0x0F,
+ RATE_11MBPS = 0x6E,
+ RATE_12MBPS = 0x0A,
+ RATE_18MBPS = 0x0E,
+ RATE_22MBPS = 0xDC,
+ RATE_24MBPS = 0x09,
+ RATE_36MBPS = 0x0D,
+ RATE_48MBPS = 0x08,
+ RATE_54MBPS = 0x0C
+};
+
+enum {
+ RATE_INDEX_1MBPS = 0,
+ RATE_INDEX_2MBPS = 1,
+ RATE_INDEX_5_5MBPS = 2,
+ RATE_INDEX_6MBPS = 3,
+ RATE_INDEX_9MBPS = 4,
+ RATE_INDEX_11MBPS = 5,
+ RATE_INDEX_12MBPS = 6,
+ RATE_INDEX_18MBPS = 7,
+ RATE_INDEX_22MBPS = 8,
+ RATE_INDEX_24MBPS = 9,
+ RATE_INDEX_36MBPS = 10,
+ RATE_INDEX_48MBPS = 11,
+ RATE_INDEX_54MBPS = 12,
+ RATE_INDEX_MAX = RATE_INDEX_54MBPS,
+ MAX_RATE_INDEX,
+ INVALID_RATE_INDEX = MAX_RATE_INDEX,
+ RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF
+};
+
+enum {
+ RATE_MASK_1MBPS = 0x1,
+ RATE_MASK_2MBPS = 0x2,
+ RATE_MASK_5_5MBPS = 0x4,
+ RATE_MASK_11MBPS = 0x20,
+};
+
+#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */
+#define OFDM_RATE_BIT BIT(6)
+#define PBCC_RATE_BIT BIT(7)
+
+enum {
+ CCK_LONG = 0,
+ CCK_SHORT = SHORT_PREAMBLE_BIT,
+ PBCC_LONG = PBCC_RATE_BIT,
+ PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT,
+ OFDM = OFDM_RATE_BIT
+};
+
+/******************************************************************************
+
+Transmit-Descriptor RATE-SET field definitions...
+
+Define a new "Rate-Set" for TX path that incorporates the
+Rate & Modulation info into a single 16-bit field.
+
+TxdRateSet_t:
+b15 - Indicates Preamble type (1=SHORT, 0=LONG).
+ Notes:
+ Must be LONG (0) for 1Mbps rate.
+ Does not apply (set to 0) for RevG-OFDM rates.
+b14 - Indicates PBCC encoding (1=PBCC, 0=not).
+ Notes:
+ Does not apply (set to 0) for rates 1 and 2 Mbps.
+ Does not apply (set to 0) for RevG-OFDM rates.
+b13 - Unused (set to 0).
+b12-b0 - Supported Rate indicator bits as defined below.
+
+******************************************************************************/
+
+
+/*************************************************************************
+
+ Interrupt Trigger Register (Host -> WiLink)
+
+**************************************************************************/
+
+/* Hardware to Embedded CPU Interrupts - first 32-bit register set */
+
+/*
+ * Host Command Interrupt. Setting this bit masks
+ * the interrupt that the host issues to inform
+ * the FW that it has sent a command
+ * to the Wlan hardware Command Mailbox.
+ */
+#define INTR_TRIG_CMD BIT(0)
+
+/*
+ * Host Event Acknowlegde Interrupt. The host
+ * sets this bit to acknowledge that it received
+ * the unsolicited information from the event
+ * mailbox.
+ */
+#define INTR_TRIG_EVENT_ACK BIT(1)
+
+/*
+ * The host sets this bit to inform the Wlan
+ * FW that a TX packet is in the XFER
+ * Buffer #0.
+ */
+#define INTR_TRIG_TX_PROC0 BIT(2)
+
+/*
+ * The host sets this bit to inform the FW
+ * that it read a packet from RX XFER
+ * Buffer #0.
+ */
+#define INTR_TRIG_RX_PROC0 BIT(3)
+
+#define INTR_TRIG_DEBUG_ACK BIT(4)
+
+#define INTR_TRIG_STATE_CHANGED BIT(5)
+
+
+/* Hardware to Embedded CPU Interrupts - second 32-bit register set */
+
+/*
+ * The host sets this bit to inform the FW
+ * that it read a packet from RX XFER
+ * Buffer #1.
+ */
+#define INTR_TRIG_RX_PROC1 BIT(17)
+
+/*
+ * The host sets this bit to inform the Wlan
+ * hardware that a TX packet is in the XFER
+ * Buffer #1.
+ */
+#define INTR_TRIG_TX_PROC1 BIT(18)
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c
index 981ea259eb89..17c54b59ef86 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -25,13 +25,15 @@
#include <linux/skbuff.h>
#include <net/mac80211.h>
-#include "wl12xx.h"
-#include "reg.h"
-#include "spi.h"
-#include "rx.h"
+#include "wl1251.h"
+#include "wl1251_reg.h"
+#include "wl1251_io.h"
+#include "wl1251_rx.h"
+#include "wl1251_cmd.h"
+#include "wl1251_acx.h"
-static void wl12xx_rx_header(struct wl12xx *wl,
- struct wl12xx_rx_descriptor *desc)
+static void wl1251_rx_header(struct wl1251 *wl,
+ struct wl1251_rx_descriptor *desc)
{
u32 rx_packet_ring_addr;
@@ -39,15 +41,17 @@ static void wl12xx_rx_header(struct wl12xx *wl,
if (wl->rx_current_buffer)
rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
- wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc,
- sizeof(struct wl12xx_rx_descriptor));
+ wl1251_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc));
}
-static void wl12xx_rx_status(struct wl12xx *wl,
- struct wl12xx_rx_descriptor *desc,
+static void wl1251_rx_status(struct wl1251 *wl,
+ struct wl1251_rx_descriptor *desc,
struct ieee80211_rx_status *status,
u8 beacon)
{
+ u64 mactime;
+ int ret;
+
memset(status, 0, sizeof(struct ieee80211_rx_status));
status->band = IEEE80211_BAND_2GHZ;
@@ -62,32 +66,14 @@ static void wl12xx_rx_status(struct wl12xx *wl,
* this one must be atomic, while our SPI routines can sleep.
*/
if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) {
- u64 mactime;
- int ret;
- struct wl12xx_command cmd;
- struct acx_tsf_info *tsf_info;
-
- memset(&cmd, 0, sizeof(cmd));
-
- ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO,
- sizeof(struct acx_tsf_info),
- &cmd);
- if (ret < 0) {
- wl12xx_warning("ACX_FW_REV interrogate failed");
- return;
- }
-
- tsf_info = (struct acx_tsf_info *)&(cmd.parameters);
-
- mactime = tsf_info->current_tsf_lsb |
- (tsf_info->current_tsf_msb << 31);
-
- status->mactime = mactime;
+ ret = wl1251_acx_tsf_info(wl, &mactime);
+ if (ret == 0)
+ status->mactime = mactime;
}
status->signal = desc->rssi;
- status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 /
- (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI);
+ status->qual = (desc->rssi - WL1251_RX_MIN_RSSI) * 100 /
+ (WL1251_RX_MAX_RSSI - WL1251_RX_MIN_RSSI);
status->qual = min(status->qual, 100);
status->qual = max(status->qual, 0);
@@ -118,8 +104,8 @@ static void wl12xx_rx_status(struct wl12xx *wl,
/* FIXME: set status->rate_idx */
}
-static void wl12xx_rx_body(struct wl12xx *wl,
- struct wl12xx_rx_descriptor *desc)
+static void wl1251_rx_body(struct wl1251 *wl,
+ struct wl1251_rx_descriptor *desc)
{
struct sk_buff *skb;
struct ieee80211_rx_status status;
@@ -127,12 +113,12 @@ static void wl12xx_rx_body(struct wl12xx *wl,
u16 length, *fc;
u32 curr_id, last_id_inc, rx_packet_ring_addr;
- length = WL12XX_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH);
+ length = WL1251_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH);
curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT;
last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1);
if (last_id_inc != curr_id) {
- wl12xx_warning("curr ID:%d, last ID inc:%d",
+ wl1251_warning("curr ID:%d, last ID inc:%d",
curr_id, last_id_inc);
wl->rx_last_id = curr_id;
} else {
@@ -140,18 +126,18 @@ static void wl12xx_rx_body(struct wl12xx *wl,
}
rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr +
- sizeof(struct wl12xx_rx_descriptor) + 20;
+ sizeof(struct wl1251_rx_descriptor) + 20;
if (wl->rx_current_buffer)
rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
skb = dev_alloc_skb(length);
if (!skb) {
- wl12xx_error("Couldn't allocate RX frame");
+ wl1251_error("Couldn't allocate RX frame");
return;
}
rx_buffer = skb_put(skb, length);
- wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
+ wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
/* The actual lenght doesn't include the target's alignment */
skb->len = desc->length - PLCP_HEADER_LENGTH;
@@ -161,15 +147,16 @@ static void wl12xx_rx_body(struct wl12xx *wl,
if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
beacon = 1;
- wl12xx_rx_status(wl, desc, &status, beacon);
+ wl1251_rx_status(wl, desc, &status, beacon);
- wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
+ wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
beacon ? "beacon" : "");
- ieee80211_rx(wl->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx(wl->hw, skb);
}
-static void wl12xx_rx_ack(struct wl12xx *wl)
+static void wl1251_rx_ack(struct wl1251 *wl)
{
u32 data, addr;
@@ -181,28 +168,30 @@ static void wl12xx_rx_ack(struct wl12xx *wl)
data = INTR_TRIG_RX_PROC0;
}
- wl12xx_reg_write32(wl, addr, data);
+ wl1251_reg_write32(wl, addr, data);
/* Toggle buffer ring */
wl->rx_current_buffer = !wl->rx_current_buffer;
}
-void wl12xx_rx(struct wl12xx *wl)
+void wl1251_rx(struct wl1251 *wl)
{
- struct wl12xx_rx_descriptor rx_desc;
+ struct wl1251_rx_descriptor *rx_desc;
- if (wl->state != WL12XX_STATE_ON)
+ if (wl->state != WL1251_STATE_ON)
return;
+ rx_desc = wl->rx_descriptor;
+
/* We first read the frame's header */
- wl12xx_rx_header(wl, &rx_desc);
+ wl1251_rx_header(wl, rx_desc);
/* Now we can read the body */
- wl12xx_rx_body(wl, &rx_desc);
+ wl1251_rx_body(wl, rx_desc);
/* Finally, we need to ACK the RX */
- wl12xx_rx_ack(wl);
+ wl1251_rx_ack(wl);
return;
}
diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h
index 8a23fdea5016..563a3fde40fb 100644
--- a/drivers/net/wireless/wl12xx/rx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,11 +22,13 @@
*
*/
-#ifndef __WL12XX_RX_H__
-#define __WL12XX_RX_H__
+#ifndef __WL1251_RX_H__
+#define __WL1251_RX_H__
#include <linux/bitops.h>
+#include "wl1251.h"
+
/*
* RX PATH
*
@@ -43,12 +45,12 @@
* 4) The target prepares the next RX packet.
*/
-#define WL12XX_RX_MAX_RSSI -30
-#define WL12XX_RX_MIN_RSSI -95
+#define WL1251_RX_MAX_RSSI -30
+#define WL1251_RX_MIN_RSSI -95
-#define WL12XX_RX_ALIGN_TO 4
-#define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \
- ~(WL12XX_RX_ALIGN_TO - 1))
+#define WL1251_RX_ALIGN_TO 4
+#define WL1251_RX_ALIGN(len) (((len) + WL1251_RX_ALIGN_TO - 1) & \
+ ~(WL1251_RX_ALIGN_TO - 1))
#define SHORT_PREAMBLE_BIT BIT(0)
#define OFDM_RATE_BIT BIT(6)
@@ -72,7 +74,7 @@
#define RX_DESC_MIC_FAIL 0x2000
#define RX_DESC_DECRYPT_FAIL 0x4000
-struct wl12xx_rx_descriptor {
+struct wl1251_rx_descriptor {
u32 timestamp; /* In microseconds */
u16 length; /* Paylod length, including headers */
u16 flags;
@@ -86,7 +88,7 @@ struct wl12xx_rx_descriptor {
u8 type;
/*
- * Recevied Rate:
+ * Received Rate:
* 0x0A - 1MBPS
* 0x14 - 2MBPS
* 0x37 - 5_5MBPS
@@ -117,6 +119,6 @@ struct wl12xx_rx_descriptor {
u8 snr; /* in dB */
} __attribute__ ((packed));
-void wl12xx_rx(struct wl12xx *wl);
+void wl1251_rx(struct wl1251 *wl);
#endif
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 @@
+/*
+ * wl12xx SDIO routines
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Copyright (C) 2005 Texas Instruments Incorporated
+ * Copyright (C) 2008 Google Inc
+ * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com)
+ */
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/mod_devicetable.h>
+#include <linux/irq.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/platform_device.h>
+
+#include "wl1251.h"
+#include "wl12xx_80211.h"
+#include "wl1251_reg.h"
+#include "wl1251_ps.h"
+#include "wl1251_io.h"
+#include "wl1251_tx.h"
+#include "wl1251_debugfs.h"
+
+#ifndef SDIO_VENDOR_ID_TI
+#define SDIO_VENDOR_ID_TI 0x104c
+#endif
+
+#ifndef SDIO_DEVICE_ID_TI_WL1251
+#define SDIO_DEVICE_ID_TI_WL1251 0x9066
+#endif
+
+static struct sdio_func *wl_to_func(struct wl1251 *wl)
+{
+ return wl->if_priv;
+}
+
+static void wl1251_sdio_interrupt(struct sdio_func *func)
+{
+ struct wl1251 *wl = sdio_get_drvdata(func);
+
+ wl1251_debug(DEBUG_IRQ, "IRQ");
+
+ /* FIXME should be synchronous for sdio */
+ ieee80211_queue_work(wl->hw, &wl->irq_work);
+}
+
+static const struct sdio_device_id wl1251_devices[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1251) },
+ {}
+};
+MODULE_DEVICE_TABLE(sdio, wl1251_devices);
+
+
+void wl1251_sdio_read(struct wl1251 *wl, int addr, void *buf, size_t len)
+{
+ int ret;
+ struct sdio_func *func = wl_to_func(wl);
+
+ sdio_claim_host(func);
+ ret = sdio_memcpy_fromio(func, buf, addr, len);
+ if (ret)
+ wl1251_error("sdio read failed (%d)", ret);
+ sdio_release_host(func);
+}
+
+void wl1251_sdio_write(struct wl1251 *wl, int addr, void *buf, size_t len)
+{
+ int ret;
+ struct sdio_func *func = wl_to_func(wl);
+
+ sdio_claim_host(func);
+ ret = sdio_memcpy_toio(func, addr, buf, len);
+ if (ret)
+ wl1251_error("sdio write failed (%d)", ret);
+ sdio_release_host(func);
+}
+
+void wl1251_sdio_reset(struct wl1251 *wl)
+{
+}
+
+static void wl1251_sdio_enable_irq(struct wl1251 *wl)
+{
+ struct sdio_func *func = wl_to_func(wl);
+
+ sdio_claim_host(func);
+ sdio_claim_irq(func, wl1251_sdio_interrupt);
+ sdio_release_host(func);
+}
+
+static void wl1251_sdio_disable_irq(struct wl1251 *wl)
+{
+ struct sdio_func *func = wl_to_func(wl);
+
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_release_host(func);
+}
+
+void wl1251_sdio_set_power(bool enable)
+{
+}
+
+struct wl1251_if_operations wl1251_sdio_ops = {
+ .read = wl1251_sdio_read,
+ .write = wl1251_sdio_write,
+ .reset = wl1251_sdio_reset,
+ .enable_irq = wl1251_sdio_enable_irq,
+ .disable_irq = wl1251_sdio_disable_irq,
+};
+
+int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+ int ret;
+ struct wl1251 *wl;
+ struct ieee80211_hw *hw;
+
+ hw = wl1251_alloc_hw();
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ wl = hw->priv;
+
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ if (ret)
+ goto release;
+
+ sdio_set_block_size(func, 512);
+
+ SET_IEEE80211_DEV(hw, &func->dev);
+ wl->if_priv = func;
+ wl->if_ops = &wl1251_sdio_ops;
+ wl->set_power = wl1251_sdio_set_power;
+
+ sdio_release_host(func);
+ ret = wl1251_init_ieee80211(wl);
+ if (ret)
+ goto disable;
+
+ sdio_set_drvdata(func, wl);
+ return ret;
+
+disable:
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+release:
+ sdio_release_host(func);
+ return ret;
+}
+
+static void __devexit wl1251_sdio_remove(struct sdio_func *func)
+{
+ struct wl1251 *wl = sdio_get_drvdata(func);
+
+ wl1251_free_hw(wl);
+
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+}
+
+static struct sdio_driver wl1251_sdio_driver = {
+ .name = "wl1251_sdio",
+ .id_table = wl1251_devices,
+ .probe = wl1251_sdio_probe,
+ .remove = __devexit_p(wl1251_sdio_remove),
+};
+
+static int __init wl1251_sdio_init(void)
+{
+ int err;
+
+ err = sdio_register_driver(&wl1251_sdio_driver);
+ if (err)
+ wl1251_error("failed to register sdio driver: %d", err);
+ return err;
+}
+
+static void __exit wl1251_sdio_exit(void)
+{
+ sdio_unregister_driver(&wl1251_sdio_driver);
+ wl1251_notice("unloaded");
+}
+
+module_init(wl1251_sdio_init);
+module_exit(wl1251_sdio_exit);
+
+MODULE_LICENSE("GPL");
+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
new file mode 100644
index 000000000000..14eff2b3d4c6
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.c
@@ -0,0 +1,344 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/wl12xx.h>
+
+#include "wl1251.h"
+#include "wl1251_reg.h"
+#include "wl1251_spi.h"
+
+static irqreturn_t wl1251_irq(int irq, void *cookie)
+{
+ struct wl1251 *wl;
+
+ wl1251_debug(DEBUG_IRQ, "IRQ");
+
+ wl = cookie;
+
+ ieee80211_queue_work(wl->hw, &wl->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static struct spi_device *wl_to_spi(struct wl1251 *wl)
+{
+ return wl->if_priv;
+}
+
+static void wl1251_spi_reset(struct wl1251 *wl)
+{
+ u8 *cmd;
+ struct spi_transfer t;
+ struct spi_message m;
+
+ cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
+ if (!cmd) {
+ wl1251_error("could not allocate cmd for spi reset");
+ return;
+ }
+
+ memset(&t, 0, sizeof(t));
+ spi_message_init(&m);
+
+ memset(cmd, 0xff, WSPI_INIT_CMD_LEN);
+
+ t.tx_buf = cmd;
+ t.len = WSPI_INIT_CMD_LEN;
+ spi_message_add_tail(&t, &m);
+
+ spi_sync(wl_to_spi(wl), &m);
+
+ wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
+}
+
+static void wl1251_spi_wake(struct wl1251 *wl)
+{
+ u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
+ struct spi_transfer t;
+ struct spi_message m;
+
+ cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
+ if (!cmd) {
+ wl1251_error("could not allocate cmd for spi init");
+ return;
+ }
+
+ memset(crc, 0, sizeof(crc));
+ memset(&t, 0, sizeof(t));
+ spi_message_init(&m);
+
+ /*
+ * Set WSPI_INIT_COMMAND
+ * the data is being send from the MSB to LSB
+ */
+ cmd[2] = 0xff;
+ cmd[3] = 0xff;
+ cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX;
+ cmd[0] = 0;
+ cmd[7] = 0;
+ cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3;
+ cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN;
+
+ if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0)
+ cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY;
+ else
+ cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY;
+
+ cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS
+ | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS;
+
+ crc[0] = cmd[1];
+ crc[1] = cmd[0];
+ crc[2] = cmd[7];
+ crc[3] = cmd[6];
+ crc[4] = cmd[5];
+
+ cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1;
+ cmd[4] |= WSPI_INIT_CMD_END;
+
+ t.tx_buf = cmd;
+ t.len = WSPI_INIT_CMD_LEN;
+ spi_message_add_tail(&t, &m);
+
+ spi_sync(wl_to_spi(wl), &m);
+
+ wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
+}
+
+static void wl1251_spi_reset_wake(struct wl1251 *wl)
+{
+ wl1251_spi_reset(wl);
+ wl1251_spi_wake(wl);
+}
+
+static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf,
+ size_t len)
+{
+ struct spi_transfer t[3];
+ struct spi_message m;
+ u8 *busy_buf;
+ u32 *cmd;
+
+ cmd = &wl->buffer_cmd;
+ busy_buf = wl->buffer_busyword;
+
+ *cmd = 0;
+ *cmd |= WSPI_CMD_READ;
+ *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
+ *cmd |= addr & WSPI_CMD_BYTE_ADDR;
+
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+
+ t[0].tx_buf = cmd;
+ t[0].len = 4;
+ spi_message_add_tail(&t[0], &m);
+
+ /* Busy and non busy words read */
+ t[1].rx_buf = busy_buf;
+ t[1].len = WL1251_BUSY_WORD_LEN;
+ spi_message_add_tail(&t[1], &m);
+
+ t[2].rx_buf = buf;
+ t[2].len = len;
+ spi_message_add_tail(&t[2], &m);
+
+ spi_sync(wl_to_spi(wl), &m);
+
+ /* FIXME: check busy words */
+
+ wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
+ wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
+}
+
+static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf,
+ size_t len)
+{
+ struct spi_transfer t[2];
+ struct spi_message m;
+ u32 *cmd;
+
+ cmd = &wl->buffer_cmd;
+
+ *cmd = 0;
+ *cmd |= WSPI_CMD_WRITE;
+ *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
+ *cmd |= addr & WSPI_CMD_BYTE_ADDR;
+
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+
+ t[0].tx_buf = cmd;
+ t[0].len = sizeof(*cmd);
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].tx_buf = buf;
+ t[1].len = len;
+ spi_message_add_tail(&t[1], &m);
+
+ spi_sync(wl_to_spi(wl), &m);
+
+ wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
+ wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
+}
+
+static void wl1251_spi_enable_irq(struct wl1251 *wl)
+{
+ return enable_irq(wl->irq);
+}
+
+static void wl1251_spi_disable_irq(struct wl1251 *wl)
+{
+ return disable_irq(wl->irq);
+}
+
+static const struct wl1251_if_operations wl1251_spi_ops = {
+ .read = wl1251_spi_read,
+ .write = wl1251_spi_write,
+ .reset = wl1251_spi_reset_wake,
+ .enable_irq = wl1251_spi_enable_irq,
+ .disable_irq = wl1251_spi_disable_irq,
+};
+
+static int __devinit wl1251_spi_probe(struct spi_device *spi)
+{
+ struct wl12xx_platform_data *pdata;
+ struct ieee80211_hw *hw;
+ struct wl1251 *wl;
+ int ret;
+
+ pdata = spi->dev.platform_data;
+ if (!pdata) {
+ wl1251_error("no platform data");
+ return -ENODEV;
+ }
+
+ hw = wl1251_alloc_hw();
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ wl = hw->priv;
+
+ SET_IEEE80211_DEV(hw, &spi->dev);
+ dev_set_drvdata(&spi->dev, wl);
+ wl->if_priv = spi;
+ wl->if_ops = &wl1251_spi_ops;
+
+ /* This is the only SPI value that we need to set here, the rest
+ * comes from the board-peripherals file */
+ spi->bits_per_word = 32;
+
+ ret = spi_setup(spi);
+ if (ret < 0) {
+ wl1251_error("spi_setup failed");
+ goto out_free;
+ }
+
+ wl->set_power = pdata->set_power;
+ if (!wl->set_power) {
+ wl1251_error("set power function missing in platform data");
+ return -ENODEV;
+ }
+
+ wl->irq = spi->irq;
+ if (wl->irq < 0) {
+ wl1251_error("irq missing in platform data");
+ return -ENODEV;
+ }
+
+ ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
+ if (ret < 0) {
+ wl1251_error("request_irq() failed: %d", ret);
+ goto out_free;
+ }
+
+ set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
+
+ disable_irq(wl->irq);
+
+ ret = wl1251_init_ieee80211(wl);
+ if (ret)
+ goto out_irq;
+
+ return 0;
+
+ out_irq:
+ free_irq(wl->irq, wl);
+
+ out_free:
+ ieee80211_free_hw(hw);
+
+ return ret;
+}
+
+static int __devexit wl1251_spi_remove(struct spi_device *spi)
+{
+ struct wl1251 *wl = dev_get_drvdata(&spi->dev);
+
+ free_irq(wl->irq, wl);
+ wl1251_free_hw(wl);
+
+ return 0;
+}
+
+static struct spi_driver wl1251_spi_driver = {
+ .driver = {
+ .name = "wl12xx",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+
+ .probe = wl1251_spi_probe,
+ .remove = __devexit_p(wl1251_spi_remove),
+};
+
+static int __init wl1251_spi_init(void)
+{
+ int ret;
+
+ ret = spi_register_driver(&wl1251_spi_driver);
+ if (ret < 0) {
+ wl1251_error("failed to register spi driver: %d", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static void __exit wl1251_spi_exit(void)
+{
+ spi_unregister_driver(&wl1251_spi_driver);
+
+ wl1251_notice("unloaded");
+}
+
+module_init(wl1251_spi_init);
+module_exit(wl1251_spi_exit);
+
+MODULE_LICENSE("GPL");
+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
new file mode 100644
index 000000000000..2e273a97e7f3
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.h
@@ -0,0 +1,61 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (c) 1998-2007 Texas Instruments Incorporated
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1251_SPI_H__
+#define __WL1251_SPI_H__
+
+#include "wl1251_cmd.h"
+#include "wl1251_acx.h"
+#include "wl1251_reg.h"
+
+#define WSPI_CMD_READ 0x40000000
+#define WSPI_CMD_WRITE 0x00000000
+#define WSPI_CMD_FIXED 0x20000000
+#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000
+#define WSPI_CMD_BYTE_LENGTH_OFFSET 17
+#define WSPI_CMD_BYTE_ADDR 0x0001FFFF
+
+#define WSPI_INIT_CMD_CRC_LEN 5
+
+#define WSPI_INIT_CMD_START 0x00
+#define WSPI_INIT_CMD_TX 0x40
+/* the extra bypass bit is sampled by the TNET as '1' */
+#define WSPI_INIT_CMD_BYPASS_BIT 0x80
+#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07
+#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80
+#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00
+#define WSPI_INIT_CMD_IOD 0x40
+#define WSPI_INIT_CMD_IP 0x20
+#define WSPI_INIT_CMD_CS 0x10
+#define WSPI_INIT_CMD_WS 0x08
+#define WSPI_INIT_CMD_WSPI 0x01
+#define WSPI_INIT_CMD_END 0x01
+
+#define WSPI_INIT_CMD_LEN 8
+
+#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \
+ ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32))
+#define HW_ACCESS_WSPI_INIT_CMD_MASK 0
+
+#endif /* __WL1251_SPI_H__ */
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c
index 62145e205a8c..f85970615849 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -25,13 +25,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "wl12xx.h"
-#include "reg.h"
-#include "spi.h"
-#include "tx.h"
-#include "ps.h"
+#include "wl1251.h"
+#include "wl1251_reg.h"
+#include "wl1251_tx.h"
+#include "wl1251_ps.h"
+#include "wl1251_io.h"
-static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count)
+static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count)
{
int used, data_in_count;
@@ -52,15 +52,15 @@ static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count)
return false;
}
-static int wl12xx_tx_path_status(struct wl12xx *wl)
+static int wl1251_tx_path_status(struct wl1251 *wl)
{
u32 status, addr, data_out_count;
bool busy;
addr = wl->data_path->tx_control_addr;
- status = wl12xx_mem_read32(wl, addr);
+ status = wl1251_mem_read32(wl, addr);
data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK;
- busy = wl12xx_tx_double_buffer_busy(wl, data_out_count);
+ busy = wl1251_tx_double_buffer_busy(wl, data_out_count);
if (busy)
return -EBUSY;
@@ -68,7 +68,7 @@ static int wl12xx_tx_path_status(struct wl12xx *wl)
return 0;
}
-static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb)
+static int wl1251_tx_id(struct wl1251 *wl, struct sk_buff *skb)
{
int i;
@@ -81,7 +81,7 @@ static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb)
return -EBUSY;
}
-static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr,
+static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr,
struct ieee80211_tx_info *control, u16 fc)
{
*(u16 *)&tx_hdr->control = 0;
@@ -109,7 +109,7 @@ static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr,
#define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \
WLAN_QOS_HDR_LEN)
#define HW_BLOCK_SIZE 252
-static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
+static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
{
u16 payload_len, frag_threshold, mem_blocks;
u16 num_mpdus, mem_blocks_per_frag;
@@ -142,7 +142,7 @@ static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
tx_hdr->num_mem_blocks = mem_blocks;
}
-static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
+static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb,
struct ieee80211_tx_info *control)
{
struct tx_double_buffer_desc *tx_hdr;
@@ -153,7 +153,7 @@ static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
if (!skb)
return -EINVAL;
- id = wl12xx_tx_id(wl, skb);
+ id = wl1251_tx_id(wl, skb);
if (id < 0)
return id;
@@ -170,14 +170,14 @@ static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
/* FIXME: how to get the correct queue id? */
tx_hdr->xmit_queue = 0;
- wl12xx_tx_control(tx_hdr, control, fc);
- wl12xx_tx_frag_block_num(tx_hdr);
+ wl1251_tx_control(tx_hdr, control, fc);
+ wl1251_tx_frag_block_num(tx_hdr);
return 0;
}
/* We copy the packet to the target */
-static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
+static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
struct ieee80211_tx_info *control)
{
struct tx_double_buffer_desc *tx_hdr;
@@ -196,12 +196,12 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
u8 *pos;
fc = *(u16 *)(skb->data + sizeof(*tx_hdr));
- tx_hdr->length += WL12XX_TKIP_IV_SPACE;
+ tx_hdr->length += WL1251_TKIP_IV_SPACE;
hdrlen = ieee80211_hdrlen(fc);
- pos = skb_push(skb, WL12XX_TKIP_IV_SPACE);
- memmove(pos, pos + WL12XX_TKIP_IV_SPACE,
+ pos = skb_push(skb, WL1251_TKIP_IV_SPACE);
+ memmove(pos, pos + WL1251_TKIP_IV_SPACE,
sizeof(*tx_hdr) + hdrlen);
}
@@ -211,7 +211,7 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
*/
if (unlikely((long)skb->data & 0x03)) {
int offset = (4 - (long)skb->data) & 0x03;
- wl12xx_debug(DEBUG_TX, "skb offset %d", offset);
+ wl1251_debug(DEBUG_TX, "skb offset %d", offset);
/* check whether the current skb can be used */
if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {
@@ -221,13 +221,13 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
skb_reserve(skb, offset);
memmove(skb->data, src, skb->len);
} else {
- wl12xx_info("No handler, fixme!");
+ wl1251_info("No handler, fixme!");
return -EINVAL;
}
}
/* Our skb->data at this point includes the HW header */
- len = WL12XX_TX_ALIGN(skb->len);
+ len = WL1251_TX_ALIGN(skb->len);
if (wl->data_in_count & 0x1)
addr = wl->data_path->tx_packet_ring_addr +
@@ -235,15 +235,15 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
else
addr = wl->data_path->tx_packet_ring_addr;
- wl12xx_spi_mem_write(wl, addr, skb->data, len);
+ wl1251_mem_write(wl, addr, skb->data, len);
- wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
+ wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate);
return 0;
}
-static void wl12xx_tx_trigger(struct wl12xx *wl)
+static void wl1251_tx_trigger(struct wl1251 *wl)
{
u32 data, addr;
@@ -255,7 +255,7 @@ static void wl12xx_tx_trigger(struct wl12xx *wl)
data = INTR_TRIG_TX_PROC0;
}
- wl12xx_reg_write32(wl, addr, data);
+ wl1251_reg_write32(wl, addr, data);
/* Bumping data in */
wl->data_in_count = (wl->data_in_count + 1) &
@@ -263,7 +263,7 @@ static void wl12xx_tx_trigger(struct wl12xx *wl)
}
/* caller must hold wl->mutex */
-static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb)
+static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
{
struct ieee80211_tx_info *info;
int ret = 0;
@@ -274,51 +274,53 @@ static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb)
if (info->control.hw_key) {
idx = info->control.hw_key->hw_key_idx;
if (unlikely(wl->default_key != idx)) {
- ret = wl12xx_acx_default_key(wl, idx);
+ ret = wl1251_acx_default_key(wl, idx);
if (ret < 0)
return ret;
}
}
- ret = wl12xx_tx_path_status(wl);
+ ret = wl1251_tx_path_status(wl);
if (ret < 0)
return ret;
- ret = wl12xx_tx_fill_hdr(wl, skb, info);
+ ret = wl1251_tx_fill_hdr(wl, skb, info);
if (ret < 0)
return ret;
- ret = wl12xx_tx_send_packet(wl, skb, info);
+ ret = wl1251_tx_send_packet(wl, skb, info);
if (ret < 0)
return ret;
- wl12xx_tx_trigger(wl);
+ wl1251_tx_trigger(wl);
return ret;
}
-void wl12xx_tx_work(struct work_struct *work)
+void wl1251_tx_work(struct work_struct *work)
{
- struct wl12xx *wl = container_of(work, struct wl12xx, tx_work);
+ struct wl1251 *wl = container_of(work, struct wl1251, tx_work);
struct sk_buff *skb;
bool woken_up = false;
int ret;
mutex_lock(&wl->mutex);
- if (unlikely(wl->state == WL12XX_STATE_OFF))
+ if (unlikely(wl->state == WL1251_STATE_OFF))
goto out;
while ((skb = skb_dequeue(&wl->tx_queue))) {
if (!woken_up) {
- wl12xx_ps_elp_wakeup(wl);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
woken_up = true;
}
- ret = wl12xx_tx_frame(wl, skb);
+ ret = wl1251_tx_frame(wl, skb);
if (ret == -EBUSY) {
/* firmware buffer is full, stop queues */
- wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, "
+ wl1251_debug(DEBUG_TX, "tx_work: fw buffer full, "
"stop queues");
ieee80211_stop_queues(wl->hw);
wl->tx_queue_stopped = true;
@@ -332,12 +334,12 @@ void wl12xx_tx_work(struct work_struct *work)
out:
if (woken_up)
- wl12xx_ps_elp_sleep(wl);
+ wl1251_ps_elp_sleep(wl);
mutex_unlock(&wl->mutex);
}
-static const char *wl12xx_tx_parse_status(u8 status)
+static const char *wl1251_tx_parse_status(u8 status)
{
/* 8 bit status field, one character per bit plus null */
static char buf[9];
@@ -365,7 +367,7 @@ static const char *wl12xx_tx_parse_status(u8 status)
return buf;
}
-static void wl12xx_tx_packet_cb(struct wl12xx *wl,
+static void wl1251_tx_packet_cb(struct wl1251 *wl,
struct tx_result *result)
{
struct ieee80211_tx_info *info;
@@ -375,7 +377,7 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
skb = wl->tx_frames[result->id];
if (skb == NULL) {
- wl12xx_error("SKB for packet %d is NULL", result->id);
+ wl1251_error("SKB for packet %d is NULL", result->id);
return;
}
@@ -396,14 +398,14 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
if (info->control.hw_key &&
info->control.hw_key->alg == ALG_TKIP) {
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- memmove(frame + WL12XX_TKIP_IV_SPACE, frame, hdrlen);
- skb_pull(skb, WL12XX_TKIP_IV_SPACE);
+ memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen);
+ skb_pull(skb, WL1251_TKIP_IV_SPACE);
}
- wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
+ wl1251_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
" status 0x%x (%s)",
result->id, skb, result->ack_failures, result->rate,
- result->status, wl12xx_tx_parse_status(result->status));
+ result->status, wl1251_tx_parse_status(result->status));
ieee80211_tx_status(wl->hw, skb);
@@ -411,7 +413,7 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
wl->tx_frames[result->id] = NULL;
if (wl->tx_queue_stopped) {
- wl12xx_debug(DEBUG_TX, "cb: queue was stopped");
+ wl1251_debug(DEBUG_TX, "cb: queue was stopped");
skb = skb_dequeue(&wl->tx_queue);
@@ -420,10 +422,10 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
queue empty */
if (skb) {
- ret = wl12xx_tx_frame(wl, skb);
+ ret = wl1251_tx_frame(wl, skb);
if (ret == -EBUSY) {
/* firmware buffer is still full */
- wl12xx_debug(DEBUG_TX, "cb: fw buffer "
+ wl1251_debug(DEBUG_TX, "cb: fw buffer "
"still full");
skb_queue_head(&wl->tx_queue, skb);
return;
@@ -433,23 +435,23 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
}
}
- wl12xx_debug(DEBUG_TX, "cb: waking queues");
+ wl1251_debug(DEBUG_TX, "cb: waking queues");
ieee80211_wake_queues(wl->hw);
wl->tx_queue_stopped = false;
}
}
/* Called upon reception of a TX complete interrupt */
-void wl12xx_tx_complete(struct wl12xx *wl)
+void wl1251_tx_complete(struct wl1251 *wl)
{
int i, result_index, num_complete = 0;
struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr;
- if (unlikely(wl->state != WL12XX_STATE_ON))
+ if (unlikely(wl->state != WL1251_STATE_ON))
return;
/* First we read the result */
- wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr,
+ wl1251_mem_read(wl, wl->data_path->tx_complete_addr,
result, sizeof(result));
result_index = wl->next_tx_complete;
@@ -459,7 +461,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
if (result_ptr->done_1 == 1 &&
result_ptr->done_2 == 1) {
- wl12xx_tx_packet_cb(wl, result_ptr);
+ wl1251_tx_packet_cb(wl, result_ptr);
result_ptr->done_1 = 0;
result_ptr->done_2 = 0;
@@ -480,41 +482,41 @@ void wl12xx_tx_complete(struct wl12xx *wl)
*/
if (result_index > wl->next_tx_complete) {
/* Only 1 write is needed */
- wl12xx_spi_mem_write(wl,
- wl->data_path->tx_complete_addr +
- (wl->next_tx_complete *
- sizeof(struct tx_result)),
- &result[wl->next_tx_complete],
- num_complete *
- sizeof(struct tx_result));
+ wl1251_mem_write(wl,
+ wl->data_path->tx_complete_addr +
+ (wl->next_tx_complete *
+ sizeof(struct tx_result)),
+ &result[wl->next_tx_complete],
+ num_complete *
+ sizeof(struct tx_result));
} else if (result_index < wl->next_tx_complete) {
/* 2 writes are needed */
- wl12xx_spi_mem_write(wl,
- wl->data_path->tx_complete_addr +
- (wl->next_tx_complete *
- sizeof(struct tx_result)),
- &result[wl->next_tx_complete],
- (FW_TX_CMPLT_BLOCK_SIZE -
- wl->next_tx_complete) *
- sizeof(struct tx_result));
-
- wl12xx_spi_mem_write(wl,
- wl->data_path->tx_complete_addr,
- result,
- (num_complete -
- FW_TX_CMPLT_BLOCK_SIZE +
- wl->next_tx_complete) *
- sizeof(struct tx_result));
+ wl1251_mem_write(wl,
+ wl->data_path->tx_complete_addr +
+ (wl->next_tx_complete *
+ sizeof(struct tx_result)),
+ &result[wl->next_tx_complete],
+ (FW_TX_CMPLT_BLOCK_SIZE -
+ wl->next_tx_complete) *
+ sizeof(struct tx_result));
+
+ wl1251_mem_write(wl,
+ wl->data_path->tx_complete_addr,
+ result,
+ (num_complete -
+ FW_TX_CMPLT_BLOCK_SIZE +
+ wl->next_tx_complete) *
+ sizeof(struct tx_result));
} else {
/* We have to write the whole array */
- wl12xx_spi_mem_write(wl,
- wl->data_path->tx_complete_addr,
- result,
- FW_TX_CMPLT_BLOCK_SIZE *
- sizeof(struct tx_result));
+ wl1251_mem_write(wl,
+ wl->data_path->tx_complete_addr,
+ result,
+ FW_TX_CMPLT_BLOCK_SIZE *
+ sizeof(struct tx_result));
}
}
@@ -523,7 +525,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
}
/* caller must hold wl->mutex */
-void wl12xx_tx_flush(struct wl12xx *wl)
+void wl1251_tx_flush(struct wl1251 *wl)
{
int i;
struct sk_buff *skb;
@@ -535,7 +537,7 @@ void wl12xx_tx_flush(struct wl12xx *wl)
while ((skb = skb_dequeue(&wl->tx_queue))) {
info = IEEE80211_SKB_CB(skb);
- wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb);
+ wl1251_debug(DEBUG_TX, "flushing skb 0x%p", skb);
if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS))
continue;
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h
index dc82691f4c14..7c1c1665c810 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,8 +22,8 @@
*
*/
-#ifndef __WL12XX_TX_H__
-#define __WL12XX_TX_H__
+#ifndef __WL1251_TX_H__
+#define __WL1251_TX_H__
#include <linux/bitops.h>
@@ -73,10 +73,11 @@
#define TX_COMPLETE_REQUIRED_BIT 0x80
#define TX_STATUS_DATA_OUT_COUNT_MASK 0xf
-#define WL12XX_TX_ALIGN_TO 4
-#define WL12XX_TX_ALIGN(len) (((len) + WL12XX_TX_ALIGN_TO - 1) & \
- ~(WL12XX_TX_ALIGN_TO - 1))
-#define WL12XX_TKIP_IV_SPACE 4
+
+#define WL1251_TX_ALIGN_TO 4
+#define WL1251_TX_ALIGN(len) (((len) + WL1251_TX_ALIGN_TO - 1) & \
+ ~(WL1251_TX_ALIGN_TO - 1))
+#define WL1251_TKIP_IV_SPACE 4
struct tx_control {
/* Rate Policy (class) index */
@@ -208,8 +209,8 @@ struct tx_result {
u8 done_2;
} __attribute__ ((packed));
-void wl12xx_tx_work(struct work_struct *work);
-void wl12xx_tx_complete(struct wl12xx *wl);
-void wl12xx_tx_flush(struct wl12xx *wl);
+void wl1251_tx_work(struct work_struct *work);
+void wl1251_tx_complete(struct wl1251 *wl);
+void wl1251_tx_flush(struct wl1251 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl1271.h
index 48641437414b..55818f94017b 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -1,10 +1,10 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1271
*
- * Copyright (c) 1998-2007 Texas Instruments Incorporated
+ * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
* Copyright (C) 2008-2009 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -22,15 +22,17 @@
*
*/
-#ifndef __WL12XX_H__
-#define __WL12XX_H__
+#ifndef __WL1271_H__
+#define __WL1271_H__
#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/bitops.h>
#include <net/mac80211.h>
-#define DRIVER_NAME "wl12xx"
+#define DRIVER_NAME "wl1271"
#define DRIVER_PREFIX DRIVER_NAME ": "
enum {
@@ -56,25 +58,25 @@ enum {
#define DEBUG_DUMP_LIMIT 1024
-#define wl12xx_error(fmt, arg...) \
+#define wl1271_error(fmt, arg...) \
printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
-#define wl12xx_warning(fmt, arg...) \
+#define wl1271_warning(fmt, arg...) \
printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
-#define wl12xx_notice(fmt, arg...) \
+#define wl1271_notice(fmt, arg...) \
printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg)
-#define wl12xx_info(fmt, arg...) \
+#define wl1271_info(fmt, arg...) \
printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg)
-#define wl12xx_debug(level, fmt, arg...) \
+#define wl1271_debug(level, fmt, arg...) \
do { \
if (level & DEBUG_LEVEL) \
printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \
} while (0)
-#define wl12xx_dump(level, prefix, buf, len) \
+#define wl1271_dump(level, prefix, buf, len) \
do { \
if (level & DEBUG_LEVEL) \
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
@@ -84,7 +86,7 @@ enum {
0); \
} while (0)
-#define wl12xx_dump_ascii(level, prefix, buf, len) \
+#define wl1271_dump_ascii(level, prefix, buf, len) \
do { \
if (level & DEBUG_LEVEL) \
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
@@ -94,35 +96,29 @@ enum {
true); \
} while (0)
-#define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
+#define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
CFG_BSSID_FILTER_EN)
-#define WL12XX_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \
- CFG_RX_MGMT_EN | \
- CFG_RX_DATA_EN | \
- CFG_RX_CTL_EN | \
- CFG_RX_BCN_EN | \
- CFG_RX_AUTH_EN | \
- CFG_RX_ASSOC_EN)
-
-
-struct boot_attr {
- u32 radio_type;
- u8 mac_clock;
- u8 arm_clock;
- int firmware_debug;
- u32 minor;
- u32 major;
- u32 bugfix;
-};
+#define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \
+ CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
+ CFG_RX_CTL_EN | CFG_RX_BCN_EN | \
+ CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
+
+#define WL1271_FW_NAME "wl1271-fw.bin"
+#define WL1271_NVS_NAME "wl1271-nvs.bin"
+
+#define WL1271_BUSY_WORD_LEN 8
-enum wl12xx_state {
- WL12XX_STATE_OFF,
- WL12XX_STATE_ON,
- WL12XX_STATE_PLT,
+#define WL1271_ELP_HW_STATE_ASLEEP 0
+#define WL1271_ELP_HW_STATE_IRQ 1
+
+enum wl1271_state {
+ WL1271_STATE_OFF,
+ WL1271_STATE_ON,
+ WL1271_STATE_PLT,
};
-enum wl12xx_partition_type {
+enum wl1271_partition_type {
PART_DOWN,
PART_WORK,
PART_DRPW,
@@ -130,44 +126,25 @@ enum wl12xx_partition_type {
PART_TABLE_LEN
};
-struct wl12xx_partition {
+struct wl1271_partition {
u32 size;
u32 start;
};
-struct wl12xx_partition_set {
- struct wl12xx_partition mem;
- struct wl12xx_partition reg;
+struct wl1271_partition_set {
+ struct wl1271_partition mem;
+ struct wl1271_partition reg;
};
-struct wl12xx;
+struct wl1271;
/* FIXME: I'm not sure about this structure name */
-struct wl12xx_chip {
+struct wl1271_chip {
u32 id;
-
- const char *fw_filename;
- const char *nvs_filename;
-
char fw_ver[21];
-
- unsigned int power_on_sleep;
- int intr_cmd_complete;
- int intr_init_complete;
-
- int (*op_upload_fw)(struct wl12xx *wl);
- int (*op_upload_nvs)(struct wl12xx *wl);
- int (*op_boot)(struct wl12xx *wl);
- void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag);
- void (*op_target_enable_interrupts)(struct wl12xx *wl);
- int (*op_hw_init)(struct wl12xx *wl);
- int (*op_plt_init)(struct wl12xx *wl);
-
- struct wl12xx_partition_set *p_table;
- enum wl12xx_acx_int_reg *acx_reg_table;
};
-struct wl12xx_stats {
+struct wl1271_stats {
struct acx_statistics *fw_stats;
unsigned long fw_stats_update;
@@ -175,7 +152,7 @@ struct wl12xx_stats {
unsigned int excessive_retries;
};
-struct wl12xx_debugfs {
+struct wl1271_debugfs {
struct dentry *rootdir;
struct dentry *fw_statistics;
@@ -276,7 +253,28 @@ struct wl12xx_debugfs {
struct dentry *excessive_retries;
};
-struct wl12xx {
+#define NUM_TX_QUEUES 4
+#define NUM_RX_PKT_DESC 8
+
+/* FW status registers */
+struct wl1271_fw_status {
+ u32 intr;
+ u8 fw_rx_counter;
+ u8 drv_rx_counter;
+ u8 reserved;
+ u8 tx_results_counter;
+ u32 rx_pkt_descs[NUM_RX_PKT_DESC];
+ u32 tx_released_blks[NUM_TX_QUEUES];
+ u32 fw_localtime;
+ u32 padding[2];
+} __attribute__ ((packed));
+
+struct wl1271_rx_mem_pool_addr {
+ u32 addr;
+ u32 addr_extra;
+};
+
+struct wl1271 {
struct ieee80211_hw *hw;
bool mac80211_registered;
@@ -285,7 +283,9 @@ struct wl12xx {
void (*set_power)(bool enable);
int irq;
- enum wl12xx_state state;
+ spinlock_t wl_lock;
+
+ enum wl1271_state state;
struct mutex mutex;
int physical_mem_addr;
@@ -293,11 +293,10 @@ struct wl12xx {
int virtual_mem_addr;
int virtual_reg_addr;
- struct wl12xx_chip chip;
+ struct wl1271_chip chip;
int cmd_box_addr;
int event_box_addr;
- struct boot_attr boot_attr;
u8 *fw;
size_t fw_len;
@@ -307,14 +306,26 @@ struct wl12xx {
u8 bssid[ETH_ALEN];
u8 mac_addr[ETH_ALEN];
u8 bss_type;
+ u8 ssid[IW_ESSID_MAX_SIZE + 1];
+ u8 ssid_len;
u8 listen_int;
int channel;
- void *target_mem_map;
- struct acx_data_path_params_resp *data_path;
+ struct wl1271_acx_mem_map *target_mem_map;
+
+ /* Accounting for allocated / available TX blocks on HW */
+ u32 tx_blocks_freed[NUM_TX_QUEUES];
+ u32 tx_blocks_available;
+ u8 tx_results_count;
+
+ /* Transmitted TX packets counter for chipset interface */
+ int tx_packets_count;
- /* Number of TX packets transferred to the FW, modulo 16 */
- u32 data_in_count;
+ /* Time-offset between host and chipset clocks */
+ int time_offset;
+
+ /* Session counter for the chipset */
+ int session_counter;
/* Frames scheduled for transmission, not handled yet */
struct sk_buff_head tx_queue;
@@ -326,25 +337,13 @@ struct wl12xx {
/* Pending TX frames */
struct sk_buff *tx_frames[16];
- /*
- * Index pointing to the next TX complete entry
- * in the cyclic XT complete array we get from
- * the FW.
- */
- u32 next_tx_complete;
-
/* FW Rx counter */
u32 rx_counter;
- /* Rx frames handled */
- u32 rx_handled;
-
- /* Current double buffer */
- u32 rx_current_buffer;
- u32 rx_last_id;
+ /* Rx memory pool address */
+ struct wl1271_rx_mem_pool_addr rx_mem_pool_addr;
/* The target interrupt mask */
- u32 intr_mask;
struct work_struct irq_work;
/* The mbox event mask */
@@ -362,15 +361,14 @@ struct wl12xx {
/* Default key (for WEP) */
u32 default_key;
- unsigned int tx_mgmt_frm_rate;
- unsigned int tx_mgmt_frm_mod;
-
unsigned int rx_config;
unsigned int rx_filter;
/* is firmware in elp mode */
bool elp;
+ struct completion *elp_compl;
+
/* we can be in psm, but not in elp, we have to differentiate */
bool psm;
@@ -380,30 +378,30 @@ struct wl12xx {
/* in dBm */
int power_level;
- struct wl12xx_stats stats;
- struct wl12xx_debugfs debugfs;
+ struct wl1271_stats stats;
+ struct wl1271_debugfs debugfs;
+
+ u32 buffer_32;
+ u32 buffer_cmd;
+ u8 buffer_busyword[WL1271_BUSY_WORD_LEN];
+ struct wl1271_rx_descriptor *rx_descriptor;
+
+ struct wl1271_fw_status *fw_status;
+ struct wl1271_tx_hw_res_if *tx_res_if;
};
-int wl12xx_plt_start(struct wl12xx *wl);
-int wl12xx_plt_stop(struct wl12xx *wl);
+int wl1271_plt_start(struct wl1271 *wl);
+int wl1271_plt_stop(struct wl1271 *wl);
-#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */
-#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS
#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
-#define WL12XX_DEFAULT_POWER_LEVEL 20
+#define SESSION_COUNTER_MAX 7 /* maximum value for the session counter */
-#define WL12XX_TX_QUEUE_MAX_LENGTH 20
+#define WL1271_DEFAULT_POWER_LEVEL 0
-/* Different chips need different sleep times after power on. WL1271 needs
- * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we
- * know the chip ID, we change the sleep value in the wl12xx chip structure,
- * so in subsequent power ons, we don't waste more time then needed. */
-#define WL12XX_DEFAULT_POWER_ON_SLEEP 200
+#define WL1271_TX_QUEUE_MAX_LENGTH 20
-#define CHIP_ID_1251_PG10 (0x7010101)
-#define CHIP_ID_1251_PG11 (0x7020101)
-#define CHIP_ID_1251_PG12 (0x7030101)
-#define CHIP_ID_1271_PG10 (0x4030101)
+/* WL1271 needs a 200ms sleep after power on */
+#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
#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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "wl1271_acx.h"
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/crc7.h>
+#include <linux/spi/spi.h>
+
+#include "wl1271.h"
+#include "wl12xx_80211.h"
+#include "wl1271_reg.h"
+#include "wl1271_spi.h"
+#include "wl1271_ps.h"
+
+int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event,
+ u8 listen_interval)
+{
+ struct acx_wake_up_condition *wake_up;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx wake up conditions");
+
+ wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
+ if (!wake_up) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wake_up->wake_up_event = wake_up_event;
+ wake_up->listen_interval = listen_interval;
+
+ ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
+ wake_up, sizeof(*wake_up));
+ if (ret < 0) {
+ wl1271_warning("could not set wake up conditions: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(wake_up);
+ return ret;
+}
+
+int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth)
+{
+ struct acx_sleep_auth *auth;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx sleep auth");
+
+ auth = kzalloc(sizeof(*auth), GFP_KERNEL);
+ if (!auth) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ auth->sleep_auth = sleep_auth;
+
+ ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
+ if (ret < 0)
+ return ret;
+
+out:
+ kfree(auth);
+ return ret;
+}
+
+int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len)
+{
+ struct acx_revision *rev;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx fw rev");
+
+ rev = kzalloc(sizeof(*rev), GFP_KERNEL);
+ if (!rev) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1271_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev));
+ if (ret < 0) {
+ wl1271_warning("ACX_FW_REV interrogate failed");
+ goto out;
+ }
+
+ /* be careful with the buffer sizes */
+ strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
+
+ /*
+ * if the firmware version string is exactly
+ * sizeof(rev->fw_version) long or fw_len is less than
+ * sizeof(rev->fw_version) it won't be null terminated
+ */
+ buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
+
+out:
+ kfree(rev);
+ return ret;
+}
+
+int wl1271_acx_tx_power(struct wl1271 *wl, int power)
+{
+ struct acx_current_tx_power *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr");
+
+ if (power < 0 || power > 25)
+ return -EINVAL;
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->current_tx_power = power * 10;
+
+ ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("configure of tx power failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_feature_cfg(struct wl1271 *wl)
+{
+ struct acx_feature_config *feature;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx feature cfg");
+
+ feature = kzalloc(sizeof(*feature), GFP_KERNEL);
+ if (!feature) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
+ feature->data_flow_options = 0;
+ feature->options = 0;
+
+ ret = wl1271_cmd_configure(wl, ACX_FEATURE_CFG,
+ feature, sizeof(*feature));
+ if (ret < 0) {
+ wl1271_error("Couldnt set HW encryption");
+ goto out;
+ }
+
+out:
+ kfree(feature);
+ return ret;
+}
+
+int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map,
+ size_t len)
+{
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx mem map");
+
+ ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time)
+{
+ struct acx_rx_msdu_lifetime *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx rx msdu life time");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->lifetime = life_time;
+ ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("failed to set rx msdu life time: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter)
+{
+ struct acx_rx_config *rx_config;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx rx config");
+
+ rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL);
+ if (!rx_config) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rx_config->config_options = config;
+ rx_config->filter_options = filter;
+
+ ret = wl1271_cmd_configure(wl, ACX_RX_CFG,
+ rx_config, sizeof(*rx_config));
+ if (ret < 0) {
+ wl1271_warning("failed to set rx config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(rx_config);
+ return ret;
+}
+
+int wl1271_acx_pd_threshold(struct wl1271 *wl)
+{
+ struct acx_packet_detection *pd;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx data pd threshold");
+
+ pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* FIXME: threshold value not set */
+
+ ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd));
+ if (ret < 0) {
+ wl1271_warning("failed to set pd threshold: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(pd);
+ return 0;
+}
+
+int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time)
+{
+ struct acx_slot *slot;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx slot");
+
+ slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+ if (!slot) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ slot->wone_index = STATION_WONE_INDEX;
+ slot->slot_time = slot_time;
+
+ ret = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot));
+ if (ret < 0) {
+ wl1271_warning("failed to set slot time: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(slot);
+ return ret;
+}
+
+int wl1271_acx_group_address_tbl(struct wl1271 *wl)
+{
+ struct acx_dot11_grp_addr_tbl *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx group address tbl");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* MAC filtering */
+ acx->enabled = 0;
+ acx->num_groups = 0;
+ memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN);
+
+ ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("failed to set group addr table: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_service_period_timeout(struct wl1271 *wl)
+{
+ struct acx_rx_timeout *rx_timeout;
+ int ret;
+
+ rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL);
+ if (!rx_timeout) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_ACX, "acx service period timeout");
+
+ rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF;
+ rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF;
+
+ ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT,
+ rx_timeout, sizeof(*rx_timeout));
+ if (ret < 0) {
+ wl1271_warning("failed to set service period timeout: %d",
+ ret);
+ goto out;
+ }
+
+out:
+ kfree(rx_timeout);
+ return ret;
+}
+
+int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold)
+{
+ struct acx_rts_threshold *rts;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx rts threshold");
+
+ rts = kzalloc(sizeof(*rts), GFP_KERNEL);
+ if (!rts) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rts->threshold = rts_threshold;
+
+ ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
+ if (ret < 0) {
+ wl1271_warning("failed to set rts threshold: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(rts);
+ return ret;
+}
+
+int wl1271_acx_beacon_filter_opt(struct wl1271 *wl)
+{
+ struct acx_beacon_filter_option *beacon_filter;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx beacon filter opt");
+
+ beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL);
+ if (!beacon_filter) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ beacon_filter->enable = 0;
+ beacon_filter->max_num_beacons = 0;
+
+ ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT,
+ beacon_filter, sizeof(*beacon_filter));
+ if (ret < 0) {
+ wl1271_warning("failed to set beacon filter opt: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(beacon_filter);
+ return ret;
+}
+
+int wl1271_acx_beacon_filter_table(struct wl1271 *wl)
+{
+ struct acx_beacon_filter_ie_table *ie_table;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx beacon filter table");
+
+ ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL);
+ if (!ie_table) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ie_table->num_ie = 0;
+ memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
+
+ ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE,
+ ie_table, sizeof(*ie_table));
+ if (ret < 0) {
+ wl1271_warning("failed to set beacon filter table: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(ie_table);
+ return ret;
+}
+
+int wl1271_acx_sg_enable(struct wl1271 *wl)
+{
+ struct acx_bt_wlan_coex *pta;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx sg enable");
+
+ pta = kzalloc(sizeof(*pta), GFP_KERNEL);
+ if (!pta) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ pta->enable = SG_ENABLE;
+
+ ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta));
+ if (ret < 0) {
+ wl1271_warning("failed to set softgemini enable: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(pta);
+ return ret;
+}
+
+int wl1271_acx_sg_cfg(struct wl1271 *wl)
+{
+ struct acx_bt_wlan_coex_param *param;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx sg cfg");
+
+ param = kzalloc(sizeof(*param), GFP_KERNEL);
+ if (!param) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* BT-WLAN coext parameters */
+ param->min_rate = RATE_INDEX_24MBPS;
+ param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF;
+ param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF;
+ param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF;
+ param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF;
+ param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF;
+ param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF;
+ param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF;
+ param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF;
+ param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF;
+ param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF;
+ param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF;
+ param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF;
+ param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF;
+ param->antenna_type = PTA_ANTENNA_TYPE_DEF;
+ param->signal_type = PTA_SIGNALING_TYPE_DEF;
+ param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF;
+ param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF;
+ param->max_cts = PTA_MAX_NUM_CTS_DEF;
+ param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF;
+ param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF;
+ param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF;
+ param->wlan_elp_hp = PTA_ELP_HP_DEF;
+ param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF;
+ param->ack_mode_dual_ant = PTA_ACK_MODE_DEF;
+ param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF;
+ param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF;
+ param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF;
+
+ ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
+ if (ret < 0) {
+ wl1271_warning("failed to set sg config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(param);
+ return ret;
+}
+
+int wl1271_acx_cca_threshold(struct wl1271 *wl)
+{
+ struct acx_energy_detection *detection;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx cca threshold");
+
+ detection = kzalloc(sizeof(*detection), GFP_KERNEL);
+ if (!detection) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
+ detection->tx_energy_detection = 0;
+
+ ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD,
+ detection, sizeof(*detection));
+ if (ret < 0) {
+ wl1271_warning("failed to set cca threshold: %d", ret);
+ return ret;
+ }
+
+out:
+ kfree(detection);
+ return ret;
+}
+
+int wl1271_acx_bcn_dtim_options(struct wl1271 *wl)
+{
+ struct acx_beacon_broadcast *bb;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx bcn dtim options");
+
+ bb = kzalloc(sizeof(*bb), GFP_KERNEL);
+ if (!bb) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE;
+ bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE;
+ bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE;
+ bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF;
+
+ ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb));
+ if (ret < 0) {
+ wl1271_warning("failed to set rx config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(bb);
+ return ret;
+}
+
+int wl1271_acx_aid(struct wl1271 *wl, u16 aid)
+{
+ struct acx_aid *acx_aid;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx aid");
+
+ acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL);
+ if (!acx_aid) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx_aid->aid = aid;
+
+ ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
+ if (ret < 0) {
+ wl1271_warning("failed to set aid: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx_aid);
+ return ret;
+}
+
+int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask)
+{
+ struct acx_event_mask *mask;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx event mbox mask");
+
+ mask = kzalloc(sizeof(*mask), GFP_KERNEL);
+ if (!mask) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* high event mask is unused */
+ mask->high_event_mask = 0xffffffff;
+
+ mask->event_mask = event_mask;
+
+ ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK,
+ mask, sizeof(*mask));
+ if (ret < 0) {
+ wl1271_warning("failed to set acx_event_mbox_mask: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(mask);
+ return ret;
+}
+
+int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble)
+{
+ struct acx_preamble *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx_set_preamble");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->preamble = preamble;
+
+ ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("Setting of preamble failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_cts_protect(struct wl1271 *wl,
+ enum acx_ctsprotect_type ctsprotect)
+{
+ struct acx_ctsprotect *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->ctsprotect = ctsprotect;
+
+ ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("Setting of ctsprotect failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
+{
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx statistics");
+
+ ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats,
+ sizeof(*stats));
+ if (ret < 0) {
+ wl1271_warning("acx statistics failed: %d", ret);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+int wl1271_acx_rate_policies(struct wl1271 *wl)
+{
+ struct acx_rate_policy *acx;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_ACX, "acx rate policies");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* configure one default (one-size-fits-all) rate class */
+ acx->rate_class_cnt = 1;
+ acx->rate_class[0].enabled_rates = ACX_RATE_MASK_ALL;
+ acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT;
+ acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT;
+ acx->rate_class[0].aflags = 0;
+
+ ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("Setting of rate policies failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_ac_cfg(struct wl1271 *wl)
+{
+ struct acx_ac_cfg *acx;
+ int i, ret = 0;
+
+ wl1271_debug(DEBUG_ACX, "acx access category config");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * FIXME: Configure each AC with appropriate values (most suitable
+ * values will probably be different for each AC.
+ */
+ for (i = 0; i < WL1271_ACX_AC_COUNT; i++) {
+ acx->ac = i;
+
+ /*
+ * FIXME: The following default values originate from
+ * the TI reference driver. What do they mean?
+ */
+ acx->cw_min = 15;
+ acx->cw_max = 63;
+ acx->aifsn = 3;
+ acx->reserved = 0;
+ acx->tx_op_limit = 0;
+
+ ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("Setting of access category "
+ "config: %d", ret);
+ goto out;
+ }
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_tid_cfg(struct wl1271 *wl)
+{
+ struct acx_tid_config *acx;
+ int i, ret = 0;
+
+ wl1271_debug(DEBUG_ACX, "acx tid config");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* FIXME: configure each TID with a different AC reference */
+ for (i = 0; i < WL1271_ACX_TID_COUNT; i++) {
+ acx->queue_id = i;
+ acx->tsid = WL1271_ACX_AC_BE;
+ acx->ps_scheme = WL1271_ACX_PS_SCHEME_LEGACY;
+ acx->ack_policy = WL1271_ACX_ACK_POLICY_LEGACY;
+
+ ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("Setting of tid config failed: %d", ret);
+ goto out;
+ }
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_frag_threshold(struct wl1271 *wl)
+{
+ struct acx_frag_threshold *acx;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_ACX, "acx frag threshold");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
+ ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("Setting of frag threshold failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_tx_config_options(struct wl1271 *wl)
+{
+ struct acx_tx_config_options *acx;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_ACX, "acx tx config options");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->tx_compl_timeout = WL1271_ACX_TX_COMPL_TIMEOUT;
+ acx->tx_compl_threshold = WL1271_ACX_TX_COMPL_THRESHOLD;
+ ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("Setting of tx options failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_mem_cfg(struct wl1271 *wl)
+{
+ struct wl1271_acx_config_memory *mem_conf;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
+
+ mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
+ if (!mem_conf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* memory config */
+ mem_conf->num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
+ mem_conf->rx_mem_block_num = ACX_RX_MEM_BLOCKS;
+ mem_conf->tx_min_mem_block_num = ACX_TX_MIN_MEM_BLOCKS;
+ mem_conf->num_ssid_profiles = ACX_NUM_SSID_PROFILES;
+ mem_conf->total_tx_descriptors = ACX_TX_DESCRIPTORS;
+
+ ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
+ sizeof(*mem_conf));
+ if (ret < 0) {
+ wl1271_warning("wl1271 mem config failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(mem_conf);
+ return ret;
+}
+
+int wl1271_acx_init_mem_config(struct wl1271 *wl)
+{
+ int ret;
+
+ ret = wl1271_acx_mem_cfg(wl);
+ if (ret < 0)
+ return ret;
+
+ wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map),
+ GFP_KERNEL);
+ if (!wl->target_mem_map) {
+ wl1271_error("couldn't allocate target memory map");
+ return -ENOMEM;
+ }
+
+ /* we now ask for the firmware built memory map */
+ ret = wl1271_acx_mem_map(wl, (void *)wl->target_mem_map,
+ sizeof(struct wl1271_acx_mem_map));
+ if (ret < 0) {
+ wl1271_error("couldn't retrieve firmware memory map");
+ kfree(wl->target_mem_map);
+ wl->target_mem_map = NULL;
+ return ret;
+ }
+
+ /* initialize TX block book keeping */
+ wl->tx_blocks_available = wl->target_mem_map->num_tx_mem_blocks;
+ wl1271_debug(DEBUG_TX, "available tx blocks: %d",
+ wl->tx_blocks_available);
+
+ return 0;
+}
+
+int wl1271_acx_init_rx_interrupt(struct wl1271 *wl)
+{
+ struct wl1271_acx_rx_config_opt *rx_conf;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config");
+
+ rx_conf = kzalloc(sizeof(*rx_conf), GFP_KERNEL);
+ if (!rx_conf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rx_conf->threshold = WL1271_RX_INTR_THRESHOLD_DEF;
+ rx_conf->timeout = WL1271_RX_INTR_TIMEOUT_DEF;
+ rx_conf->mblk_threshold = USHORT_MAX; /* Disabled */
+ rx_conf->queue_type = RX_QUEUE_TYPE_RX_LOW_PRIORITY;
+
+ ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf,
+ sizeof(*rx_conf));
+ if (ret < 0) {
+ wl1271_warning("wl1271 rx config opt failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(rx_conf);
+ return ret;
+}
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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_ACX_H__
+#define __WL1271_ACX_H__
+
+#include "wl1271.h"
+#include "wl1271_cmd.h"
+
+/*************************************************************************
+
+ Host Interrupt Register (WiLink -> Host)
+
+**************************************************************************/
+/* HW Initiated interrupt Watchdog timer expiration */
+#define WL1271_ACX_INTR_WATCHDOG BIT(0)
+/* Init sequence is done (masked interrupt, detection through polling only ) */
+#define WL1271_ACX_INTR_INIT_COMPLETE BIT(1)
+/* Event was entered to Event MBOX #A*/
+#define WL1271_ACX_INTR_EVENT_A BIT(2)
+/* Event was entered to Event MBOX #B*/
+#define WL1271_ACX_INTR_EVENT_B BIT(3)
+/* Command processing completion*/
+#define WL1271_ACX_INTR_CMD_COMPLETE BIT(4)
+/* Signaling the host on HW wakeup */
+#define WL1271_ACX_INTR_HW_AVAILABLE BIT(5)
+/* The MISC bit is used for aggregation of RX, TxComplete and TX rate update */
+#define WL1271_ACX_INTR_DATA BIT(6)
+/* Trace meassge on MBOX #A */
+#define WL1271_ACX_INTR_TRACE_A BIT(7)
+/* Trace meassge on MBOX #B */
+#define WL1271_ACX_INTR_TRACE_B BIT(8)
+
+#define WL1271_ACX_INTR_ALL 0xFFFFFFFF
+#define WL1271_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \
+ WL1271_ACX_INTR_INIT_COMPLETE | \
+ WL1271_ACX_INTR_EVENT_A | \
+ WL1271_ACX_INTR_EVENT_B | \
+ WL1271_ACX_INTR_CMD_COMPLETE | \
+ WL1271_ACX_INTR_HW_AVAILABLE | \
+ WL1271_ACX_INTR_DATA)
+
+#define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \
+ WL1271_ACX_INTR_EVENT_B | \
+ WL1271_ACX_INTR_DATA)
+
+/* Target's information element */
+struct acx_header {
+ struct wl1271_cmd_header cmd;
+
+ /* acx (or information element) header */
+ u16 id;
+
+ /* payload length (not including headers */
+ u16 len;
+};
+
+struct acx_error_counter {
+ struct acx_header header;
+
+ /* The number of PLCP errors since the last time this */
+ /* information element was interrogated. This field is */
+ /* automatically cleared when it is interrogated.*/
+ u32 PLCP_error;
+
+ /* The number of FCS errors since the last time this */
+ /* information element was interrogated. This field is */
+ /* automatically cleared when it is interrogated.*/
+ u32 FCS_error;
+
+ /* The number of MPDUs without PLCP header errors received*/
+ /* since the last time this information element was interrogated. */
+ /* This field is automatically cleared when it is interrogated.*/
+ u32 valid_frame;
+
+ /* the number of missed sequence numbers in the squentially */
+ /* values of frames seq numbers */
+ u32 seq_num_miss;
+} __attribute__ ((packed));
+
+struct acx_revision {
+ struct acx_header header;
+
+ /*
+ * The WiLink firmware version, an ASCII string x.x.x.x,
+ * that uniquely identifies the current firmware.
+ * The left most digit is incremented each time a
+ * significant change is made to the firmware, such as
+ * code redesign or new platform support.
+ * The second digit is incremented when major enhancements
+ * are added or major fixes are made.
+ * The third digit is incremented for each GA release.
+ * The fourth digit is incremented for each build.
+ * The first two digits identify a firmware release version,
+ * in other words, a unique set of features.
+ * The first three digits identify a GA release.
+ */
+ char fw_version[20];
+
+ /*
+ * This 4 byte field specifies the WiLink hardware version.
+ * bits 0 - 15: Reserved.
+ * bits 16 - 23: Version ID - The WiLink version ID
+ * (1 = first spin, 2 = second spin, and so on).
+ * bits 24 - 31: Chip ID - The WiLink chip ID.
+ */
+ u32 hw_version;
+} __attribute__ ((packed));
+
+enum wl1271_psm_mode {
+ /* Active mode */
+ WL1271_PSM_CAM = 0,
+
+ /* Power save mode */
+ WL1271_PSM_PS = 1,
+
+ /* Extreme low power */
+ WL1271_PSM_ELP = 2,
+};
+
+struct acx_sleep_auth {
+ struct acx_header header;
+
+ /* The sleep level authorization of the device. */
+ /* 0 - Always active*/
+ /* 1 - Power down mode: light / fast sleep*/
+ /* 2 - ELP mode: Deep / Max sleep*/
+ u8 sleep_auth;
+ u8 padding[3];
+} __attribute__ ((packed));
+
+enum {
+ HOSTIF_PCI_MASTER_HOST_INDIRECT,
+ HOSTIF_PCI_MASTER_HOST_DIRECT,
+ HOSTIF_SLAVE,
+ HOSTIF_PKT_RING,
+ HOSTIF_DONTCARE = 0xFF
+};
+
+#define DEFAULT_UCAST_PRIORITY 0
+#define DEFAULT_RX_Q_PRIORITY 0
+#define DEFAULT_NUM_STATIONS 1
+#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */
+#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */
+#define TRACE_BUFFER_MAX_SIZE 256
+
+#define DP_RX_PACKET_RING_CHUNK_SIZE 1600
+#define DP_TX_PACKET_RING_CHUNK_SIZE 1600
+#define DP_RX_PACKET_RING_CHUNK_NUM 2
+#define DP_TX_PACKET_RING_CHUNK_NUM 2
+#define DP_TX_COMPLETE_TIME_OUT 20
+#define FW_TX_CMPLT_BLOCK_SIZE 16
+
+#define TX_MSDU_LIFETIME_MIN 0
+#define TX_MSDU_LIFETIME_MAX 3000
+#define TX_MSDU_LIFETIME_DEF 512
+#define RX_MSDU_LIFETIME_MIN 0
+#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF
+#define RX_MSDU_LIFETIME_DEF 512000
+
+struct acx_rx_msdu_lifetime {
+ struct acx_header header;
+
+ /*
+ * The maximum amount of time, in TU, before the
+ * firmware discards the MSDU.
+ */
+ u32 lifetime;
+} __attribute__ ((packed));
+
+/*
+ * RX Config Options Table
+ * Bit Definition
+ * === ==========
+ * 31:14 Reserved
+ * 13 Copy RX Status - when set, write three receive status words
+ * to top of rx'd MPDUs.
+ * When cleared, do not write three status words (added rev 1.5)
+ * 12 Reserved
+ * 11 RX Complete upon FCS error - when set, give rx complete
+ * interrupt for FCS errors, after the rx filtering, e.g. unicast
+ * frames not to us with FCS error will not generate an interrupt.
+ * 10 SSID Filter Enable - When set, the WiLink discards all beacon,
+ * probe request, and probe response frames with an SSID that does
+ * not match the SSID specified by the host in the START/JOIN
+ * command.
+ * When clear, the WiLink receives frames with any SSID.
+ * 9 Broadcast Filter Enable - When set, the WiLink discards all
+ * broadcast frames. When clear, the WiLink receives all received
+ * broadcast frames.
+ * 8:6 Reserved
+ * 5 BSSID Filter Enable - When set, the WiLink discards any frames
+ * with a BSSID that does not match the BSSID specified by the
+ * host.
+ * When clear, the WiLink receives frames from any BSSID.
+ * 4 MAC Addr Filter - When set, the WiLink discards any frames
+ * with a destination address that does not match the MAC address
+ * of the adaptor.
+ * When clear, the WiLink receives frames destined to any MAC
+ * address.
+ * 3 Promiscuous - When set, the WiLink receives all valid frames
+ * (i.e., all frames that pass the FCS check).
+ * When clear, only frames that pass the other filters specified
+ * are received.
+ * 2 FCS - When set, the WiLink includes the FCS with the received
+ * frame.
+ * When cleared, the FCS is discarded.
+ * 1 PLCP header - When set, write all data from baseband to frame
+ * buffer including PHY header.
+ * 0 Reserved - Always equal to 0.
+ *
+ * RX Filter Options Table
+ * Bit Definition
+ * === ==========
+ * 31:12 Reserved - Always equal to 0.
+ * 11 Association - When set, the WiLink receives all association
+ * related frames (association request/response, reassocation
+ * request/response, and disassociation). When clear, these frames
+ * are discarded.
+ * 10 Auth/De auth - When set, the WiLink receives all authentication
+ * and de-authentication frames. When clear, these frames are
+ * discarded.
+ * 9 Beacon - When set, the WiLink receives all beacon frames.
+ * When clear, these frames are discarded.
+ * 8 Contention Free - When set, the WiLink receives all contention
+ * free frames.
+ * When clear, these frames are discarded.
+ * 7 Control - When set, the WiLink receives all control frames.
+ * When clear, these frames are discarded.
+ * 6 Data - When set, the WiLink receives all data frames.
+ * When clear, these frames are discarded.
+ * 5 FCS Error - When set, the WiLink receives frames that have FCS
+ * errors.
+ * When clear, these frames are discarded.
+ * 4 Management - When set, the WiLink receives all management
+ * frames.
+ * When clear, these frames are discarded.
+ * 3 Probe Request - When set, the WiLink receives all probe request
+ * frames.
+ * When clear, these frames are discarded.
+ * 2 Probe Response - When set, the WiLink receives all probe
+ * response frames.
+ * When clear, these frames are discarded.
+ * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK
+ * frames.
+ * When clear, these frames are discarded.
+ * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames
+ * that have reserved frame types and sub types as defined by the
+ * 802.11 specification.
+ * When clear, these frames are discarded.
+ */
+struct acx_rx_config {
+ struct acx_header header;
+
+ u32 config_options;
+ u32 filter_options;
+} __attribute__ ((packed));
+
+struct acx_packet_detection {
+ struct acx_header header;
+
+ u32 threshold;
+} __attribute__ ((packed));
+
+
+enum acx_slot_type {
+ SLOT_TIME_LONG = 0,
+ SLOT_TIME_SHORT = 1,
+ DEFAULT_SLOT_TIME = SLOT_TIME_SHORT,
+ MAX_SLOT_TIMES = 0xFF
+};
+
+#define STATION_WONE_INDEX 0
+
+struct acx_slot {
+ struct acx_header header;
+
+ u8 wone_index; /* Reserved */
+ u8 slot_time;
+ u8 reserved[6];
+} __attribute__ ((packed));
+
+
+#define ADDRESS_GROUP_MAX (8)
+#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX)
+
+struct acx_dot11_grp_addr_tbl {
+ struct acx_header header;
+
+ u8 enabled;
+ u8 num_groups;
+ u8 pad[2];
+ u8 mac_table[ADDRESS_GROUP_MAX_LEN];
+} __attribute__ ((packed));
+
+
+#define RX_TIMEOUT_PS_POLL_MIN 0
+#define RX_TIMEOUT_PS_POLL_MAX (200000)
+#define RX_TIMEOUT_PS_POLL_DEF (15)
+#define RX_TIMEOUT_UPSD_MIN 0
+#define RX_TIMEOUT_UPSD_MAX (200000)
+#define RX_TIMEOUT_UPSD_DEF (15)
+
+struct acx_rx_timeout {
+ struct acx_header header;
+
+ /*
+ * The longest time the STA will wait to receive
+ * traffic from the AP after a PS-poll has been
+ * transmitted.
+ */
+ u16 ps_poll_timeout;
+
+ /*
+ * The longest time the STA will wait to receive
+ * traffic from the AP after a frame has been sent
+ * from an UPSD enabled queue.
+ */
+ u16 upsd_timeout;
+} __attribute__ ((packed));
+
+#define RTS_THRESHOLD_MIN 0
+#define RTS_THRESHOLD_MAX 4096
+#define RTS_THRESHOLD_DEF 2347
+
+struct acx_rts_threshold {
+ struct acx_header header;
+
+ u16 threshold;
+ u8 pad[2];
+} __attribute__ ((packed));
+
+struct acx_beacon_filter_option {
+ struct acx_header header;
+
+ u8 enable;
+
+ /*
+ * The number of beacons without the unicast TIM
+ * bit set that the firmware buffers before
+ * signaling the host about ready frames.
+ * When set to 0 and the filter is enabled, beacons
+ * without the unicast TIM bit set are dropped.
+ */
+ u8 max_num_beacons;
+ u8 pad[2];
+} __attribute__ ((packed));
+
+/*
+ * ACXBeaconFilterEntry (not 221)
+ * Byte Offset Size (Bytes) Definition
+ * =========== ============ ==========
+ * 0 1 IE identifier
+ * 1 1 Treatment bit mask
+ *
+ * ACXBeaconFilterEntry (221)
+ * Byte Offset Size (Bytes) Definition
+ * =========== ============ ==========
+ * 0 1 IE identifier
+ * 1 1 Treatment bit mask
+ * 2 3 OUI
+ * 5 1 Type
+ * 6 2 Version
+ *
+ *
+ * Treatment bit mask - The information element handling:
+ * bit 0 - The information element is compared and transferred
+ * in case of change.
+ * bit 1 - The information element is transferred to the host
+ * with each appearance or disappearance.
+ * Note that both bits can be set at the same time.
+ */
+#define BEACON_FILTER_TABLE_MAX_IE_NUM (32)
+#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6)
+#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2)
+#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6)
+#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \
+ BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \
+ (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \
+ BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE))
+
+struct acx_beacon_filter_ie_table {
+ struct acx_header header;
+
+ u8 num_ie;
+ u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
+ u8 pad[3];
+} __attribute__ ((packed));
+
+enum {
+ SG_ENABLE = 0,
+ SG_DISABLE,
+ SG_SENSE_NO_ACTIVITY,
+ SG_SENSE_ACTIVE
+};
+
+struct acx_bt_wlan_coex {
+ struct acx_header header;
+
+ /*
+ * 0 -> PTA enabled
+ * 1 -> PTA disabled
+ * 2 -> sense no active mode, i.e.
+ * an interrupt is sent upon
+ * BT activity.
+ * 3 -> PTA is switched on in response
+ * to the interrupt sending.
+ */
+ u8 enable;
+ u8 pad[3];
+} __attribute__ ((packed));
+
+#define PTA_ANTENNA_TYPE_DEF (0)
+#define PTA_BT_HP_MAXTIME_DEF (2000)
+#define PTA_WLAN_HP_MAX_TIME_DEF (5000)
+#define PTA_SENSE_DISABLE_TIMER_DEF (1350)
+#define PTA_PROTECTIVE_RX_TIME_DEF (1500)
+#define PTA_PROTECTIVE_TX_TIME_DEF (1500)
+#define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000)
+#define PTA_SIGNALING_TYPE_DEF (1)
+#define PTA_AFH_LEVERAGE_ON_DEF (0)
+#define PTA_NUMBER_QUIET_CYCLE_DEF (0)
+#define PTA_MAX_NUM_CTS_DEF (3)
+#define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2)
+#define PTA_NUMBER_OF_BT_PACKETS_DEF (2)
+#define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500)
+#define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000)
+#define PTA_CYCLE_TIME_FAST_DEF (8700)
+#define PTA_RX_FOR_AVALANCHE_DEF (5)
+#define PTA_ELP_HP_DEF (0)
+#define PTA_ANTI_STARVE_PERIOD_DEF (500)
+#define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4)
+#define PTA_ALLOW_PA_SD_DEF (1)
+#define PTA_TIME_BEFORE_BEACON_DEF (6300)
+#define PTA_HPDM_MAX_TIME_DEF (1600)
+#define PTA_TIME_OUT_NEXT_WLAN_DEF (2550)
+#define PTA_AUTO_MODE_NO_CTS_DEF (0)
+#define PTA_BT_HP_RESPECTED_DEF (3)
+#define PTA_WLAN_RX_MIN_RATE_DEF (24)
+#define PTA_ACK_MODE_DEF (1)
+
+struct acx_bt_wlan_coex_param {
+ struct acx_header header;
+
+ /*
+ * The minimum rate of a received WLAN packet in the STA,
+ * during protective mode, of which a new BT-HP request
+ * during this Rx will always be respected and gain the antenna.
+ */
+ u32 min_rate;
+
+ /* Max time the BT HP will be respected. */
+ u16 bt_hp_max_time;
+
+ /* Max time the WLAN HP will be respected. */
+ u16 wlan_hp_max_time;
+
+ /*
+ * The time between the last BT activity
+ * and the moment when the sense mode returns
+ * to SENSE_INACTIVE.
+ */
+ u16 sense_disable_timer;
+
+ /* Time before the next BT HP instance */
+ u16 rx_time_bt_hp;
+ u16 tx_time_bt_hp;
+
+ /* range: 10-20000 default: 1500 */
+ u16 rx_time_bt_hp_fast;
+ u16 tx_time_bt_hp_fast;
+
+ /* range: 2000-65535 default: 8700 */
+ u16 wlan_cycle_fast;
+
+ /* range: 0 - 15000 (Msec) default: 1000 */
+ u16 bt_anti_starvation_period;
+
+ /* range 400-10000(Usec) default: 3000 */
+ u16 next_bt_lp_packet;
+
+ /* Deafult: worst case for BT DH5 traffic */
+ u16 wake_up_beacon;
+
+ /* range: 0-50000(Usec) default: 1050 */
+ u16 hp_dm_max_guard_time;
+
+ /*
+ * This is to prevent both BT & WLAN antenna
+ * starvation.
+ * Range: 100-50000(Usec) default:2550
+ */
+ u16 next_wlan_packet;
+
+ /* 0 -> shared antenna */
+ u8 antenna_type;
+
+ /*
+ * 0 -> TI legacy
+ * 1 -> Palau
+ */
+ u8 signal_type;
+
+ /*
+ * BT AFH status
+ * 0 -> no AFH
+ * 1 -> from dedicated GPIO
+ * 2 -> AFH on (from host)
+ */
+ u8 afh_leverage_on;
+
+ /*
+ * The number of cycles during which no
+ * TX will be sent after 1 cycle of RX
+ * transaction in protective mode
+ */
+ u8 quiet_cycle_num;
+
+ /*
+ * The maximum number of CTSs that will
+ * be sent for receiving RX packet in
+ * protective mode
+ */
+ u8 max_cts;
+
+ /*
+ * The number of WLAN packets
+ * transferred in common mode before
+ * switching to BT.
+ */
+ u8 wlan_packets_num;
+
+ /*
+ * The number of BT packets
+ * transferred in common mode before
+ * switching to WLAN.
+ */
+ u8 bt_packets_num;
+
+ /* range: 1-255 default: 5 */
+ u8 missed_rx_avalanche;
+
+ /* range: 0-1 default: 1 */
+ u8 wlan_elp_hp;
+
+ /* range: 0 - 15 default: 4 */
+ u8 bt_anti_starvation_cycles;
+
+ u8 ack_mode_dual_ant;
+
+ /*
+ * Allow PA_SD assertion/de-assertion
+ * during enabled BT activity.
+ */
+ u8 pa_sd_enable;
+
+ /*
+ * Enable/Disable PTA in auto mode:
+ * Support Both Active & P.S modes
+ */
+ u8 pta_auto_mode_enable;
+
+ /* range: 0 - 20 default: 1 */
+ u8 bt_hp_respected_num;
+} __attribute__ ((packed));
+
+#define CCA_THRSH_ENABLE_ENERGY_D 0x140A
+#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF
+
+struct acx_energy_detection {
+ struct acx_header header;
+
+ /* The RX Clear Channel Assessment threshold in the PHY */
+ u16 rx_cca_threshold;
+ u8 tx_energy_detection;
+ u8 pad;
+} __attribute__ ((packed));
+
+#define BCN_RX_TIMEOUT_DEF_VALUE 10000
+#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000
+#define RX_BROADCAST_IN_PS_DEF_VALUE 1
+#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4
+
+struct acx_beacon_broadcast {
+ struct acx_header header;
+
+ u16 beacon_rx_timeout;
+ u16 broadcast_timeout;
+
+ /* Enables receiving of broadcast packets in PS mode */
+ u8 rx_broadcast_in_ps;
+
+ /* Consecutive PS Poll failures before updating the host */
+ u8 ps_poll_threshold;
+ u8 pad[2];
+} __attribute__ ((packed));
+
+struct acx_event_mask {
+ struct acx_header header;
+
+ u32 event_mask;
+ u32 high_event_mask; /* Unused */
+} __attribute__ ((packed));
+
+#define CFG_RX_FCS BIT(2)
+#define CFG_RX_ALL_GOOD BIT(3)
+#define CFG_UNI_FILTER_EN BIT(4)
+#define CFG_BSSID_FILTER_EN BIT(5)
+#define CFG_MC_FILTER_EN BIT(6)
+#define CFG_MC_ADDR0_EN BIT(7)
+#define CFG_MC_ADDR1_EN BIT(8)
+#define CFG_BC_REJECT_EN BIT(9)
+#define CFG_SSID_FILTER_EN BIT(10)
+#define CFG_RX_INT_FCS_ERROR BIT(11)
+#define CFG_RX_INT_ENCRYPTED BIT(12)
+#define CFG_RX_WR_RX_STATUS BIT(13)
+#define CFG_RX_FILTER_NULTI BIT(14)
+#define CFG_RX_RESERVE BIT(15)
+#define CFG_RX_TIMESTAMP_TSF BIT(16)
+
+#define CFG_RX_RSV_EN BIT(0)
+#define CFG_RX_RCTS_ACK BIT(1)
+#define CFG_RX_PRSP_EN BIT(2)
+#define CFG_RX_PREQ_EN BIT(3)
+#define CFG_RX_MGMT_EN BIT(4)
+#define CFG_RX_FCS_ERROR BIT(5)
+#define CFG_RX_DATA_EN BIT(6)
+#define CFG_RX_CTL_EN BIT(7)
+#define CFG_RX_CF_EN BIT(8)
+#define CFG_RX_BCN_EN BIT(9)
+#define CFG_RX_AUTH_EN BIT(10)
+#define CFG_RX_ASSOC_EN BIT(11)
+
+#define SCAN_PASSIVE BIT(0)
+#define SCAN_5GHZ_BAND BIT(1)
+#define SCAN_TRIGGERED BIT(2)
+#define SCAN_PRIORITY_HIGH BIT(3)
+
+struct acx_feature_config {
+ struct acx_header header;
+
+ u32 options;
+ u32 data_flow_options;
+} __attribute__ ((packed));
+
+struct acx_current_tx_power {
+ struct acx_header header;
+
+ u8 current_tx_power;
+ u8 padding[3];
+} __attribute__ ((packed));
+
+enum acx_wake_up_event {
+ WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/
+ WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/
+ WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */
+ WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */
+ WAKE_UP_EVENT_BITS_MASK = 0x0F
+};
+
+struct acx_wake_up_condition {
+ struct acx_header header;
+
+ u8 wake_up_event; /* Only one bit can be set */
+ u8 listen_interval;
+ u8 pad[2];
+} __attribute__ ((packed));
+
+struct acx_aid {
+ struct acx_header header;
+
+ /*
+ * To be set when associated with an AP.
+ */
+ u16 aid;
+ u8 pad[2];
+} __attribute__ ((packed));
+
+enum acx_preamble_type {
+ ACX_PREAMBLE_LONG = 0,
+ ACX_PREAMBLE_SHORT = 1
+};
+
+struct acx_preamble {
+ struct acx_header header;
+
+ /*
+ * When set, the WiLink transmits the frames with a short preamble and
+ * when cleared, the WiLink transmits the frames with a long preamble.
+ */
+ u8 preamble;
+ u8 padding[3];
+} __attribute__ ((packed));
+
+enum acx_ctsprotect_type {
+ CTSPROTECT_DISABLE = 0,
+ CTSPROTECT_ENABLE = 1
+};
+
+struct acx_ctsprotect {
+ struct acx_header header;
+ u8 ctsprotect;
+ u8 padding[3];
+} __attribute__ ((packed));
+
+struct acx_tx_statistics {
+ u32 internal_desc_overflow;
+} __attribute__ ((packed));
+
+struct acx_rx_statistics {
+ u32 out_of_mem;
+ u32 hdr_overflow;
+ u32 hw_stuck;
+ u32 dropped;
+ u32 fcs_err;
+ u32 xfr_hint_trig;
+ u32 path_reset;
+ u32 reset_counter;
+} __attribute__ ((packed));
+
+struct acx_dma_statistics {
+ u32 rx_requested;
+ u32 rx_errors;
+ u32 tx_requested;
+ u32 tx_errors;
+} __attribute__ ((packed));
+
+struct acx_isr_statistics {
+ /* host command complete */
+ u32 cmd_cmplt;
+
+ /* fiqisr() */
+ u32 fiqs;
+
+ /* (INT_STS_ND & INT_TRIG_RX_HEADER) */
+ u32 rx_headers;
+
+ /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */
+ u32 rx_completes;
+
+ /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */
+ u32 rx_mem_overflow;
+
+ /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */
+ u32 rx_rdys;
+
+ /* irqisr() */
+ u32 irqs;
+
+ /* (INT_STS_ND & INT_TRIG_TX_PROC) */
+ u32 tx_procs;
+
+ /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */
+ u32 decrypt_done;
+
+ /* (INT_STS_ND & INT_TRIG_DMA0) */
+ u32 dma0_done;
+
+ /* (INT_STS_ND & INT_TRIG_DMA1) */
+ u32 dma1_done;
+
+ /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */
+ u32 tx_exch_complete;
+
+ /* (INT_STS_ND & INT_TRIG_COMMAND) */
+ u32 commands;
+
+ /* (INT_STS_ND & INT_TRIG_RX_PROC) */
+ u32 rx_procs;
+
+ /* (INT_STS_ND & INT_TRIG_PM_802) */
+ u32 hw_pm_mode_changes;
+
+ /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */
+ u32 host_acknowledges;
+
+ /* (INT_STS_ND & INT_TRIG_PM_PCI) */
+ u32 pci_pm;
+
+ /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */
+ u32 wakeups;
+
+ /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
+ u32 low_rssi;
+} __attribute__ ((packed));
+
+struct acx_wep_statistics {
+ /* WEP address keys configured */
+ u32 addr_key_count;
+
+ /* default keys configured */
+ u32 default_key_count;
+
+ u32 reserved;
+
+ /* number of times that WEP key not found on lookup */
+ u32 key_not_found;
+
+ /* number of times that WEP key decryption failed */
+ u32 decrypt_fail;
+
+ /* WEP packets decrypted */
+ u32 packets;
+
+ /* WEP decrypt interrupts */
+ u32 interrupt;
+} __attribute__ ((packed));
+
+#define ACX_MISSED_BEACONS_SPREAD 10
+
+struct acx_pwr_statistics {
+ /* the amount of enters into power save mode (both PD & ELP) */
+ u32 ps_enter;
+
+ /* the amount of enters into ELP mode */
+ u32 elp_enter;
+
+ /* the amount of missing beacon interrupts to the host */
+ u32 missing_bcns;
+
+ /* the amount of wake on host-access times */
+ u32 wake_on_host;
+
+ /* the amount of wake on timer-expire */
+ u32 wake_on_timer_exp;
+
+ /* the number of packets that were transmitted with PS bit set */
+ u32 tx_with_ps;
+
+ /* the number of packets that were transmitted with PS bit clear */
+ u32 tx_without_ps;
+
+ /* the number of received beacons */
+ u32 rcvd_beacons;
+
+ /* the number of entering into PowerOn (power save off) */
+ u32 power_save_off;
+
+ /* the number of entries into power save mode */
+ u16 enable_ps;
+
+ /*
+ * the number of exits from power save, not including failed PS
+ * transitions
+ */
+ u16 disable_ps;
+
+ /*
+ * the number of times the TSF counter was adjusted because
+ * of drift
+ */
+ u32 fix_tsf_ps;
+
+ /* Gives statistics about the spread continuous missed beacons.
+ * The 16 LSB are dedicated for the PS mode.
+ * The 16 MSB are dedicated for the PS mode.
+ * cont_miss_bcns_spread[0] - single missed beacon.
+ * cont_miss_bcns_spread[1] - two continuous missed beacons.
+ * cont_miss_bcns_spread[2] - three continuous missed beacons.
+ * ...
+ * cont_miss_bcns_spread[9] - ten and more continuous missed beacons.
+ */
+ u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD];
+
+ /* the number of beacons in awake mode */
+ u32 rcvd_awake_beacons;
+} __attribute__ ((packed));
+
+struct acx_mic_statistics {
+ u32 rx_pkts;
+ u32 calc_failure;
+} __attribute__ ((packed));
+
+struct acx_aes_statistics {
+ u32 encrypt_fail;
+ u32 decrypt_fail;
+ u32 encrypt_packets;
+ u32 decrypt_packets;
+ u32 encrypt_interrupt;
+ u32 decrypt_interrupt;
+} __attribute__ ((packed));
+
+struct acx_event_statistics {
+ u32 heart_beat;
+ u32 calibration;
+ u32 rx_mismatch;
+ u32 rx_mem_empty;
+ u32 rx_pool;
+ u32 oom_late;
+ u32 phy_transmit_error;
+ u32 tx_stuck;
+} __attribute__ ((packed));
+
+struct acx_ps_statistics {
+ u32 pspoll_timeouts;
+ u32 upsd_timeouts;
+ u32 upsd_max_sptime;
+ u32 upsd_max_apturn;
+ u32 pspoll_max_apturn;
+ u32 pspoll_utilization;
+ u32 upsd_utilization;
+} __attribute__ ((packed));
+
+struct acx_rxpipe_statistics {
+ u32 rx_prep_beacon_drop;
+ u32 descr_host_int_trig_rx_data;
+ u32 beacon_buffer_thres_host_int_trig_rx_data;
+ u32 missed_beacon_host_int_trig_rx_data;
+ u32 tx_xfr_host_int_trig_rx_data;
+} __attribute__ ((packed));
+
+struct acx_statistics {
+ struct acx_header header;
+
+ struct acx_tx_statistics tx;
+ struct acx_rx_statistics rx;
+ struct acx_dma_statistics dma;
+ struct acx_isr_statistics isr;
+ struct acx_wep_statistics wep;
+ struct acx_pwr_statistics pwr;
+ struct acx_aes_statistics aes;
+ struct acx_mic_statistics mic;
+ struct acx_event_statistics event;
+ struct acx_ps_statistics ps;
+ struct acx_rxpipe_statistics rxpipe;
+} __attribute__ ((packed));
+
+#define ACX_MAX_RATE_CLASSES 8
+#define ACX_RATE_MASK_UNSPECIFIED 0
+#define ACX_RATE_MASK_ALL 0x1eff
+#define ACX_RATE_RETRY_LIMIT 10
+
+struct acx_rate_class {
+ u32 enabled_rates;
+ u8 short_retry_limit;
+ u8 long_retry_limit;
+ u8 aflags;
+ u8 reserved;
+};
+
+struct acx_rate_policy {
+ struct acx_header header;
+
+ u32 rate_class_cnt;
+ struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES];
+} __attribute__ ((packed));
+
+#define WL1271_ACX_AC_COUNT 4
+
+struct acx_ac_cfg {
+ struct acx_header header;
+ u8 ac;
+ u8 cw_min;
+ u16 cw_max;
+ u8 aifsn;
+ u8 reserved;
+ u16 tx_op_limit;
+} __attribute__ ((packed));
+
+enum wl1271_acx_ac {
+ WL1271_ACX_AC_BE = 0,
+ WL1271_ACX_AC_BK = 1,
+ WL1271_ACX_AC_VI = 2,
+ WL1271_ACX_AC_VO = 3,
+ WL1271_ACX_AC_CTS2SELF = 4,
+ WL1271_ACX_AC_ANY_TID = 0x1F,
+ WL1271_ACX_AC_INVALID = 0xFF,
+};
+
+enum wl1271_acx_ps_scheme {
+ WL1271_ACX_PS_SCHEME_LEGACY = 0,
+ WL1271_ACX_PS_SCHEME_UPSD_TRIGGER = 1,
+ WL1271_ACX_PS_SCHEME_LEGACY_PSPOLL = 2,
+ WL1271_ACX_PS_SCHEME_SAPSD = 3,
+};
+
+enum wl1271_acx_ack_policy {
+ WL1271_ACX_ACK_POLICY_LEGACY = 0,
+ WL1271_ACX_ACK_POLICY_NO_ACK = 1,
+ WL1271_ACX_ACK_POLICY_BLOCK = 2,
+};
+
+#define WL1271_ACX_TID_COUNT 7
+
+struct acx_tid_config {
+ struct acx_header header;
+ u8 queue_id;
+ u8 channel_type;
+ u8 tsid;
+ u8 ps_scheme;
+ u8 ack_policy;
+ u8 padding[3];
+ u32 apsd_conf[2];
+} __attribute__ ((packed));
+
+struct acx_frag_threshold {
+ struct acx_header header;
+ u16 frag_threshold;
+ u8 padding[2];
+} __attribute__ ((packed));
+
+#define WL1271_ACX_TX_COMPL_TIMEOUT 5
+#define WL1271_ACX_TX_COMPL_THRESHOLD 5
+
+struct acx_tx_config_options {
+ struct acx_header header;
+ u16 tx_compl_timeout; /* msec */
+ u16 tx_compl_threshold; /* number of packets */
+} __attribute__ ((packed));
+
+#define ACX_RX_MEM_BLOCKS 64
+#define ACX_TX_MIN_MEM_BLOCKS 64
+#define ACX_TX_DESCRIPTORS 32
+#define ACX_NUM_SSID_PROFILES 1
+
+struct wl1271_acx_config_memory {
+ struct acx_header header;
+
+ u8 rx_mem_block_num;
+ u8 tx_min_mem_block_num;
+ u8 num_stations;
+ u8 num_ssid_profiles;
+ u32 total_tx_descriptors;
+} __attribute__ ((packed));
+
+struct wl1271_acx_mem_map {
+ struct acx_header header;
+
+ void *code_start;
+ void *code_end;
+
+ void *wep_defkey_start;
+ void *wep_defkey_end;
+
+ void *sta_table_start;
+ void *sta_table_end;
+
+ void *packet_template_start;
+ void *packet_template_end;
+
+ /* Address of the TX result interface (control block) */
+ u32 tx_result;
+ u32 tx_result_queue_start;
+
+ void *queue_memory_start;
+ void *queue_memory_end;
+
+ u32 packet_memory_pool_start;
+ u32 packet_memory_pool_end;
+
+ void *debug_buffer1_start;
+ void *debug_buffer1_end;
+
+ void *debug_buffer2_start;
+ void *debug_buffer2_end;
+
+ /* Number of blocks FW allocated for TX packets */
+ u32 num_tx_mem_blocks;
+
+ /* Number of blocks FW allocated for RX packets */
+ u32 num_rx_mem_blocks;
+
+ /* the following 4 fields are valid in SLAVE mode only */
+ u8 *tx_cbuf;
+ u8 *rx_cbuf;
+ void *rx_ctrl;
+ void *tx_ctrl;
+} __attribute__ ((packed));
+
+enum wl1271_acx_rx_queue_type {
+ RX_QUEUE_TYPE_RX_LOW_PRIORITY, /* All except the high priority */
+ RX_QUEUE_TYPE_RX_HIGH_PRIORITY, /* Management and voice packets */
+ RX_QUEUE_TYPE_NUM,
+ RX_QUEUE_TYPE_MAX = USHORT_MAX
+};
+
+#define WL1271_RX_INTR_THRESHOLD_DEF 0 /* no pacing, send interrupt on
+ * every event */
+#define WL1271_RX_INTR_THRESHOLD_MIN 0
+#define WL1271_RX_INTR_THRESHOLD_MAX 15
+
+#define WL1271_RX_INTR_TIMEOUT_DEF 5
+#define WL1271_RX_INTR_TIMEOUT_MIN 1
+#define WL1271_RX_INTR_TIMEOUT_MAX 100
+
+struct wl1271_acx_rx_config_opt {
+ struct acx_header header;
+
+ u16 mblk_threshold;
+ u16 threshold;
+ u16 timeout;
+ u8 queue_type;
+ u8 reserved;
+} __attribute__ ((packed));
+
+enum {
+ ACX_WAKE_UP_CONDITIONS = 0x0002,
+ ACX_MEM_CFG = 0x0003,
+ ACX_SLOT = 0x0004,
+ ACX_AC_CFG = 0x0007,
+ ACX_MEM_MAP = 0x0008,
+ ACX_AID = 0x000A,
+ /* ACX_FW_REV is missing in the ref driver, but seems to work */
+ ACX_FW_REV = 0x000D,
+ ACX_MEDIUM_USAGE = 0x000F,
+ ACX_RX_CFG = 0x0010,
+ ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */
+ ACX_STATISTICS = 0x0013, /* Debug API */
+ ACX_PWR_CONSUMPTION_STATISTICS = 0x0014,
+ ACX_FEATURE_CFG = 0x0015,
+ ACX_TID_CFG = 0x001A,
+ ACX_PS_RX_STREAMING = 0x001B,
+ ACX_BEACON_FILTER_OPT = 0x001F,
+ ACX_NOISE_HIST = 0x0021,
+ ACX_HDK_VERSION = 0x0022, /* ??? */
+ ACX_PD_THRESHOLD = 0x0023,
+ ACX_TX_CONFIG_OPT = 0x0024,
+ ACX_CCA_THRESHOLD = 0x0025,
+ ACX_EVENT_MBOX_MASK = 0x0026,
+ ACX_CONN_MONIT_PARAMS = 0x002D,
+ ACX_CONS_TX_FAILURE = 0x002F,
+ ACX_BCN_DTIM_OPTIONS = 0x0031,
+ ACX_SG_ENABLE = 0x0032,
+ ACX_SG_CFG = 0x0033,
+ ACX_BEACON_FILTER_TABLE = 0x0038,
+ ACX_ARP_IP_FILTER = 0x0039,
+ ACX_ROAMING_STATISTICS_TBL = 0x003B,
+ ACX_RATE_POLICY = 0x003D,
+ ACX_CTS_PROTECTION = 0x003E,
+ ACX_SLEEP_AUTH = 0x003F,
+ ACX_PREAMBLE_TYPE = 0x0040,
+ ACX_ERROR_CNT = 0x0041,
+ ACX_IBSS_FILTER = 0x0044,
+ ACX_SERVICE_PERIOD_TIMEOUT = 0x0045,
+ ACX_TSF_INFO = 0x0046,
+ ACX_CONFIG_PS_WMM = 0x0049,
+ ACX_ENABLE_RX_DATA_FILTER = 0x004A,
+ ACX_SET_RX_DATA_FILTER = 0x004B,
+ ACX_GET_DATA_FILTER_STATISTICS = 0x004C,
+ ACX_RX_CONFIG_OPT = 0x004E,
+ ACX_FRAG_CFG = 0x004F,
+ ACX_BET_ENABLE = 0x0050,
+ ACX_RSSI_SNR_TRIGGER = 0x0051,
+ ACX_RSSI_SNR_WEIGHTS = 0x0051,
+ ACX_KEEP_ALIVE_MODE = 0x0052,
+ ACX_SET_KEEP_ALIVE_CONFIG = 0x0054,
+ ACX_BA_SESSION_RESPONDER_POLICY = 0x0055,
+ ACX_BA_SESSION_INITIATOR_POLICY = 0x0056,
+ ACX_PEER_HT_CAP = 0x0057,
+ ACX_HT_BSS_OPERATION = 0x0058,
+ ACX_COEX_ACTIVITY = 0x0059,
+ DOT11_RX_MSDU_LIFE_TIME = 0x1004,
+ DOT11_CUR_TX_PWR = 0x100D,
+ DOT11_RX_DOT11_MODE = 0x1012,
+ DOT11_RTS_THRESHOLD = 0x1013,
+ DOT11_GROUP_ADDRESS_TBL = 0x1014,
+
+ MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL,
+
+ MAX_IE = 0xFFFF
+};
+
+
+int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event,
+ u8 listen_interval);
+int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth);
+int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len);
+int wl1271_acx_tx_power(struct wl1271 *wl, int power);
+int wl1271_acx_feature_cfg(struct wl1271 *wl);
+int wl1271_acx_mem_map(struct wl1271 *wl,
+ struct acx_header *mem_map, size_t len);
+int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time);
+int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter);
+int wl1271_acx_pd_threshold(struct wl1271 *wl);
+int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time);
+int wl1271_acx_group_address_tbl(struct wl1271 *wl);
+int wl1271_acx_service_period_timeout(struct wl1271 *wl);
+int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold);
+int wl1271_acx_beacon_filter_opt(struct wl1271 *wl);
+int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
+int wl1271_acx_sg_enable(struct wl1271 *wl);
+int wl1271_acx_sg_cfg(struct wl1271 *wl);
+int wl1271_acx_cca_threshold(struct wl1271 *wl);
+int wl1271_acx_bcn_dtim_options(struct wl1271 *wl);
+int wl1271_acx_aid(struct wl1271 *wl, u16 aid);
+int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask);
+int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
+int wl1271_acx_cts_protect(struct wl1271 *wl,
+ enum acx_ctsprotect_type ctsprotect);
+int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
+int wl1271_acx_rate_policies(struct wl1271 *wl);
+int wl1271_acx_ac_cfg(struct wl1271 *wl);
+int wl1271_acx_tid_cfg(struct wl1271 *wl);
+int wl1271_acx_frag_threshold(struct wl1271 *wl);
+int wl1271_acx_tx_config_options(struct wl1271 *wl);
+int wl1271_acx_mem_cfg(struct wl1271 *wl);
+int wl1271_acx_init_mem_config(struct wl1271 *wl);
+int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
+
+#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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/gpio.h>
+
+#include "wl1271_acx.h"
+#include "wl1271_reg.h"
+#include "wl1271_boot.h"
+#include "wl1271_spi.h"
+#include "wl1271_event.h"
+
+static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
+ [PART_DOWN] = {
+ .mem = {
+ .start = 0x00000000,
+ .size = 0x000177c0
+ },
+ .reg = {
+ .start = REGISTERS_BASE,
+ .size = 0x00008800
+ },
+ },
+
+ [PART_WORK] = {
+ .mem = {
+ .start = 0x00040000,
+ .size = 0x00014fc0
+ },
+ .reg = {
+ .start = REGISTERS_BASE,
+ .size = 0x0000b000
+ },
+ },
+
+ [PART_DRPW] = {
+ .mem = {
+ .start = 0x00040000,
+ .size = 0x00014fc0
+ },
+ .reg = {
+ .start = DRPW_BASE,
+ .size = 0x00006000
+ }
+ }
+};
+
+static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
+{
+ u32 cpu_ctrl;
+
+ /* 10.5.0 run the firmware (I) */
+ cpu_ctrl = wl1271_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+
+ /* 10.5.1 run the firmware (II) */
+ cpu_ctrl |= flag;
+ wl1271_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
+}
+
+static void wl1271_boot_fw_version(struct wl1271 *wl)
+{
+ struct wl1271_static_data static_data;
+
+ wl1271_spi_mem_read(wl, wl->cmd_box_addr,
+ &static_data, sizeof(static_data));
+
+ strncpy(wl->chip.fw_ver, static_data.fw_version,
+ sizeof(wl->chip.fw_ver));
+
+ /* make sure the string is NULL-terminated */
+ wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0';
+}
+
+static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
+ size_t fw_data_len, u32 dest)
+{
+ int addr, chunk_num, partition_limit;
+ u8 *p;
+
+ /* whal_FwCtrl_LoadFwImageSm() */
+
+ wl1271_debug(DEBUG_BOOT, "starting firmware upload");
+
+ wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d",
+ fw_data_len, CHUNK_SIZE);
+
+
+ if ((fw_data_len % 4) != 0) {
+ wl1271_error("firmware length not multiple of four");
+ return -EIO;
+ }
+
+ wl1271_set_partition(wl, dest,
+ part_table[PART_DOWN].mem.size,
+ part_table[PART_DOWN].reg.start,
+ part_table[PART_DOWN].reg.size);
+
+ /* 10.1 set partition limit and chunk num */
+ chunk_num = 0;
+ partition_limit = part_table[PART_DOWN].mem.size;
+
+ while (chunk_num < fw_data_len / CHUNK_SIZE) {
+ /* 10.2 update partition, if needed */
+ addr = dest + (chunk_num + 2) * CHUNK_SIZE;
+ if (addr > partition_limit) {
+ addr = dest + chunk_num * CHUNK_SIZE;
+ partition_limit = chunk_num * CHUNK_SIZE +
+ part_table[PART_DOWN].mem.size;
+
+ /* FIXME: Over 80 chars! */
+ wl1271_set_partition(wl,
+ addr,
+ part_table[PART_DOWN].mem.size,
+ part_table[PART_DOWN].reg.start,
+ part_table[PART_DOWN].reg.size);
+ }
+
+ /* 10.3 upload the chunk */
+ addr = dest + chunk_num * CHUNK_SIZE;
+ p = buf + chunk_num * CHUNK_SIZE;
+ wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
+ p, addr);
+ wl1271_spi_mem_write(wl, addr, p, CHUNK_SIZE);
+
+ chunk_num++;
+ }
+
+ /* 10.4 upload the last chunk */
+ addr = dest + chunk_num * CHUNK_SIZE;
+ p = buf + chunk_num * CHUNK_SIZE;
+ wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
+ fw_data_len % CHUNK_SIZE, p, addr);
+ wl1271_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
+
+ return 0;
+}
+
+static int wl1271_boot_upload_firmware(struct wl1271 *wl)
+{
+ u32 chunks, addr, len;
+ u8 *fw;
+
+ fw = wl->fw;
+ chunks = be32_to_cpup((u32 *) fw);
+ fw += sizeof(u32);
+
+ wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks);
+
+ while (chunks--) {
+ addr = be32_to_cpup((u32 *) fw);
+ fw += sizeof(u32);
+ len = be32_to_cpup((u32 *) fw);
+ fw += sizeof(u32);
+
+ if (len > 300000) {
+ wl1271_info("firmware chunk too long: %u", len);
+ return -EINVAL;
+ }
+ wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u",
+ chunks, addr, len);
+ wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
+ fw += len;
+ }
+
+ return 0;
+}
+
+static int wl1271_boot_upload_nvs(struct wl1271 *wl)
+{
+ size_t nvs_len, burst_len;
+ int i;
+ u32 dest_addr, val;
+ u8 *nvs_ptr, *nvs, *nvs_aligned;
+
+ nvs = wl->nvs;
+ if (nvs == NULL)
+ return -ENODEV;
+
+ nvs_ptr = nvs;
+
+ nvs_len = wl->nvs_len;
+
+ /* Update the device MAC address into the nvs */
+ nvs[11] = wl->mac_addr[0];
+ nvs[10] = wl->mac_addr[1];
+ nvs[6] = wl->mac_addr[2];
+ nvs[5] = wl->mac_addr[3];
+ nvs[4] = wl->mac_addr[4];
+ nvs[3] = wl->mac_addr[5];
+
+ /*
+ * Layout before the actual NVS tables:
+ * 1 byte : burst length.
+ * 2 bytes: destination address.
+ * n bytes: data to burst copy.
+ *
+ * This is ended by a 0 length, then the NVS tables.
+ */
+
+ /* FIXME: Do we need to check here whether the LSB is 1? */
+ while (nvs_ptr[0]) {
+ burst_len = nvs_ptr[0];
+ dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
+
+ /* FIXME: Due to our new wl1271_translate_reg_addr function,
+ we need to add the REGISTER_BASE to the destination */
+ dest_addr += REGISTERS_BASE;
+
+ /* We move our pointer to the data */
+ nvs_ptr += 3;
+
+ for (i = 0; i < burst_len; i++) {
+ val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
+ | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
+
+ wl1271_debug(DEBUG_BOOT,
+ "nvs burst write 0x%x: 0x%x",
+ dest_addr, val);
+ wl1271_reg_write32(wl, dest_addr, val);
+
+ nvs_ptr += 4;
+ dest_addr += 4;
+ }
+ }
+
+ /*
+ * We've reached the first zero length, the first NVS table
+ * is 7 bytes further.
+ */
+ nvs_ptr += 7;
+ nvs_len -= nvs_ptr - nvs;
+ nvs_len = ALIGN(nvs_len, 4);
+
+ /* FIXME: The driver sets the partition here, but this is not needed,
+ since it sets to the same one as currently in use */
+ /* Now we must set the partition correctly */
+ wl1271_set_partition(wl,
+ part_table[PART_WORK].mem.start,
+ part_table[PART_WORK].mem.size,
+ part_table[PART_WORK].reg.start,
+ part_table[PART_WORK].reg.size);
+
+ /* Copy the NVS tables to a new block to ensure alignment */
+ nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
+
+ /* And finally we upload the NVS tables */
+ /* FIXME: In wl1271, we upload everything at once.
+ No endianness handling needed here?! The ref driver doesn't do
+ anything about it at this point */
+ wl1271_spi_mem_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len);
+
+ kfree(nvs_aligned);
+ return 0;
+}
+
+static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
+{
+ enable_irq(wl->irq);
+ wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+ WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
+ wl1271_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
+}
+
+static int wl1271_boot_soft_reset(struct wl1271 *wl)
+{
+ unsigned long timeout;
+ u32 boot_data;
+
+ /* perform soft reset */
+ wl1271_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
+
+ /* SOFT_RESET is self clearing */
+ timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
+ while (1) {
+ boot_data = wl1271_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
+ wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
+ if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
+ break;
+
+ if (time_after(jiffies, timeout)) {
+ /* 1.2 check pWhalBus->uSelfClearTime if the
+ * timeout was reached */
+ wl1271_error("soft reset timeout");
+ return -1;
+ }
+
+ udelay(SOFT_RESET_STALL_TIME);
+ }
+
+ /* disable Rx/Tx */
+ wl1271_reg_write32(wl, ENABLE, 0x0);
+
+ /* disable auto calibration on start*/
+ wl1271_reg_write32(wl, SPARE_A2, 0xffff);
+
+ return 0;
+}
+
+static int wl1271_boot_run_firmware(struct wl1271 *wl)
+{
+ int loop, ret;
+ u32 chip_id, interrupt;
+
+ wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
+
+ chip_id = wl1271_reg_read32(wl, CHIP_ID_B);
+
+ wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
+
+ if (chip_id != wl->chip.id) {
+ wl1271_error("chip id doesn't match after firmware boot");
+ return -EIO;
+ }
+
+ /* wait for init to complete */
+ loop = 0;
+ while (loop++ < INIT_LOOP) {
+ udelay(INIT_LOOP_DELAY);
+ interrupt = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+
+ if (interrupt == 0xffffffff) {
+ wl1271_error("error reading hardware complete "
+ "init indication");
+ return -EIO;
+ }
+ /* check that ACX_INTR_INIT_COMPLETE is enabled */
+ else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) {
+ wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ WL1271_ACX_INTR_INIT_COMPLETE);
+ break;
+ }
+ }
+
+ if (loop >= INIT_LOOP) {
+ wl1271_error("timeout waiting for the hardware to "
+ "complete initialization");
+ return -EIO;
+ }
+
+ /* get hardware config command mail box */
+ wl->cmd_box_addr = wl1271_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
+
+ /* get hardware config event mail box */
+ wl->event_box_addr = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+
+ /* set the working partition to its "running" mode offset */
+ wl1271_set_partition(wl,
+ part_table[PART_WORK].mem.start,
+ part_table[PART_WORK].mem.size,
+ part_table[PART_WORK].reg.start,
+ part_table[PART_WORK].reg.size);
+
+ wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
+ wl->cmd_box_addr, wl->event_box_addr);
+
+ wl1271_boot_fw_version(wl);
+
+ /*
+ * in case of full asynchronous mode the firmware event must be
+ * ready to receive event from the command mailbox
+ */
+
+ /* enable gpio interrupts */
+ wl1271_boot_enable_interrupts(wl);
+
+ /* unmask all mbox events */
+ wl->event_mask = 0xffffffff;
+
+ ret = wl1271_event_unmask(wl);
+ if (ret < 0) {
+ wl1271_error("EVENT mask setting failed");
+ return ret;
+ }
+
+ wl1271_event_mbox_config(wl);
+
+ /* firmware startup completed */
+ return 0;
+}
+
+static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
+{
+ u32 polarity, status, i;
+
+ wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY);
+ wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ);
+
+ /* Wait until the command is complete (ie. bit 18 is set) */
+ for (i = 0; i < OCP_CMD_LOOP; i++) {
+ polarity = wl1271_reg_read32(wl, OCP_DATA_READ);
+ if (polarity & OCP_READY_MASK)
+ break;
+ }
+ if (i == OCP_CMD_LOOP) {
+ wl1271_error("OCP command timeout!");
+ return -EIO;
+ }
+
+ status = polarity & OCP_STATUS_MASK;
+ if (status != OCP_STATUS_OK) {
+ wl1271_error("OCP command failed (%d)", status);
+ return -EIO;
+ }
+
+ /* We use HIGH polarity, so unset the LOW bit */
+ polarity &= ~POLARITY_LOW;
+
+ wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY);
+ wl1271_reg_write32(wl, OCP_DATA_WRITE, polarity);
+ wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE);
+
+ return 0;
+}
+
+int wl1271_boot(struct wl1271 *wl)
+{
+ int ret = 0;
+ u32 tmp, clk, pause;
+
+ if (REF_CLOCK == 0 || REF_CLOCK == 2)
+ /* ref clk: 19.2/38.4 */
+ clk = 0x3;
+ else if (REF_CLOCK == 1 || REF_CLOCK == 3)
+ /* ref clk: 26/52 */
+ clk = 0x5;
+
+ wl1271_reg_write32(wl, PLL_PARAMETERS, clk);
+
+ pause = wl1271_reg_read32(wl, PLL_PARAMETERS);
+
+ wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
+
+ pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be
+ * WU_COUNTER_PAUSE_VAL instead of
+ * 0x3ff (magic number ). How does
+ * this work?! */
+ pause |= WU_COUNTER_PAUSE_VAL;
+ wl1271_reg_write32(wl, WU_COUNTER_PAUSE, pause);
+
+ /* Continue the ELP wake up sequence */
+ wl1271_reg_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
+ udelay(500);
+
+ wl1271_set_partition(wl,
+ part_table[PART_DRPW].mem.start,
+ part_table[PART_DRPW].mem.size,
+ part_table[PART_DRPW].reg.start,
+ part_table[PART_DRPW].reg.size);
+
+ /* Read-modify-write DRPW_SCRATCH_START register (see next state)
+ to be used by DRPw FW. The RTRIM value will be added by the FW
+ before taking DRPw out of reset */
+
+ wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
+ clk = wl1271_reg_read32(wl, DRPW_SCRATCH_START);
+
+ wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
+
+ /* 2 */
+ clk |= (REF_CLOCK << 1) << 4;
+ wl1271_reg_write32(wl, DRPW_SCRATCH_START, clk);
+
+ wl1271_set_partition(wl,
+ part_table[PART_WORK].mem.start,
+ part_table[PART_WORK].mem.size,
+ part_table[PART_WORK].reg.start,
+ part_table[PART_WORK].reg.size);
+
+ /* Disable interrupts */
+ wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+
+ ret = wl1271_boot_soft_reset(wl);
+ if (ret < 0)
+ goto out;
+
+ /* 2. start processing NVS file */
+ ret = wl1271_boot_upload_nvs(wl);
+ if (ret < 0)
+ goto out;
+
+ /* write firmware's last address (ie. it's length) to
+ * ACX_EEPROMLESS_IND_REG */
+ wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
+
+ wl1271_reg_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
+
+ tmp = wl1271_reg_read32(wl, CHIP_ID_B);
+
+ wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
+
+ /* 6. read the EEPROM parameters */
+ tmp = wl1271_reg_read32(wl, SCR_PAD2);
+
+ ret = wl1271_boot_write_irq_polarity(wl);
+ if (ret < 0)
+ goto out;
+
+ /* FIXME: Need to check whether this is really what we want */
+ wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+ WL1271_ACX_ALL_EVENTS_VECTOR);
+
+ /* WL1271: The reference driver skips steps 7 to 10 (jumps directly
+ * to upload_fw) */
+
+ ret = wl1271_boot_upload_firmware(wl);
+ if (ret < 0)
+ goto out;
+
+ /* 10.5 start firmware */
+ ret = wl1271_boot_run_firmware(wl);
+ if (ret < 0)
+ goto out;
+
+ /* set the wl1271 default filters */
+ wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
+ wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
+
+ wl1271_event_mbox_config(wl);
+
+out:
+ return ret;
+}
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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __BOOT_H__
+#define __BOOT_H__
+
+#include "wl1271.h"
+
+int wl1271_boot(struct wl1271 *wl);
+
+#define WL1271_NO_SUBBANDS 8
+#define WL1271_NO_POWER_LEVELS 4
+#define WL1271_FW_VERSION_MAX_LEN 20
+
+struct wl1271_static_data {
+ u8 mac_address[ETH_ALEN];
+ u8 padding[2];
+ u8 fw_version[WL1271_FW_VERSION_MAX_LEN];
+ u32 hw_version;
+ u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS];
+};
+
+/* number of times we try to read the INIT interrupt */
+#define INIT_LOOP 20000
+
+/* delay between retries */
+#define INIT_LOOP_DELAY 50
+
+#define REF_CLOCK 2
+#define WU_COUNTER_PAUSE_VAL 0x3FF
+#define WELP_ARM_COMMAND_VAL 0x4
+
+#define OCP_CMD_LOOP 32
+
+#define OCP_CMD_WRITE 0x1
+#define OCP_CMD_READ 0x2
+
+#define OCP_READY_MASK BIT(18)
+#define OCP_STATUS_MASK (BIT(16) | BIT(17))
+
+#define OCP_STATUS_NO_RESP 0x00000
+#define OCP_STATUS_OK 0x10000
+#define OCP_STATUS_REQ_FAILED 0x20000
+#define OCP_STATUS_RESP_ERROR 0x30000
+
+#define OCP_REG_POLARITY 0x30032
+
+#define CMD_MBOX_ADDRESS 0x407B4
+
+#define POLARITY_LOW BIT(1)
+
+#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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/crc7.h>
+#include <linux/spi/spi.h>
+#include <linux/etherdevice.h>
+
+#include "wl1271.h"
+#include "wl1271_reg.h"
+#include "wl1271_spi.h"
+#include "wl1271_acx.h"
+#include "wl12xx_80211.h"
+#include "wl1271_cmd.h"
+
+/*
+ * send command to firmware
+ *
+ * @wl: wl struct
+ * @id: command id
+ * @buf: buffer containing the command, must work with dma
+ * @len: length of the buffer
+ */
+int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len)
+{
+ struct wl1271_cmd_header *cmd;
+ unsigned long timeout;
+ u32 intr;
+ int ret = 0;
+
+ cmd = buf;
+ cmd->id = id;
+ cmd->status = 0;
+
+ WARN_ON(len % 4 != 0);
+
+ wl1271_spi_mem_write(wl, wl->cmd_box_addr, buf, len);
+
+ wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
+
+ timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
+
+ intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
+ if (time_after(jiffies, timeout)) {
+ wl1271_error("command complete timeout");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ msleep(1);
+
+ intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ }
+
+ wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ WL1271_ACX_INTR_CMD_COMPLETE);
+
+out:
+ return ret;
+}
+
+int wl1271_cmd_cal_channel_tune(struct wl1271 *wl)
+{
+ struct wl1271_cmd_cal_channel_tune *cmd;
+ int ret = 0;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->test.id = TEST_CMD_CHANNEL_TUNE;
+
+ cmd->band = WL1271_CHANNEL_TUNE_BAND_2_4;
+ /* set up any channel, 7 is in the middle of the range */
+ cmd->channel = 7;
+
+ ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
+ if (ret < 0)
+ wl1271_warning("TEST_CMD_CHANNEL_TUNE failed");
+
+ kfree(cmd);
+ return ret;
+}
+
+int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl)
+{
+ struct wl1271_cmd_cal_update_ref_point *cmd;
+ int ret = 0;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT;
+
+ /* FIXME: still waiting for the correct values */
+ cmd->ref_power = 0;
+ cmd->ref_detector = 0;
+
+ cmd->sub_band = WL1271_PD_REFERENCE_POINT_BAND_B_G;
+
+ ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
+ if (ret < 0)
+ wl1271_warning("TEST_CMD_UPDATE_PD_REFERENCE_POINT failed");
+
+ kfree(cmd);
+ return ret;
+}
+
+int wl1271_cmd_cal_p2g(struct wl1271 *wl)
+{
+ struct wl1271_cmd_cal_p2g *cmd;
+ int ret = 0;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->test.id = TEST_CMD_P2G_CAL;
+
+ cmd->sub_band_mask = WL1271_CAL_P2G_BAND_B_G;
+
+ ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
+ if (ret < 0)
+ wl1271_warning("TEST_CMD_P2G_CAL failed");
+
+ kfree(cmd);
+ return ret;
+}
+
+int wl1271_cmd_cal(struct wl1271 *wl)
+{
+ /*
+ * FIXME: we must make sure that we're not sleeping when calibration
+ * is done
+ */
+ int ret;
+
+ wl1271_notice("performing tx calibration");
+
+ ret = wl1271_cmd_cal_channel_tune(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_cmd_cal_update_ref_point(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_cmd_cal_p2g(wl);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
+ u16 beacon_interval, u8 wait)
+{
+ static bool do_cal = true;
+ unsigned long timeout;
+ struct wl1271_cmd_join *join;
+ int ret, i;
+ u8 *bssid;
+
+ /* FIXME: remove when we get calibration from the factory */
+ if (do_cal) {
+ ret = wl1271_cmd_cal(wl);
+ if (ret < 0)
+ wl1271_warning("couldn't calibrate");
+ else
+ do_cal = false;
+ }
+
+
+ join = kzalloc(sizeof(*join), GFP_KERNEL);
+ if (!join) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd join");
+
+ /* Reverse order BSSID */
+ bssid = (u8 *) &join->bssid_lsb;
+ for (i = 0; i < ETH_ALEN; i++)
+ bssid[i] = wl->bssid[ETH_ALEN - i - 1];
+
+ join->rx_config_options = wl->rx_config;
+ join->rx_filter_options = wl->rx_filter;
+
+ join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
+ RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
+
+ join->beacon_interval = beacon_interval;
+ join->dtim_interval = dtim_interval;
+ join->bss_type = bss_type;
+ join->channel = wl->channel;
+ join->ssid_len = wl->ssid_len;
+ memcpy(join->ssid, wl->ssid, wl->ssid_len);
+ join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH;
+
+ /* increment the session counter */
+ wl->session_counter++;
+ if (wl->session_counter >= SESSION_COUNTER_MAX)
+ wl->session_counter = 0;
+
+ join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
+
+
+ ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd join");
+ goto out_free;
+ }
+
+ timeout = msecs_to_jiffies(JOIN_TIMEOUT);
+
+ /*
+ * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
+ * simplify locking we just sleep instead, for now
+ */
+ if (wait)
+ msleep(10);
+
+out_free:
+ kfree(join);
+
+out:
+ return ret;
+}
+
+/**
+ * send test command to firmware
+ *
+ * @wl: wl struct
+ * @buf: buffer containing the command, with all headers, must work with dma
+ * @len: length of the buffer
+ * @answer: is answer needed
+ */
+int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
+{
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd test");
+
+ ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len);
+
+ if (ret < 0) {
+ wl1271_warning("TEST command failed");
+ return ret;
+ }
+
+ if (answer) {
+ struct wl1271_command *cmd_answer;
+
+ /*
+ * The test command got in, we can read the answer.
+ * The answer would be a wl1271_command, where the
+ * parameter array contains the actual answer.
+ */
+ wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
+
+ cmd_answer = buf;
+
+ if (cmd_answer->header.status != CMD_STATUS_SUCCESS)
+ wl1271_error("TEST command answer error: %d",
+ cmd_answer->header.status);
+ }
+
+ return 0;
+}
+
+/**
+ * read acx from firmware
+ *
+ * @wl: wl struct
+ * @id: acx id
+ * @buf: buffer for the response, including all headers, must work with dma
+ * @len: lenght of buf
+ */
+int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
+{
+ struct acx_header *acx = buf;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd interrogate");
+
+ acx->id = id;
+
+ /* payload length, does not include any headers */
+ acx->len = len - sizeof(*acx);
+
+ ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_error("INTERROGATE command failed");
+ goto out;
+ }
+
+ /* the interrogate command got in, we can read the answer */
+ wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, len);
+
+ acx = buf;
+ if (acx->cmd.status != CMD_STATUS_SUCCESS)
+ wl1271_error("INTERROGATE command error: %d",
+ acx->cmd.status);
+
+out:
+ return ret;
+}
+
+/**
+ * write acx value to firmware
+ *
+ * @wl: wl struct
+ * @id: acx id
+ * @buf: buffer containing acx, including all headers, must work with dma
+ * @len: length of buf
+ */
+int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
+{
+ struct acx_header *acx = buf;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd configure");
+
+ acx->id = id;
+
+ /* payload length, does not include any headers */
+ acx->len = len - sizeof(*acx);
+
+ ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len);
+ if (ret < 0) {
+ wl1271_warning("CONFIGURE command NOK");
+ return ret;
+ }
+
+ return 0;
+}
+
+int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
+{
+ struct cmd_enabledisable_path *cmd;
+ int ret;
+ u16 cmd_rx, cmd_tx;
+
+ wl1271_debug(DEBUG_CMD, "cmd data path");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->channel = channel;
+
+ if (enable) {
+ cmd_rx = CMD_ENABLE_RX;
+ cmd_tx = CMD_ENABLE_TX;
+ } else {
+ cmd_rx = CMD_DISABLE_RX;
+ cmd_tx = CMD_DISABLE_TX;
+ }
+
+ ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1271_error("rx %s cmd for channel %d failed",
+ enable ? "start" : "stop", channel);
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d",
+ enable ? "start" : "stop", channel);
+
+ ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1271_error("tx %s cmd for channel %d failed",
+ enable ? "start" : "stop", channel);
+ return ret;
+ }
+
+ wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
+ enable ? "start" : "stop", channel);
+
+out:
+ kfree(cmd);
+ return ret;
+}
+
+int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
+{
+ struct wl1271_cmd_ps_params *ps_params = NULL;
+ int ret = 0;
+
+ /* FIXME: this should be in ps.c */
+ ret = wl1271_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP,
+ wl->listen_int);
+ if (ret < 0) {
+ wl1271_error("couldn't set wake up conditions");
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd set ps mode");
+
+ ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
+ if (!ps_params) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ps_params->ps_mode = ps_mode;
+ ps_params->send_null_data = 1;
+ ps_params->retries = 5;
+ ps_params->hang_over_period = 128;
+ ps_params->null_data_rate = 1; /* 1 Mbps */
+
+ ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
+ sizeof(*ps_params));
+ if (ret < 0) {
+ wl1271_error("cmd set_ps_mode failed");
+ goto out;
+ }
+
+out:
+ kfree(ps_params);
+ return ret;
+}
+
+int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
+ size_t len)
+{
+ struct cmd_read_write_memory *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd read memory");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ WARN_ON(len > MAX_READ_SIZE);
+ len = min_t(size_t, len, MAX_READ_SIZE);
+
+ cmd->addr = addr;
+ cmd->size = len;
+
+ ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1271_error("read memory command failed: %d", ret);
+ goto out;
+ }
+
+ /* the read command got in, we can now read the answer */
+ wl1271_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
+
+ if (cmd->header.status != CMD_STATUS_SUCCESS)
+ wl1271_error("error in read command result: %d",
+ cmd->header.status);
+
+ memcpy(answer, cmd->value, len);
+
+out:
+ kfree(cmd);
+ return ret;
+}
+
+int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
+ u8 active_scan, u8 high_prio, u8 num_channels,
+ u8 probe_requests)
+{
+
+ struct wl1271_cmd_trigger_scan_to *trigger = NULL;
+ struct wl1271_cmd_scan *params = NULL;
+ int i, ret;
+ u16 scan_options = 0;
+
+ if (wl->scanning)
+ return -EINVAL;
+
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
+ params->params.rx_filter_options =
+ cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
+
+ if (!active_scan)
+ scan_options |= WL1271_SCAN_OPT_PASSIVE;
+ if (high_prio)
+ scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH;
+ params->params.scan_options = scan_options;
+
+ params->params.num_channels = num_channels;
+ params->params.num_probe_requests = probe_requests;
+ params->params.tx_rate = cpu_to_le32(RATE_MASK_2MBPS);
+ params->params.tid_trigger = 0;
+ params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
+
+ for (i = 0; i < num_channels; i++) {
+ params->channels[i].min_duration =
+ cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
+ params->channels[i].max_duration =
+ cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
+ memset(&params->channels[i].bssid_lsb, 0xff, 4);
+ memset(&params->channels[i].bssid_msb, 0xff, 2);
+ params->channels[i].early_termination = 0;
+ params->channels[i].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR;
+ params->channels[i].channel = i + 1;
+ }
+
+ if (len && ssid) {
+ params->params.ssid_len = len;
+ memcpy(params->params.ssid, ssid, len);
+ }
+
+ ret = wl1271_cmd_build_probe_req(wl, ssid, len);
+ if (ret < 0) {
+ wl1271_error("PROBE request template failed");
+ goto out;
+ }
+
+ trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
+ if (!trigger) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* disable the timeout */
+ trigger->timeout = 0;
+
+ ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
+ sizeof(*trigger));
+ if (ret < 0) {
+ wl1271_error("trigger scan to failed for hw scan");
+ goto out;
+ }
+
+ wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
+
+ wl->scanning = true;
+
+ ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
+ if (ret < 0) {
+ wl1271_error("SCAN failed");
+ goto out;
+ }
+
+ wl1271_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
+
+ if (params->header.status != CMD_STATUS_SUCCESS) {
+ wl1271_error("Scan command error: %d",
+ params->header.status);
+ wl->scanning = false;
+ ret = -EIO;
+ goto out;
+ }
+
+out:
+ kfree(params);
+ return ret;
+}
+
+int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
+ void *buf, size_t buf_len)
+{
+ struct wl1271_cmd_template_set *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id);
+
+ WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE);
+ buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE);
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->len = cpu_to_le16(buf_len);
+ cmd->template_type = template_id;
+ cmd->enabled_rates = ACX_RATE_MASK_UNSPECIFIED;
+ cmd->short_retry_limit = ACX_RATE_RETRY_LIMIT;
+ cmd->long_retry_limit = ACX_RATE_RETRY_LIMIT;
+
+ if (buf)
+ memcpy(cmd->template_data, buf, buf_len);
+
+ ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1271_warning("cmd set_template failed: %d", ret);
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+static int wl1271_build_basic_rates(char *rates)
+{
+ u8 index = 0;
+
+ rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
+ rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
+ rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
+ rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
+
+ return index;
+}
+
+static int wl1271_build_extended_rates(char *rates)
+{
+ u8 index = 0;
+
+ rates[index++] = IEEE80211_OFDM_RATE_6MB;
+ rates[index++] = IEEE80211_OFDM_RATE_9MB;
+ rates[index++] = IEEE80211_OFDM_RATE_12MB;
+ rates[index++] = IEEE80211_OFDM_RATE_18MB;
+ rates[index++] = IEEE80211_OFDM_RATE_24MB;
+ rates[index++] = IEEE80211_OFDM_RATE_36MB;
+ rates[index++] = IEEE80211_OFDM_RATE_48MB;
+ rates[index++] = IEEE80211_OFDM_RATE_54MB;
+
+ return index;
+}
+
+int wl1271_cmd_build_null_data(struct wl1271 *wl)
+{
+ struct wl12xx_null_data_template template;
+
+ if (!is_zero_ether_addr(wl->bssid)) {
+ memcpy(template.header.da, wl->bssid, ETH_ALEN);
+ memcpy(template.header.bssid, wl->bssid, ETH_ALEN);
+ } else {
+ memset(template.header.da, 0xff, ETH_ALEN);
+ memset(template.header.bssid, 0xff, ETH_ALEN);
+ }
+
+ memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
+ template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ IEEE80211_STYPE_NULLFUNC);
+
+ return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template,
+ sizeof(template));
+
+}
+
+int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
+{
+ struct wl12xx_ps_poll_template template;
+
+ memcpy(template.bssid, wl->bssid, ETH_ALEN);
+ memcpy(template.ta, wl->mac_addr, ETH_ALEN);
+ template.aid = aid;
+ template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
+
+ return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template,
+ sizeof(template));
+
+}
+
+int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len)
+{
+ struct wl12xx_probe_req_template template;
+ struct wl12xx_ie_rates *rates;
+ char *ptr;
+ u16 size;
+
+ ptr = (char *)&template;
+ size = sizeof(struct ieee80211_header);
+
+ memset(template.header.da, 0xff, ETH_ALEN);
+ memset(template.header.bssid, 0xff, ETH_ALEN);
+ memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
+ template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+
+ /* IEs */
+ /* SSID */
+ template.ssid.header.id = WLAN_EID_SSID;
+ template.ssid.header.len = ssid_len;
+ if (ssid_len && ssid)
+ memcpy(template.ssid.ssid, ssid, ssid_len);
+ size += sizeof(struct wl12xx_ie_header) + ssid_len;
+ ptr += size;
+
+ /* Basic Rates */
+ rates = (struct wl12xx_ie_rates *)ptr;
+ rates->header.id = WLAN_EID_SUPP_RATES;
+ rates->header.len = wl1271_build_basic_rates(rates->rates);
+ size += sizeof(struct wl12xx_ie_header) + rates->header.len;
+ ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;
+
+ /* Extended rates */
+ rates = (struct wl12xx_ie_rates *)ptr;
+ rates->header.id = WLAN_EID_EXT_SUPP_RATES;
+ rates->header.len = wl1271_build_extended_rates(rates->rates);
+ size += sizeof(struct wl12xx_ie_header) + rates->header.len;
+
+ wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
+
+ return wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
+ &template, size);
+}
+
+int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
+{
+ struct wl1271_cmd_set_keys *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id);
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->id = id;
+ cmd->key_action = KEY_SET_ID;
+ cmd->key_type = KEY_WEP;
+
+ ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1271_warning("cmd set_default_wep_key failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(cmd);
+
+ return ret;
+}
+
+int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
+ u8 key_size, const u8 *key, const u8 *addr)
+{
+ struct wl1271_cmd_set_keys *cmd;
+ int ret = 0;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (key_type != KEY_WEP)
+ memcpy(cmd->addr, addr, ETH_ALEN);
+
+ cmd->key_action = action;
+ cmd->key_size = key_size;
+ cmd->key_type = key_type;
+
+ /* we have only one SSID profile */
+ cmd->ssid_profile = 0;
+
+ cmd->id = id;
+
+ /* FIXME: this is from wl1251, needs to be checked */
+ if (key_type == KEY_TKIP) {
+ /*
+ * We get the key in the following form:
+ * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
+ * but the target is expecting:
+ * TKIP - RX MIC - TX MIC
+ */
+ memcpy(cmd->key, key, 16);
+ memcpy(cmd->key + 16, key + 24, 8);
+ memcpy(cmd->key + 24, key + 16, 8);
+
+ } else {
+ memcpy(cmd->key, key, key_size);
+ }
+
+ wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd));
+
+ ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1271_warning("could not set keys");
+ goto out;
+ }
+
+out:
+ kfree(cmd);
+
+ return ret;
+}
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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_CMD_H__
+#define __WL1271_CMD_H__
+
+#include "wl1271.h"
+
+struct acx_header;
+
+int wl1271_cmd_send(struct wl1271 *wl, u16 type, void *buf, size_t buf_len);
+int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
+ u16 beacon_interval, u8 wait);
+int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
+int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
+int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
+int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable);
+int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
+int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
+ size_t len);
+int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
+ u8 active_scan, u8 high_prio, u8 num_channels,
+ u8 probe_requests);
+int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
+ void *buf, size_t buf_len);
+int wl1271_cmd_build_null_data(struct wl1271 *wl);
+int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid);
+int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len);
+int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id);
+int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
+ u8 key_size, const u8 *key, const u8 *addr);
+
+enum wl1271_commands {
+ CMD_INTERROGATE = 1, /*use this to read information elements*/
+ CMD_CONFIGURE = 2, /*use this to write information elements*/
+ CMD_ENABLE_RX = 3,
+ CMD_ENABLE_TX = 4,
+ CMD_DISABLE_RX = 5,
+ CMD_DISABLE_TX = 6,
+ CMD_SCAN = 8,
+ CMD_STOP_SCAN = 9,
+ CMD_START_JOIN = 11,
+ CMD_SET_KEYS = 12,
+ CMD_READ_MEMORY = 13,
+ CMD_WRITE_MEMORY = 14,
+ CMD_SET_TEMPLATE = 19,
+ CMD_TEST = 23,
+ CMD_NOISE_HIST = 28,
+ CMD_LNA_CONTROL = 32,
+ CMD_SET_BCN_MODE = 33,
+ CMD_MEASUREMENT = 34,
+ CMD_STOP_MEASUREMENT = 35,
+ CMD_DISCONNECT = 36,
+ CMD_SET_PS_MODE = 37,
+ CMD_CHANNEL_SWITCH = 38,
+ CMD_STOP_CHANNEL_SWICTH = 39,
+ CMD_AP_DISCOVERY = 40,
+ CMD_STOP_AP_DISCOVERY = 41,
+ CMD_SPS_SCAN = 42,
+ CMD_STOP_SPS_SCAN = 43,
+ CMD_HEALTH_CHECK = 45,
+ CMD_DEBUG = 46,
+ CMD_TRIGGER_SCAN_TO = 47,
+ CMD_CONNECTION_SCAN_CFG = 48,
+ CMD_CONNECTION_SCAN_SSID_CFG = 49,
+ CMD_START_PERIODIC_SCAN = 50,
+ CMD_STOP_PERIODIC_SCAN = 51,
+ CMD_SET_STA_STATE = 52,
+
+ NUM_COMMANDS,
+ MAX_COMMAND_ID = 0xFFFF,
+};
+
+#define MAX_CMD_PARAMS 572
+
+enum cmd_templ {
+ CMD_TEMPL_NULL_DATA = 0,
+ CMD_TEMPL_BEACON,
+ CMD_TEMPL_CFG_PROBE_REQ_2_4,
+ CMD_TEMPL_CFG_PROBE_REQ_5,
+ CMD_TEMPL_PROBE_RESPONSE,
+ CMD_TEMPL_QOS_NULL_DATA,
+ CMD_TEMPL_PS_POLL,
+ CMD_TEMPL_KLV,
+ CMD_TEMPL_DISCONNECT,
+ CMD_TEMPL_PROBE_REQ_2_4, /* for firmware internal use only */
+ CMD_TEMPL_PROBE_REQ_5, /* for firmware internal use only */
+ CMD_TEMPL_BAR, /* for firmware internal use only */
+ CMD_TEMPL_CTS, /*
+ * For CTS-to-self (FastCTS) mechanism
+ * for BT/WLAN coexistence (SoftGemini). */
+ CMD_TEMPL_MAX = 0xff
+};
+
+/* unit ms */
+#define WL1271_COMMAND_TIMEOUT 2000
+#define WL1271_CMD_TEMPL_MAX_SIZE 252
+
+struct wl1271_cmd_header {
+ u16 id;
+ u16 status;
+ /* payload */
+ u8 data[0];
+} __attribute__ ((packed));
+
+#define WL1271_CMD_MAX_PARAMS 572
+
+struct wl1271_command {
+ struct wl1271_cmd_header header;
+ u8 parameters[WL1271_CMD_MAX_PARAMS];
+} __attribute__ ((packed));
+
+enum {
+ CMD_MAILBOX_IDLE = 0,
+ CMD_STATUS_SUCCESS = 1,
+ CMD_STATUS_UNKNOWN_CMD = 2,
+ CMD_STATUS_UNKNOWN_IE = 3,
+ CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11,
+ CMD_STATUS_RX_BUSY = 13,
+ CMD_STATUS_INVALID_PARAM = 14,
+ CMD_STATUS_TEMPLATE_TOO_LARGE = 15,
+ CMD_STATUS_OUT_OF_MEMORY = 16,
+ CMD_STATUS_STA_TABLE_FULL = 17,
+ CMD_STATUS_RADIO_ERROR = 18,
+ CMD_STATUS_WRONG_NESTING = 19,
+ CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/
+ CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/
+ MAX_COMMAND_STATUS = 0xff
+};
+
+
+/*
+ * CMD_READ_MEMORY
+ *
+ * The host issues this command to read the WiLink device memory/registers.
+ *
+ * Note: The Base Band address has special handling (16 bits registers and
+ * addresses). For more information, see the hardware specification.
+ */
+/*
+ * CMD_WRITE_MEMORY
+ *
+ * The host issues this command to write the WiLink device memory/registers.
+ *
+ * The Base Band address has special handling (16 bits registers and
+ * addresses). For more information, see the hardware specification.
+ */
+#define MAX_READ_SIZE 256
+
+struct cmd_read_write_memory {
+ struct wl1271_cmd_header header;
+
+ /* The address of the memory to read from or write to.*/
+ u32 addr;
+
+ /* The amount of data in bytes to read from or write to the WiLink
+ * device.*/
+ u32 size;
+
+ /* The actual value read from or written to the Wilink. The source
+ of this field is the Host in WRITE command or the Wilink in READ
+ command. */
+ u8 value[MAX_READ_SIZE];
+};
+
+#define CMDMBOX_HEADER_LEN 4
+#define CMDMBOX_INFO_ELEM_HEADER_LEN 4
+
+enum {
+ BSS_TYPE_IBSS = 0,
+ BSS_TYPE_STA_BSS = 2,
+ BSS_TYPE_AP_BSS = 3,
+ MAX_BSS_TYPE = 0xFF
+};
+
+#define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */
+#define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1
+
+struct wl1271_cmd_join {
+ struct wl1271_cmd_header header;
+
+ u32 bssid_lsb;
+ u16 bssid_msb;
+ u16 beacon_interval; /* in TBTTs */
+ u32 rx_config_options;
+ u32 rx_filter_options;
+
+ /*
+ * The target uses this field to determine the rate at
+ * which to transmit control frame responses (such as
+ * ACK or CTS frames).
+ */
+ u32 basic_rate_set;
+ u8 dtim_interval;
+ /*
+ * bits 0-2: This bitwise field specifies the type
+ * of BSS to start or join (BSS_TYPE_*).
+ * bit 4: Band - The radio band in which to join
+ * or start.
+ * 0 - 2.4GHz band
+ * 1 - 5GHz band
+ * bits 3, 5-7: Reserved
+ */
+ u8 bss_type;
+ u8 channel;
+ u8 ssid_len;
+ u8 ssid[IW_ESSID_MAX_SIZE];
+ u8 ctrl; /* JOIN_CMD_CTRL_* */
+ u8 reserved[3];
+} __attribute__ ((packed));
+
+struct cmd_enabledisable_path {
+ struct wl1271_cmd_header header;
+
+ u8 channel;
+ u8 padding[3];
+} __attribute__ ((packed));
+
+struct wl1271_cmd_template_set {
+ struct wl1271_cmd_header header;
+
+ u16 len;
+ u8 template_type;
+ u8 index; /* relevant only for KLV_TEMPLATE type */
+ u32 enabled_rates;
+ u8 short_retry_limit;
+ u8 long_retry_limit;
+ u8 aflags;
+ u8 reserved;
+ u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE];
+} __attribute__ ((packed));
+
+#define TIM_ELE_ID 5
+#define PARTIAL_VBM_MAX 251
+
+struct wl1271_tim {
+ u8 identity;
+ u8 length;
+ u8 dtim_count;
+ u8 dtim_period;
+ u8 bitmap_ctrl;
+ u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
+} __attribute__ ((packed));
+
+enum wl1271_cmd_ps_mode {
+ STATION_ACTIVE_MODE,
+ STATION_POWER_SAVE_MODE
+};
+
+struct wl1271_cmd_ps_params {
+ struct wl1271_cmd_header header;
+
+ u8 ps_mode; /* STATION_* */
+ u8 send_null_data; /* Do we have to send NULL data packet ? */
+ u8 retries; /* Number of retires for the initial NULL data packet */
+
+ /*
+ * TUs during which the target stays awake after switching
+ * to power save mode.
+ */
+ u8 hang_over_period;
+ u32 null_data_rate;
+} __attribute__ ((packed));
+
+/* HW encryption keys */
+#define NUM_ACCESS_CATEGORIES_COPY 4
+#define MAX_KEY_SIZE 32
+
+/* When set, disable HW encryption */
+#define DF_ENCRYPTION_DISABLE 0x01
+/* When set, disable HW decryption */
+#define DF_SNIFF_MODE_ENABLE 0x80
+
+enum wl1271_cmd_key_action {
+ KEY_ADD_OR_REPLACE = 1,
+ KEY_REMOVE = 2,
+ KEY_SET_ID = 3,
+ MAX_KEY_ACTION = 0xffff,
+};
+
+enum wl1271_cmd_key_type {
+ KEY_NONE = 0,
+ KEY_WEP = 1,
+ KEY_TKIP = 2,
+ KEY_AES = 3,
+ KEY_GEM = 4
+};
+
+/* FIXME: Add description for key-types */
+
+struct wl1271_cmd_set_keys {
+ struct wl1271_cmd_header header;
+
+ /* Ignored for default WEP key */
+ u8 addr[ETH_ALEN];
+
+ /* key_action_e */
+ u16 key_action;
+
+ u16 reserved_1;
+
+ /* key size in bytes */
+ u8 key_size;
+
+ /* key_type_e */
+ u8 key_type;
+ u8 ssid_profile;
+
+ /*
+ * TKIP, AES: frame's key id field.
+ * For WEP default key: key id;
+ */
+ u8 id;
+ u8 reserved_2[6];
+ u8 key[MAX_KEY_SIZE];
+ u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
+ u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
+} __attribute__ ((packed));
+
+
+#define WL1271_SCAN_MAX_CHANNELS 24
+#define WL1271_SCAN_DEFAULT_TAG 1
+#define WL1271_SCAN_CURRENT_TX_PWR 0
+#define WL1271_SCAN_OPT_ACTIVE 0
+#define WL1271_SCAN_OPT_PASSIVE 1
+#define WL1271_SCAN_OPT_PRIORITY_HIGH 4
+#define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */
+#define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */
+
+struct basic_scan_params {
+ u32 rx_config_options;
+ u32 rx_filter_options;
+ /* Scan option flags (WL1271_SCAN_OPT_*) */
+ u16 scan_options;
+ /* Number of scan channels in the list (maximum 30) */
+ u8 num_channels;
+ /* This field indicates the number of probe requests to send
+ per channel for an active scan */
+ u8 num_probe_requests;
+ /* Rate bit field for sending the probes */
+ u32 tx_rate;
+ u8 tid_trigger;
+ u8 ssid_len;
+ /* in order to align */
+ u8 padding1[2];
+ u8 ssid[IW_ESSID_MAX_SIZE];
+ /* Band to scan */
+ u8 band;
+ u8 use_ssid_list;
+ u8 scan_tag;
+ u8 padding2;
+} __attribute__ ((packed));
+
+struct basic_scan_channel_params {
+ /* Duration in TU to wait for frames on a channel for active scan */
+ u32 min_duration;
+ u32 max_duration;
+ u32 bssid_lsb;
+ u16 bssid_msb;
+ u8 early_termination;
+ u8 tx_power_att;
+ u8 channel;
+ /* FW internal use only! */
+ u8 dfs_candidate;
+ u8 activity_detected;
+ u8 pad;
+} __attribute__ ((packed));
+
+struct wl1271_cmd_scan {
+ struct wl1271_cmd_header header;
+
+ struct basic_scan_params params;
+ struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
+} __attribute__ ((packed));
+
+struct wl1271_cmd_trigger_scan_to {
+ struct wl1271_cmd_header header;
+
+ u32 timeout;
+};
+
+struct wl1271_cmd_test_header {
+ u8 id;
+ u8 padding[3];
+};
+
+enum wl1271_channel_tune_bands {
+ WL1271_CHANNEL_TUNE_BAND_2_4,
+ WL1271_CHANNEL_TUNE_BAND_5,
+ WL1271_CHANNEL_TUNE_BAND_4_9
+};
+
+#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0
+
+#define TEST_CMD_P2G_CAL 0x02
+#define TEST_CMD_CHANNEL_TUNE 0x0d
+#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d
+
+struct wl1271_cmd_cal_channel_tune {
+ struct wl1271_cmd_header header;
+
+ struct wl1271_cmd_test_header test;
+
+ u8 band;
+ u8 channel;
+
+ u16 radio_status;
+} __attribute__ ((packed));
+
+struct wl1271_cmd_cal_update_ref_point {
+ struct wl1271_cmd_header header;
+
+ struct wl1271_cmd_test_header test;
+
+ s32 ref_power;
+ s32 ref_detector;
+ u8 sub_band;
+ u8 padding[3];
+} __attribute__ ((packed));
+
+#define MAX_TLV_LENGTH 400
+#define MAX_NVS_VERSION_LENGTH 12
+
+#define WL1271_CAL_P2G_BAND_B_G BIT(0)
+
+struct wl1271_cmd_cal_p2g {
+ struct wl1271_cmd_header header;
+
+ struct wl1271_cmd_test_header test;
+
+ u16 len;
+ u8 buf[MAX_TLV_LENGTH];
+ u8 type;
+ u8 padding;
+
+ s16 radio_status;
+ u8 nvs_version[MAX_NVS_VERSION_LENGTH];
+
+ u8 sub_band_mask;
+ u8 padding2;
+} __attribute__ ((packed));
+
+#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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "wl1271_debugfs.h"
+
+#include <linux/skbuff.h>
+
+#include "wl1271.h"
+#include "wl1271_acx.h"
+#include "wl1271_ps.h"
+
+/* ms */
+#define WL1271_DEBUGFS_STATS_LIFETIME 1000
+
+/* debugfs macros idea from mac80211 */
+
+#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \
+static ssize_t name## _read(struct file *file, char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ struct wl1271 *wl = file->private_data; \
+ char buf[buflen]; \
+ int res; \
+ \
+ res = scnprintf(buf, buflen, fmt "\n", ##value); \
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
+} \
+ \
+static const struct file_operations name## _ops = { \
+ .read = name## _read, \
+ .open = wl1271_open_file_generic, \
+};
+
+#define DEBUGFS_ADD(name, parent) \
+ wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \
+ wl, &name## _ops); \
+ if (IS_ERR(wl->debugfs.name)) { \
+ ret = PTR_ERR(wl->debugfs.name); \
+ wl->debugfs.name = NULL; \
+ goto out; \
+ }
+
+#define DEBUGFS_DEL(name) \
+ do { \
+ debugfs_remove(wl->debugfs.name); \
+ wl->debugfs.name = NULL; \
+ } while (0)
+
+#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \
+static ssize_t sub## _ ##name## _read(struct file *file, \
+ char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ struct wl1271 *wl = file->private_data; \
+ char buf[buflen]; \
+ int res; \
+ \
+ wl1271_debugfs_update_stats(wl); \
+ \
+ res = scnprintf(buf, buflen, fmt "\n", \
+ wl->stats.fw_stats->sub.name); \
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
+} \
+ \
+static const struct file_operations sub## _ ##name## _ops = { \
+ .read = sub## _ ##name## _read, \
+ .open = wl1271_open_file_generic, \
+};
+
+#define DEBUGFS_FWSTATS_ADD(sub, name) \
+ DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics)
+
+#define DEBUGFS_FWSTATS_DEL(sub, name) \
+ DEBUGFS_DEL(sub## _ ##name)
+
+static void wl1271_debugfs_update_stats(struct wl1271 *wl)
+{
+ int ret;
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
+ if (wl->state == WL1271_STATE_ON &&
+ time_after(jiffies, wl->stats.fw_stats_update +
+ msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) {
+ wl1271_acx_statistics(wl, wl->stats.fw_stats);
+ wl->stats.fw_stats_update = jiffies;
+ }
+
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+static int wl1271_open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u");
+
+DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u");
+DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u");
+DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u");
+DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u");
+DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u");
+DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u");
+DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u");
+DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u");
+
+DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u");
+DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u");
+DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u");
+DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u");
+
+DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u");
+DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u");
+
+DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u");
+DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u");
+/* skipping wep.reserved */
+DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u");
+DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u");
+DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u");
+DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u");
+
+DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u");
+/* skipping cont_miss_bcns_spread for now */
+DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u");
+
+DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u");
+DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u");
+
+DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u");
+DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u");
+DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u");
+DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u");
+DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u");
+DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u");
+
+DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u");
+DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u");
+DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u");
+DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u");
+DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u");
+DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u");
+DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u");
+DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u");
+
+DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u");
+DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u");
+DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u");
+DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u");
+DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u");
+DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u");
+DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u");
+
+DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u");
+DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u");
+DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data,
+ 20, "%u");
+DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u");
+DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u");
+
+DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count);
+DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u",
+ wl->stats.excessive_retries);
+
+static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ u32 queue_len;
+ char buf[20];
+ int res;
+
+ queue_len = skb_queue_len(&wl->tx_queue);
+
+ res = scnprintf(buf, sizeof(buf), "%u\n", queue_len);
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+
+static const struct file_operations tx_queue_len_ops = {
+ .read = tx_queue_len_read,
+ .open = wl1271_open_file_generic,
+};
+
+static void wl1271_debugfs_delete_files(struct wl1271 *wl)
+{
+ DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
+
+ DEBUGFS_FWSTATS_DEL(rx, out_of_mem);
+ DEBUGFS_FWSTATS_DEL(rx, hdr_overflow);
+ DEBUGFS_FWSTATS_DEL(rx, hw_stuck);
+ DEBUGFS_FWSTATS_DEL(rx, dropped);
+ DEBUGFS_FWSTATS_DEL(rx, fcs_err);
+ DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig);
+ DEBUGFS_FWSTATS_DEL(rx, path_reset);
+ DEBUGFS_FWSTATS_DEL(rx, reset_counter);
+
+ DEBUGFS_FWSTATS_DEL(dma, rx_requested);
+ DEBUGFS_FWSTATS_DEL(dma, rx_errors);
+ DEBUGFS_FWSTATS_DEL(dma, tx_requested);
+ DEBUGFS_FWSTATS_DEL(dma, tx_errors);
+
+ DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt);
+ DEBUGFS_FWSTATS_DEL(isr, fiqs);
+ DEBUGFS_FWSTATS_DEL(isr, rx_headers);
+ DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow);
+ DEBUGFS_FWSTATS_DEL(isr, rx_rdys);
+ DEBUGFS_FWSTATS_DEL(isr, irqs);
+ DEBUGFS_FWSTATS_DEL(isr, tx_procs);
+ DEBUGFS_FWSTATS_DEL(isr, decrypt_done);
+ DEBUGFS_FWSTATS_DEL(isr, dma0_done);
+ DEBUGFS_FWSTATS_DEL(isr, dma1_done);
+ DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete);
+ DEBUGFS_FWSTATS_DEL(isr, commands);
+ DEBUGFS_FWSTATS_DEL(isr, rx_procs);
+ DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes);
+ DEBUGFS_FWSTATS_DEL(isr, host_acknowledges);
+ DEBUGFS_FWSTATS_DEL(isr, pci_pm);
+ DEBUGFS_FWSTATS_DEL(isr, wakeups);
+ DEBUGFS_FWSTATS_DEL(isr, low_rssi);
+
+ DEBUGFS_FWSTATS_DEL(wep, addr_key_count);
+ DEBUGFS_FWSTATS_DEL(wep, default_key_count);
+ /* skipping wep.reserved */
+ DEBUGFS_FWSTATS_DEL(wep, key_not_found);
+ DEBUGFS_FWSTATS_DEL(wep, decrypt_fail);
+ DEBUGFS_FWSTATS_DEL(wep, packets);
+ DEBUGFS_FWSTATS_DEL(wep, interrupt);
+
+ DEBUGFS_FWSTATS_DEL(pwr, ps_enter);
+ DEBUGFS_FWSTATS_DEL(pwr, elp_enter);
+ DEBUGFS_FWSTATS_DEL(pwr, missing_bcns);
+ DEBUGFS_FWSTATS_DEL(pwr, wake_on_host);
+ DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp);
+ DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps);
+ DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps);
+ DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons);
+ DEBUGFS_FWSTATS_DEL(pwr, power_save_off);
+ DEBUGFS_FWSTATS_DEL(pwr, enable_ps);
+ DEBUGFS_FWSTATS_DEL(pwr, disable_ps);
+ DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps);
+ /* skipping cont_miss_bcns_spread for now */
+ DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons);
+
+ DEBUGFS_FWSTATS_DEL(mic, rx_pkts);
+ DEBUGFS_FWSTATS_DEL(mic, calc_failure);
+
+ DEBUGFS_FWSTATS_DEL(aes, encrypt_fail);
+ DEBUGFS_FWSTATS_DEL(aes, decrypt_fail);
+ DEBUGFS_FWSTATS_DEL(aes, encrypt_packets);
+ DEBUGFS_FWSTATS_DEL(aes, decrypt_packets);
+ DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt);
+ DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt);
+
+ DEBUGFS_FWSTATS_DEL(event, heart_beat);
+ DEBUGFS_FWSTATS_DEL(event, calibration);
+ DEBUGFS_FWSTATS_DEL(event, rx_mismatch);
+ DEBUGFS_FWSTATS_DEL(event, rx_mem_empty);
+ DEBUGFS_FWSTATS_DEL(event, rx_pool);
+ DEBUGFS_FWSTATS_DEL(event, oom_late);
+ DEBUGFS_FWSTATS_DEL(event, phy_transmit_error);
+ DEBUGFS_FWSTATS_DEL(event, tx_stuck);
+
+ DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts);
+ DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts);
+ DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime);
+ DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn);
+ DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn);
+ DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization);
+ DEBUGFS_FWSTATS_DEL(ps, upsd_utilization);
+
+ DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop);
+ DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data);
+ DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data);
+ DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data);
+ DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data);
+
+ DEBUGFS_DEL(tx_queue_len);
+ DEBUGFS_DEL(retry_count);
+ DEBUGFS_DEL(excessive_retries);
+}
+
+static int wl1271_debugfs_add_files(struct wl1271 *wl)
+{
+ int ret = 0;
+
+ DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow);
+
+ DEBUGFS_FWSTATS_ADD(rx, out_of_mem);
+ DEBUGFS_FWSTATS_ADD(rx, hdr_overflow);
+ DEBUGFS_FWSTATS_ADD(rx, hw_stuck);
+ DEBUGFS_FWSTATS_ADD(rx, dropped);
+ DEBUGFS_FWSTATS_ADD(rx, fcs_err);
+ DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig);
+ DEBUGFS_FWSTATS_ADD(rx, path_reset);
+ DEBUGFS_FWSTATS_ADD(rx, reset_counter);
+
+ DEBUGFS_FWSTATS_ADD(dma, rx_requested);
+ DEBUGFS_FWSTATS_ADD(dma, rx_errors);
+ DEBUGFS_FWSTATS_ADD(dma, tx_requested);
+ DEBUGFS_FWSTATS_ADD(dma, tx_errors);
+
+ DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt);
+ DEBUGFS_FWSTATS_ADD(isr, fiqs);
+ DEBUGFS_FWSTATS_ADD(isr, rx_headers);
+ DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow);
+ DEBUGFS_FWSTATS_ADD(isr, rx_rdys);
+ DEBUGFS_FWSTATS_ADD(isr, irqs);
+ DEBUGFS_FWSTATS_ADD(isr, tx_procs);
+ DEBUGFS_FWSTATS_ADD(isr, decrypt_done);
+ DEBUGFS_FWSTATS_ADD(isr, dma0_done);
+ DEBUGFS_FWSTATS_ADD(isr, dma1_done);
+ DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete);
+ DEBUGFS_FWSTATS_ADD(isr, commands);
+ DEBUGFS_FWSTATS_ADD(isr, rx_procs);
+ DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes);
+ DEBUGFS_FWSTATS_ADD(isr, host_acknowledges);
+ DEBUGFS_FWSTATS_ADD(isr, pci_pm);
+ DEBUGFS_FWSTATS_ADD(isr, wakeups);
+ DEBUGFS_FWSTATS_ADD(isr, low_rssi);
+
+ DEBUGFS_FWSTATS_ADD(wep, addr_key_count);
+ DEBUGFS_FWSTATS_ADD(wep, default_key_count);
+ /* skipping wep.reserved */
+ DEBUGFS_FWSTATS_ADD(wep, key_not_found);
+ DEBUGFS_FWSTATS_ADD(wep, decrypt_fail);
+ DEBUGFS_FWSTATS_ADD(wep, packets);
+ DEBUGFS_FWSTATS_ADD(wep, interrupt);
+
+ DEBUGFS_FWSTATS_ADD(pwr, ps_enter);
+ DEBUGFS_FWSTATS_ADD(pwr, elp_enter);
+ DEBUGFS_FWSTATS_ADD(pwr, missing_bcns);
+ DEBUGFS_FWSTATS_ADD(pwr, wake_on_host);
+ DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp);
+ DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps);
+ DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps);
+ DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons);
+ DEBUGFS_FWSTATS_ADD(pwr, power_save_off);
+ DEBUGFS_FWSTATS_ADD(pwr, enable_ps);
+ DEBUGFS_FWSTATS_ADD(pwr, disable_ps);
+ DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps);
+ /* skipping cont_miss_bcns_spread for now */
+ DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons);
+
+ DEBUGFS_FWSTATS_ADD(mic, rx_pkts);
+ DEBUGFS_FWSTATS_ADD(mic, calc_failure);
+
+ DEBUGFS_FWSTATS_ADD(aes, encrypt_fail);
+ DEBUGFS_FWSTATS_ADD(aes, decrypt_fail);
+ DEBUGFS_FWSTATS_ADD(aes, encrypt_packets);
+ DEBUGFS_FWSTATS_ADD(aes, decrypt_packets);
+ DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt);
+ DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt);
+
+ DEBUGFS_FWSTATS_ADD(event, heart_beat);
+ DEBUGFS_FWSTATS_ADD(event, calibration);
+ DEBUGFS_FWSTATS_ADD(event, rx_mismatch);
+ DEBUGFS_FWSTATS_ADD(event, rx_mem_empty);
+ DEBUGFS_FWSTATS_ADD(event, rx_pool);
+ DEBUGFS_FWSTATS_ADD(event, oom_late);
+ DEBUGFS_FWSTATS_ADD(event, phy_transmit_error);
+ DEBUGFS_FWSTATS_ADD(event, tx_stuck);
+
+ DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts);
+ DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts);
+ DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime);
+ DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn);
+ DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn);
+ DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization);
+ DEBUGFS_FWSTATS_ADD(ps, upsd_utilization);
+
+ DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop);
+ DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data);
+ DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data);
+ DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data);
+ DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
+
+ DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir);
+ DEBUGFS_ADD(retry_count, wl->debugfs.rootdir);
+ DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir);
+
+out:
+ if (ret < 0)
+ wl1271_debugfs_delete_files(wl);
+
+ return ret;
+}
+
+void wl1271_debugfs_reset(struct wl1271 *wl)
+{
+ memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
+ wl->stats.retry_count = 0;
+ wl->stats.excessive_retries = 0;
+}
+
+int wl1271_debugfs_init(struct wl1271 *wl)
+{
+ int ret;
+
+ wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+ if (IS_ERR(wl->debugfs.rootdir)) {
+ ret = PTR_ERR(wl->debugfs.rootdir);
+ wl->debugfs.rootdir = NULL;
+ goto err;
+ }
+
+ wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics",
+ wl->debugfs.rootdir);
+
+ if (IS_ERR(wl->debugfs.fw_statistics)) {
+ ret = PTR_ERR(wl->debugfs.fw_statistics);
+ wl->debugfs.fw_statistics = NULL;
+ goto err_root;
+ }
+
+ wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats),
+ GFP_KERNEL);
+
+ if (!wl->stats.fw_stats) {
+ ret = -ENOMEM;
+ goto err_fw;
+ }
+
+ wl->stats.fw_stats_update = jiffies;
+
+ ret = wl1271_debugfs_add_files(wl);
+
+ if (ret < 0)
+ goto err_file;
+
+ return 0;
+
+err_file:
+ kfree(wl->stats.fw_stats);
+ wl->stats.fw_stats = NULL;
+
+err_fw:
+ debugfs_remove(wl->debugfs.fw_statistics);
+ wl->debugfs.fw_statistics = NULL;
+
+err_root:
+ debugfs_remove(wl->debugfs.rootdir);
+ wl->debugfs.rootdir = NULL;
+
+err:
+ return ret;
+}
+
+void wl1271_debugfs_exit(struct wl1271 *wl)
+{
+ wl1271_debugfs_delete_files(wl);
+
+ kfree(wl->stats.fw_stats);
+ wl->stats.fw_stats = NULL;
+
+ debugfs_remove(wl->debugfs.fw_statistics);
+ wl->debugfs.fw_statistics = NULL;
+
+ debugfs_remove(wl->debugfs.rootdir);
+ wl->debugfs.rootdir = NULL;
+
+}
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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef WL1271_DEBUGFS_H
+#define WL1271_DEBUGFS_H
+
+#include "wl1271.h"
+
+int wl1271_debugfs_init(struct wl1271 *wl);
+void wl1271_debugfs_exit(struct wl1271 *wl);
+void wl1271_debugfs_reset(struct wl1271 *wl);
+
+#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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "wl1271.h"
+#include "wl1271_reg.h"
+#include "wl1271_spi.h"
+#include "wl1271_event.h"
+#include "wl1271_ps.h"
+
+static int wl1271_event_scan_complete(struct wl1271 *wl,
+ struct event_mailbox *mbox)
+{
+ wl1271_debug(DEBUG_EVENT, "status: 0x%x",
+ mbox->scheduled_scan_status);
+
+ if (wl->scanning) {
+ mutex_unlock(&wl->mutex);
+ ieee80211_scan_completed(wl->hw, false);
+ mutex_lock(&wl->mutex);
+ wl->scanning = false;
+ }
+
+ return 0;
+}
+
+static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
+{
+ wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
+ wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
+ wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
+}
+
+static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
+{
+ int ret;
+ u32 vector;
+
+ wl1271_event_mbox_dump(mbox);
+
+ vector = mbox->events_vector & ~(mbox->events_mask);
+ wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
+
+ if (vector & SCAN_COMPLETE_EVENT_ID) {
+ ret = wl1271_event_scan_complete(wl, mbox);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (vector & BSS_LOSE_EVENT_ID) {
+ wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
+
+ if (wl->psm_requested && wl->psm) {
+ ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int wl1271_event_unmask(struct wl1271 *wl)
+{
+ int ret;
+
+ ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+void wl1271_event_mbox_config(struct wl1271 *wl)
+{
+ wl->mbox_ptr[0] = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
+
+ wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
+ wl->mbox_ptr[0], wl->mbox_ptr[1]);
+}
+
+int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
+{
+ struct event_mailbox mbox;
+ int ret;
+
+ wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
+
+ if (mbox_num > 1)
+ return -EINVAL;
+
+ /* first we read the mbox descriptor */
+ wl1271_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
+ sizeof(struct event_mailbox));
+
+ /* process the descriptor */
+ ret = wl1271_event_process(wl, &mbox);
+ if (ret < 0)
+ return ret;
+
+ /* then we let the firmware know it can go on...*/
+ wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
+
+ return 0;
+}
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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_EVENT_H__
+#define __WL1271_EVENT_H__
+
+/*
+ * Mbox events
+ *
+ * The event mechanism is based on a pair of event buffers (buffers A and
+ * B) at fixed locations in the target's memory. The host processes one
+ * buffer while the other buffer continues to collect events. If the host
+ * is not processing events, an interrupt is issued to signal that a buffer
+ * is ready. Once the host is done with processing events from one buffer,
+ * it signals the target (with an ACK interrupt) that the event buffer is
+ * free.
+ */
+
+enum {
+ MEASUREMENT_START_EVENT_ID = BIT(8),
+ MEASUREMENT_COMPLETE_EVENT_ID = BIT(9),
+ SCAN_COMPLETE_EVENT_ID = BIT(10),
+ SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(11),
+ AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12),
+ PS_REPORT_EVENT_ID = BIT(13),
+ PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14),
+ DISCONNECT_EVENT_COMPLETE_ID = BIT(15),
+ JOIN_EVENT_COMPLETE_ID = BIT(16),
+ CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
+ BSS_LOSE_EVENT_ID = BIT(18),
+ REGAINED_BSS_EVENT_ID = BIT(19),
+ ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20),
+ SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
+ SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23),
+ SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
+ PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25),
+ DBG_EVENT_ID = BIT(26),
+ HEALTH_CHECK_REPLY_EVENT_ID = BIT(27),
+ PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28),
+ PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29),
+ BA_SESSION_TEAR_DOWN_EVENT_ID = BIT(30),
+ EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff,
+};
+
+struct event_debug_report {
+ u8 debug_event_id;
+ u8 num_params;
+ u16 pad;
+ u32 report_1;
+ u32 report_2;
+ u32 report_3;
+} __attribute__ ((packed));
+
+#define NUM_OF_RSSI_SNR_TRIGGERS 8
+
+struct event_mailbox {
+ u32 events_vector;
+ u32 events_mask;
+ u32 reserved_1;
+ u32 reserved_2;
+
+ u8 dbg_event_id;
+ u8 num_relevant_params;
+ u16 reserved_3;
+ u32 event_report_p1;
+ u32 event_report_p2;
+ u32 event_report_p3;
+
+ u8 number_of_scan_results;
+ u8 scan_tag;
+ u8 reserved_4[2];
+ u32 compl_scheduled_scan_status;
+
+ u16 scheduled_scan_attended_channels;
+ u8 soft_gemini_sense_info;
+ u8 soft_gemini_protective_info;
+ s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
+ u8 channel_switch_status;
+ u8 scheduled_scan_status;
+ u8 ps_status;
+
+ u8 reserved_5[29];
+} __attribute__ ((packed));
+
+int wl1271_event_unmask(struct wl1271 *wl);
+void wl1271_event_mbox_config(struct wl1271 *wl);
+int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
+
+#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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "wl1271_init.h"
+#include "wl12xx_80211.h"
+#include "wl1271_acx.h"
+#include "wl1271_cmd.h"
+#include "wl1271_reg.h"
+
+static int wl1271_init_hwenc_config(struct wl1271 *wl)
+{
+ int ret;
+
+ ret = wl1271_acx_feature_cfg(wl);
+ if (ret < 0) {
+ wl1271_warning("couldn't set feature config");
+ return ret;
+ }
+
+ ret = wl1271_cmd_set_default_wep_key(wl, wl->default_key);
+ if (ret < 0) {
+ wl1271_warning("couldn't set default key");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int wl1271_init_templates_config(struct wl1271 *wl)
+{
+ int ret;
+
+ /* send empty templates for fw memory reservation */
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
+ sizeof(struct wl12xx_probe_req_template));
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
+ sizeof(struct wl12xx_null_data_template));
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL,
+ sizeof(struct wl12xx_ps_poll_template));
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL,
+ sizeof
+ (struct wl12xx_qos_null_data_template));
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL,
+ sizeof
+ (struct wl12xx_probe_resp_template));
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL,
+ sizeof
+ (struct wl12xx_beacon_template));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter)
+{
+ int ret;
+
+ ret = wl1271_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_acx_rx_config(wl, config, filter);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int wl1271_init_phy_config(struct wl1271 *wl)
+{
+ int ret;
+
+ ret = wl1271_acx_pd_threshold(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_acx_slot(wl, DEFAULT_SLOT_TIME);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_acx_group_address_tbl(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_acx_service_period_timeout(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int wl1271_init_beacon_filter(struct wl1271 *wl)
+{
+ int ret;
+
+ ret = wl1271_acx_beacon_filter_opt(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_acx_beacon_filter_table(wl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int wl1271_init_pta(struct wl1271 *wl)
+{
+ int ret;
+
+ ret = wl1271_acx_sg_enable(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_acx_sg_cfg(wl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int wl1271_init_energy_detection(struct wl1271 *wl)
+{
+ int ret;
+
+ ret = wl1271_acx_cca_threshold(wl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
+{
+ int ret;
+
+ ret = wl1271_acx_bcn_dtim_options(wl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int wl1271_init_general_parms(struct wl1271 *wl)
+{
+ struct wl1271_general_parms *gen_parms;
+ int ret;
+
+ gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
+ if (!gen_parms)
+ return -ENOMEM;
+
+ gen_parms->id = TEST_CMD_INI_FILE_GENERAL_PARAM;
+
+ gen_parms->ref_clk = REF_CLK_38_4_E;
+ /* FIXME: magic numbers */
+ gen_parms->settling_time = 5;
+ gen_parms->clk_valid_on_wakeup = 0;
+ gen_parms->dc2dcmode = 0;
+ gen_parms->single_dual_band = 0;
+ gen_parms->tx_bip_fem_autodetect = 1;
+ gen_parms->tx_bip_fem_manufacturer = 1;
+ gen_parms->settings = 1;
+
+ ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
+ if (ret < 0) {
+ wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
+ return ret;
+ }
+
+ kfree(gen_parms);
+ return 0;
+}
+
+static int wl1271_init_radio_parms(struct wl1271 *wl)
+{
+ /*
+ * FIXME: All these magic numbers should be moved to some place where
+ * they can be configured (separate file?)
+ */
+
+ struct wl1271_radio_parms *radio_parms;
+ int ret;
+ u8 compensation[] = { 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, 0xfc, 0x00,
+ 0x08, 0x10, 0xf0, 0xf8, 0x00, 0x0a, 0x14 };
+
+ u8 tx_rate_limits_normal[] = { 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 };
+ u8 tx_rate_limits_degraded[] = { 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 };
+
+ u8 tx_channel_limits_11b[] = { 0x22, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x22, 0x50,
+ 0x22, 0x50 };
+
+ u8 tx_channel_limits_ofdm[] = { 0x20, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x20, 0x50,
+ 0x20, 0x50 };
+
+ u8 tx_pdv_rate_offsets[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ u8 tx_ibias[] = { 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 };
+
+ radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
+ if (!radio_parms)
+ return -ENOMEM;
+
+ radio_parms->id = TEST_CMD_INI_FILE_RADIO_PARAM;
+
+ /* Static radio parameters */
+ radio_parms->rx_trace_loss = 10;
+ radio_parms->tx_trace_loss = 10;
+ memcpy(radio_parms->rx_rssi_and_proc_compens, compensation,
+ sizeof(compensation));
+
+ /* We don't set the 5GHz -- N/A */
+
+ /* Dynamic radio parameters */
+ radio_parms->tx_ref_pd_voltage = cpu_to_le16(0x24e);
+ radio_parms->tx_ref_power = 0x78;
+ radio_parms->tx_offset_db = 0x0;
+
+ memcpy(radio_parms->tx_rate_limits_normal, tx_rate_limits_normal,
+ sizeof(tx_rate_limits_normal));
+ memcpy(radio_parms->tx_rate_limits_degraded, tx_rate_limits_degraded,
+ sizeof(tx_rate_limits_degraded));
+
+ memcpy(radio_parms->tx_channel_limits_11b, tx_channel_limits_11b,
+ sizeof(tx_channel_limits_11b));
+ memcpy(radio_parms->tx_channel_limits_ofdm, tx_channel_limits_ofdm,
+ sizeof(tx_channel_limits_ofdm));
+ memcpy(radio_parms->tx_pdv_rate_offsets, tx_pdv_rate_offsets,
+ sizeof(tx_pdv_rate_offsets));
+ memcpy(radio_parms->tx_ibias, tx_ibias,
+ sizeof(tx_ibias));
+
+ radio_parms->rx_fem_insertion_loss = 0x14;
+
+ ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
+ if (ret < 0)
+ wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
+
+ kfree(radio_parms);
+ return ret;
+}
+
+int wl1271_hw_init(struct wl1271 *wl)
+{
+ int ret;
+
+ ret = wl1271_init_general_parms(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_init_radio_parms(wl);
+ if (ret < 0)
+ return ret;
+
+ /* Template settings */
+ ret = wl1271_init_templates_config(wl);
+ if (ret < 0)
+ return ret;
+
+ /* Default memory configuration */
+ ret = wl1271_acx_init_mem_config(wl);
+ if (ret < 0)
+ return ret;
+
+ /* RX config */
+ ret = wl1271_init_rx_config(wl,
+ RX_CFG_PROMISCUOUS | RX_CFG_TSF,
+ RX_FILTER_OPTION_DEF);
+ /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
+ RX_FILTER_OPTION_FILTER_ALL); */
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* PHY layer config */
+ ret = wl1271_init_phy_config(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Beacon filtering */
+ ret = wl1271_init_beacon_filter(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Configure TX patch complete interrupt behavior */
+ ret = wl1271_acx_tx_config_options(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* RX complete interrupt pacing */
+ ret = wl1271_acx_init_rx_interrupt(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Bluetooth WLAN coexistence */
+ ret = wl1271_init_pta(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Energy detection */
+ ret = wl1271_init_energy_detection(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Beacons and boradcast settings */
+ ret = wl1271_init_beacon_broadcast(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Default fragmentation threshold */
+ ret = wl1271_acx_frag_threshold(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Default TID configuration */
+ ret = wl1271_acx_tid_cfg(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Default AC configuration */
+ ret = wl1271_acx_ac_cfg(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Configure TX rate classes */
+ ret = wl1271_acx_rate_policies(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Enable data path */
+ ret = wl1271_cmd_data_path(wl, wl->channel, 1);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Configure for ELP power saving */
+ ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Configure HW encryption */
+ ret = wl1271_init_hwenc_config(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ return 0;
+
+ out_free_memmap:
+ kfree(wl->target_mem_map);
+
+ return ret;
+}
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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_INIT_H__
+#define __WL1271_INIT_H__
+
+#include "wl1271.h"
+
+int wl1271_hw_init_power_auth(struct wl1271 *wl);
+int wl1271_hw_init(struct wl1271 *wl);
+
+/* These are not really a TEST_CMD, but the ref driver uses them as such */
+#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19
+#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E
+
+struct wl1271_general_parms {
+ u8 id;
+ u8 padding[3];
+
+ u8 ref_clk;
+ u8 settling_time;
+ u8 clk_valid_on_wakeup;
+ u8 dc2dcmode;
+ u8 single_dual_band;
+
+ u8 tx_bip_fem_autodetect;
+ u8 tx_bip_fem_manufacturer;
+ u8 settings;
+} __attribute__ ((packed));
+
+enum ref_clk_enum {
+ REF_CLK_19_2_E,
+ REF_CLK_26_E,
+ REF_CLK_38_4_E,
+ REF_CLK_52_E
+};
+
+#define RSSI_AND_PROCESS_COMPENSATION_SIZE 15
+#define NUMBER_OF_SUB_BANDS_5 7
+#define NUMBER_OF_RATE_GROUPS 6
+#define NUMBER_OF_CHANNELS_2_4 14
+#define NUMBER_OF_CHANNELS_5 35
+
+struct wl1271_radio_parms {
+ u8 id;
+ u8 padding[3];
+
+ /* Static radio parameters */
+ /* 2.4GHz */
+ u8 rx_trace_loss;
+ u8 tx_trace_loss;
+ s8 rx_rssi_and_proc_compens[RSSI_AND_PROCESS_COMPENSATION_SIZE];
+
+ /* 5GHz */
+ u8 rx_trace_loss_5[NUMBER_OF_SUB_BANDS_5];
+ u8 tx_trace_loss_5[NUMBER_OF_SUB_BANDS_5];
+ s8 rx_rssi_and_proc_compens_5[RSSI_AND_PROCESS_COMPENSATION_SIZE];
+
+ /* Dynamic radio parameters */
+ /* 2.4GHz */
+ s16 tx_ref_pd_voltage;
+ s8 tx_ref_power;
+ s8 tx_offset_db;
+
+ s8 tx_rate_limits_normal[NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_degraded[NUMBER_OF_RATE_GROUPS];
+
+ s8 tx_channel_limits_11b[NUMBER_OF_CHANNELS_2_4];
+ s8 tx_channel_limits_ofdm[NUMBER_OF_CHANNELS_2_4];
+ s8 tx_pdv_rate_offsets[NUMBER_OF_RATE_GROUPS];
+
+ u8 tx_ibias[NUMBER_OF_RATE_GROUPS];
+ u8 rx_fem_insertion_loss;
+
+ u8 padding2;
+
+ /* 5GHz */
+ s16 tx_ref_pd_voltage_5[NUMBER_OF_SUB_BANDS_5];
+ s8 tx_ref_power_5[NUMBER_OF_SUB_BANDS_5];
+ s8 tx_offset_db_5[NUMBER_OF_SUB_BANDS_5];
+
+ s8 tx_rate_limits_normal_5[NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_degraded_5[NUMBER_OF_RATE_GROUPS];
+
+ s8 tx_channel_limits_ofdm_5[NUMBER_OF_CHANNELS_5];
+ s8 tx_pdv_rate_offsets_5[NUMBER_OF_RATE_GROUPS];
+
+ /* FIXME: this is inconsistent with the types for 2.4GHz */
+ s8 tx_ibias_5[NUMBER_OF_RATE_GROUPS];
+ s8 rx_fem_insertion_loss_5[NUMBER_OF_SUB_BANDS_5];
+
+ u8 padding3[2];
+} __attribute__ ((packed));
+
+#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..d9169b47ac42
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -0,0 +1,1394 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/spi/spi.h>
+#include <linux/crc32.h>
+#include <linux/etherdevice.h>
+#include <linux/spi/wl12xx.h>
+
+#include "wl1271.h"
+#include "wl12xx_80211.h"
+#include "wl1271_reg.h"
+#include "wl1271_spi.h"
+#include "wl1271_event.h"
+#include "wl1271_tx.h"
+#include "wl1271_rx.h"
+#include "wl1271_ps.h"
+#include "wl1271_init.h"
+#include "wl1271_debugfs.h"
+#include "wl1271_cmd.h"
+#include "wl1271_boot.h"
+
+static int wl1271_plt_init(struct wl1271 *wl)
+{
+ int ret;
+
+ ret = wl1271_acx_init_mem_config(wl);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_cmd_data_path(wl, wl->channel, 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void wl1271_disable_interrupts(struct wl1271 *wl)
+{
+ disable_irq(wl->irq);
+}
+
+static void wl1271_power_off(struct wl1271 *wl)
+{
+ wl->set_power(false);
+}
+
+static void wl1271_power_on(struct wl1271 *wl)
+{
+ wl->set_power(true);
+}
+
+static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status)
+{
+ u32 total = 0;
+ int i;
+
+ /*
+ * FIXME: Reading the FW status directly from the registers seems to
+ * be the right thing to do, but it doesn't work. And in the
+ * reference driver, there is a workaround called
+ * USE_SDIO_24M_WORKAROUND, which reads the status from memory
+ * instead, so we do the same here.
+ */
+
+ wl1271_spi_mem_read(wl, STATUS_MEM_ADDRESS, status, sizeof(*status));
+
+ wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
+ "drv_rx_counter = %d, tx_results_counter = %d)",
+ status->intr,
+ status->fw_rx_counter,
+ status->drv_rx_counter,
+ status->tx_results_counter);
+
+ /* update number of available TX blocks */
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ u32 cnt = status->tx_released_blks[i] - wl->tx_blocks_freed[i];
+ wl->tx_blocks_freed[i] = status->tx_released_blks[i];
+ wl->tx_blocks_available += cnt;
+ total += cnt;
+ }
+
+ /* if more blocks are available now, schedule some tx work */
+ if (total && !skb_queue_empty(&wl->tx_queue))
+ schedule_work(&wl->tx_work);
+
+ /* update the host-chipset time offset */
+ wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime;
+}
+
+#define WL1271_IRQ_MAX_LOOPS 10
+static void wl1271_irq_work(struct work_struct *work)
+{
+ u32 intr, ctr = WL1271_IRQ_MAX_LOOPS;
+ int ret;
+ struct wl1271 *wl =
+ container_of(work, struct wl1271, irq_work);
+
+ mutex_lock(&wl->mutex);
+
+ wl1271_debug(DEBUG_IRQ, "IRQ work");
+
+ if (wl->state == WL1271_STATE_OFF)
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl, true);
+ if (ret < 0)
+ goto out;
+
+ wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+
+ intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
+ if (!intr) {
+ wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
+ goto out_sleep;
+ }
+
+ intr &= WL1271_INTR_MASK;
+
+ do {
+ wl1271_fw_status(wl, wl->fw_status);
+
+
+ if (intr & (WL1271_ACX_INTR_EVENT_A |
+ WL1271_ACX_INTR_EVENT_B)) {
+ wl1271_debug(DEBUG_IRQ,
+ "WL1271_ACX_INTR_EVENT (0x%x)", intr);
+ if (intr & WL1271_ACX_INTR_EVENT_A)
+ wl1271_event_handle(wl, 0);
+ else
+ wl1271_event_handle(wl, 1);
+ }
+
+ if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
+ wl1271_debug(DEBUG_IRQ,
+ "WL1271_ACX_INTR_INIT_COMPLETE");
+
+ if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
+
+ if (intr & WL1271_ACX_INTR_DATA) {
+ u8 tx_res_cnt = wl->fw_status->tx_results_counter -
+ wl->tx_results_count;
+
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
+
+ /* check for tx results */
+ if (tx_res_cnt)
+ wl1271_tx_complete(wl, tx_res_cnt);
+
+ wl1271_rx(wl, wl->fw_status);
+ }
+
+ intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
+ intr &= WL1271_INTR_MASK;
+ } while (intr && --ctr);
+
+out_sleep:
+ wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+ WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+static irqreturn_t wl1271_irq(int irq, void *cookie)
+{
+ struct wl1271 *wl;
+ unsigned long flags;
+
+ wl1271_debug(DEBUG_IRQ, "IRQ");
+
+ wl = cookie;
+
+ /* complete the ELP completion */
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ if (wl->elp_compl) {
+ complete(wl->elp_compl);
+ wl->elp_compl = NULL;
+ }
+
+ schedule_work(&wl->irq_work);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int wl1271_fetch_firmware(struct wl1271 *wl)
+{
+ const struct firmware *fw;
+ int ret;
+
+ ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
+
+ if (ret < 0) {
+ wl1271_error("could not get firmware: %d", ret);
+ return ret;
+ }
+
+ if (fw->size % 4) {
+ wl1271_error("firmware size is not multiple of 32 bits: %zu",
+ fw->size);
+ ret = -EILSEQ;
+ goto out;
+ }
+
+ wl->fw_len = fw->size;
+ wl->fw = kmalloc(wl->fw_len, GFP_KERNEL);
+
+ if (!wl->fw) {
+ wl1271_error("could not allocate memory for the firmware");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(wl->fw, fw->data, wl->fw_len);
+
+ ret = 0;
+
+out:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int wl1271_fetch_nvs(struct wl1271 *wl)
+{
+ const struct firmware *fw;
+ int ret;
+
+ ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
+
+ if (ret < 0) {
+ wl1271_error("could not get nvs file: %d", ret);
+ return ret;
+ }
+
+ if (fw->size % 4) {
+ wl1271_error("nvs size is not multiple of 32 bits: %zu",
+ fw->size);
+ ret = -EILSEQ;
+ goto out;
+ }
+
+ wl->nvs_len = fw->size;
+ wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
+
+ if (!wl->nvs) {
+ wl1271_error("could not allocate memory for the nvs file");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(wl->nvs, fw->data, wl->nvs_len);
+
+ ret = 0;
+
+out:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static void wl1271_fw_wakeup(struct wl1271 *wl)
+{
+ u32 elp_reg;
+
+ elp_reg = ELPCTRL_WAKE_UP;
+ wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
+}
+
+static int wl1271_setup(struct wl1271 *wl)
+{
+ wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
+ if (!wl->fw_status)
+ return -ENOMEM;
+
+ wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
+ if (!wl->tx_res_if) {
+ kfree(wl->fw_status);
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&wl->irq_work, wl1271_irq_work);
+ INIT_WORK(&wl->tx_work, wl1271_tx_work);
+ return 0;
+}
+
+static int wl1271_chip_wakeup(struct wl1271 *wl)
+{
+ int ret = 0;
+
+ wl1271_power_on(wl);
+ msleep(WL1271_POWER_ON_SLEEP);
+ wl1271_spi_reset(wl);
+ wl1271_spi_init(wl);
+
+ /* We don't need a real memory partition here, because we only want
+ * to use the registers at this point. */
+ wl1271_set_partition(wl,
+ 0x00000000,
+ 0x00000000,
+ REGISTERS_BASE,
+ REGISTERS_DOWN_SIZE);
+
+ /* ELP module wake up */
+ wl1271_fw_wakeup(wl);
+
+ /* whal_FwCtrl_BootSm() */
+
+ /* 0. read chip id from CHIP_ID */
+ wl->chip.id = wl1271_reg_read32(wl, CHIP_ID_B);
+
+ /* 1. check if chip id is valid */
+
+ switch (wl->chip.id) {
+ case CHIP_ID_1271_PG10:
+ wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
+ wl->chip.id);
+
+ ret = wl1271_setup(wl);
+ if (ret < 0)
+ goto out;
+ break;
+ case CHIP_ID_1271_PG20:
+ wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
+ wl->chip.id);
+
+ ret = wl1271_setup(wl);
+ if (ret < 0)
+ goto out;
+ break;
+ default:
+ wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (wl->fw == NULL) {
+ ret = wl1271_fetch_firmware(wl);
+ if (ret < 0)
+ goto out;
+ }
+
+ /* No NVS from netlink, try to get it from the filesystem */
+ if (wl->nvs == NULL) {
+ ret = wl1271_fetch_nvs(wl);
+ if (ret < 0)
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static void wl1271_filter_work(struct work_struct *work)
+{
+ struct wl1271 *wl =
+ container_of(work, struct wl1271, filter_work);
+ int ret;
+
+ mutex_lock(&wl->mutex);
+
+ if (wl->state == WL1271_STATE_OFF)
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
+ /* FIXME: replace the magic numbers with proper definitions */
+ ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0);
+ if (ret < 0)
+ goto out_sleep;
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+int wl1271_plt_start(struct wl1271 *wl)
+{
+ int ret;
+
+ mutex_lock(&wl->mutex);
+
+ wl1271_notice("power up");
+
+ if (wl->state != WL1271_STATE_OFF) {
+ wl1271_error("cannot go into PLT state because not "
+ "in off state: %d", wl->state);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl->state = WL1271_STATE_PLT;
+
+ ret = wl1271_chip_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_boot(wl);
+ if (ret < 0)
+ goto out;
+
+ wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
+
+ ret = wl1271_plt_init(wl);
+ if (ret < 0)
+ goto out;
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+int wl1271_plt_stop(struct wl1271 *wl)
+{
+ int ret = 0;
+
+ mutex_lock(&wl->mutex);
+
+ wl1271_notice("power down");
+
+ if (wl->state != WL1271_STATE_PLT) {
+ wl1271_error("cannot power down because not in PLT "
+ "state: %d", wl->state);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl1271_disable_interrupts(wl);
+ wl1271_power_off(wl);
+
+ wl->state = WL1271_STATE_OFF;
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+
+static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct wl1271 *wl = hw->priv;
+
+ skb_queue_tail(&wl->tx_queue, skb);
+
+ /*
+ * The chip specific setup must run before the first TX packet -
+ * before that, the tx_work will not be initialized!
+ */
+
+ schedule_work(&wl->tx_work);
+
+ /*
+ * The workqueue is slow to process the tx_queue and we need stop
+ * the queue here, otherwise the queue will get too long.
+ */
+ if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
+ ieee80211_stop_queues(wl->hw);
+
+ /*
+ * FIXME: this is racy, the variable is not properly
+ * protected. Maybe fix this by removing the stupid
+ * variable altogether and checking the real queue state?
+ */
+ wl->tx_queue_stopped = true;
+ }
+
+ return NETDEV_TX_OK;
+}
+
+static int wl1271_op_start(struct ieee80211_hw *hw)
+{
+ struct wl1271 *wl = hw->priv;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 start");
+
+ mutex_lock(&wl->mutex);
+
+ if (wl->state != WL1271_STATE_OFF) {
+ wl1271_error("cannot start because not in off state: %d",
+ wl->state);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = wl1271_chip_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_boot(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_hw_init(wl);
+ if (ret < 0)
+ goto out;
+
+ wl->state = WL1271_STATE_ON;
+
+ wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
+
+out:
+ if (ret < 0)
+ wl1271_power_off(wl);
+
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+static void wl1271_op_stop(struct ieee80211_hw *hw)
+{
+ struct wl1271 *wl = hw->priv;
+ int i;
+
+ wl1271_info("down");
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
+
+ mutex_lock(&wl->mutex);
+
+ WARN_ON(wl->state != WL1271_STATE_ON);
+
+ if (wl->scanning) {
+ mutex_unlock(&wl->mutex);
+ ieee80211_scan_completed(wl->hw, true);
+ mutex_lock(&wl->mutex);
+ wl->scanning = false;
+ }
+
+ wl->state = WL1271_STATE_OFF;
+
+ wl1271_disable_interrupts(wl);
+
+ mutex_unlock(&wl->mutex);
+
+ cancel_work_sync(&wl->irq_work);
+ cancel_work_sync(&wl->tx_work);
+ cancel_work_sync(&wl->filter_work);
+
+ mutex_lock(&wl->mutex);
+
+ /* let's notify MAC80211 about the remaining pending TX frames */
+ wl1271_tx_flush(wl);
+ wl1271_power_off(wl);
+
+ memset(wl->bssid, 0, ETH_ALEN);
+ memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
+ wl->ssid_len = 0;
+ wl->listen_int = 1;
+ wl->bss_type = MAX_BSS_TYPE;
+
+ wl->rx_counter = 0;
+ wl->elp = false;
+ wl->psm = 0;
+ wl->tx_queue_stopped = false;
+ wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
+ wl->tx_blocks_available = 0;
+ wl->tx_results_count = 0;
+ wl->tx_packets_count = 0;
+ wl->time_offset = 0;
+ wl->session_counter = 0;
+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ wl->tx_blocks_freed[i] = 0;
+
+ wl1271_debugfs_reset(wl);
+ mutex_unlock(&wl->mutex);
+}
+
+static int wl1271_op_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct wl1271 *wl = hw->priv;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
+ conf->type, conf->mac_addr);
+
+ mutex_lock(&wl->mutex);
+
+ switch (conf->type) {
+ case NL80211_IFTYPE_STATION:
+ wl->bss_type = BSS_TYPE_STA_BSS;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ wl->bss_type = BSS_TYPE_IBSS;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ /* FIXME: what if conf->mac_addr changes? */
+
+out:
+ mutex_unlock(&wl->mutex);
+ return ret;
+}
+
+static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
+}
+
+#if 0
+static int wl1271_op_config_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_if_conf *conf)
+{
+ struct wl1271 *wl = hw->priv;
+ struct sk_buff *beacon;
+ DECLARE_MAC_BUF(mac);
+ int ret;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %s",
+ print_mac(mac, conf->bssid));
+ wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
+ conf->ssid_len);
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
+ memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+
+ ret = wl1271_cmd_build_null_data(wl);
+ if (ret < 0)
+ goto out_sleep;
+
+ wl->ssid_len = conf->ssid_len;
+ if (wl->ssid_len)
+ memcpy(wl->ssid, conf->ssid, wl->ssid_len);
+
+ if (wl->bss_type != BSS_TYPE_IBSS) {
+ /* FIXME: replace the magic numbers with proper definitions */
+ ret = wl1271_cmd_join(wl, wl->bss_type, 5, 100, 1);
+ if (ret < 0)
+ goto out_sleep;
+ }
+
+ if (conf->changed & IEEE80211_IFCC_BEACON) {
+ beacon = ieee80211_beacon_get(hw, vif);
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
+ beacon->data, beacon->len);
+
+ if (ret < 0) {
+ dev_kfree_skb(beacon);
+ goto out_sleep;
+ }
+
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
+ beacon->data, beacon->len);
+
+ dev_kfree_skb(beacon);
+
+ if (ret < 0)
+ goto out_sleep;
+
+ /* FIXME: replace the magic numbers with proper definitions */
+ ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0);
+
+ if (ret < 0)
+ goto out_sleep;
+ }
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+#endif
+
+static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
+{
+ struct wl1271 *wl = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+ int channel, ret = 0;
+
+ channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
+ channel,
+ conf->flags & IEEE80211_CONF_PS ? "on" : "off",
+ conf->power_level);
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
+ if (channel != wl->channel) {
+ u8 old_channel = wl->channel;
+ wl->channel = channel;
+
+ /* FIXME: use beacon interval provided by mac80211 */
+ ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0);
+ if (ret < 0) {
+ wl->channel = old_channel;
+ goto out_sleep;
+ }
+ }
+
+ ret = wl1271_cmd_build_null_data(wl);
+ if (ret < 0)
+ goto out_sleep;
+
+ if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
+ wl1271_info("psm enabled");
+
+ wl->psm_requested = true;
+
+ /*
+ * We enter PSM only if we're already associated.
+ * If we're not, we'll enter it when joining an SSID,
+ * through the bss_info_changed() hook.
+ */
+ ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+ } else if (!(conf->flags & IEEE80211_CONF_PS) &&
+ wl->psm_requested) {
+ wl1271_info("psm disabled");
+
+ wl->psm_requested = false;
+
+ if (wl->psm)
+ ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ }
+
+ if (conf->power_level != wl->power_level) {
+ ret = wl1271_acx_tx_power(wl, conf->power_level);
+ if (ret < 0)
+ goto out;
+
+ wl->power_level = conf->power_level;
+ }
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
+ FIF_ALLMULTI | \
+ FIF_FCSFAIL | \
+ FIF_BCN_PRBRESP_PROMISC | \
+ FIF_CONTROL | \
+ FIF_OTHER_BSS)
+
+static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed,
+ unsigned int *total,u64 multicast)
+{
+ struct wl1271 *wl = hw->priv;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
+
+ *total &= WL1271_SUPPORTED_FILTERS;
+ changed &= WL1271_SUPPORTED_FILTERS;
+
+ if (changed == 0)
+ return;
+
+ /* FIXME: wl->rx_config and wl->rx_filter are not protected */
+ wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
+ wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
+
+ /*
+ * FIXME: workqueues need to be properly cancelled on stop(), for
+ * now let's just disable changing the filter settings. They will
+ * be updated any on config().
+ */
+ /* schedule_work(&wl->filter_work); */
+}
+
+static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key_conf)
+{
+ struct wl1271 *wl = hw->priv;
+ const u8 *addr;
+ int ret;
+ u8 key_type;
+
+ static const u8 bcast_addr[ETH_ALEN] =
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
+
+ addr = sta ? sta->addr : bcast_addr;
+
+ wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
+ wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
+ wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
+ key_conf->alg, key_conf->keyidx,
+ key_conf->keylen, key_conf->flags);
+ wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
+
+ if (is_zero_ether_addr(addr)) {
+ /* We dont support TX only encryption */
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out_unlock;
+
+ switch (key_conf->alg) {
+ case ALG_WEP:
+ key_type = KEY_WEP;
+
+ key_conf->hw_key_idx = key_conf->keyidx;
+ break;
+ case ALG_TKIP:
+ key_type = KEY_TKIP;
+
+ key_conf->hw_key_idx = key_conf->keyidx;
+ break;
+ case ALG_CCMP:
+ key_type = KEY_AES;
+
+ key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ break;
+ default:
+ wl1271_error("Unknown key algo 0x%x", key_conf->alg);
+
+ ret = -EOPNOTSUPP;
+ goto out_sleep;
+ }
+
+ switch (cmd) {
+ case SET_KEY:
+ ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
+ key_conf->keyidx, key_type,
+ key_conf->keylen, key_conf->key,
+ addr);
+ if (ret < 0) {
+ wl1271_error("Could not add or replace key");
+ goto out_sleep;
+ }
+ break;
+
+ case DISABLE_KEY:
+ ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
+ key_conf->keyidx, key_type,
+ key_conf->keylen, key_conf->key,
+ addr);
+ if (ret < 0) {
+ wl1271_error("Could not remove key");
+ goto out_sleep;
+ }
+ break;
+
+ default:
+ wl1271_error("Unsupported key cmd 0x%x", cmd);
+ ret = -EOPNOTSUPP;
+ goto out_sleep;
+
+ break;
+ }
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+
+out_unlock:
+ mutex_unlock(&wl->mutex);
+
+out:
+ return ret;
+}
+
+static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
+ struct cfg80211_scan_request *req)
+{
+ struct wl1271 *wl = hw->priv;
+ int ret;
+ u8 *ssid = NULL;
+ size_t ssid_len = 0;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
+
+ if (req->n_ssids) {
+ ssid = req->ssids[0].ssid;
+ ssid_len = req->ssids[0].ssid_len;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_cmd_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
+
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+ struct wl1271 *wl = hw->priv;
+ int ret;
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_acx_rts_threshold(wl, (u16) value);
+ if (ret < 0)
+ wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
+
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changed)
+{
+ enum wl1271_cmd_ps_mode mode;
+ struct wl1271 *wl = hw->priv;
+ int ret;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
+ if (changed & BSS_CHANGED_ASSOC) {
+ if (bss_conf->assoc) {
+ wl->aid = bss_conf->aid;
+
+ ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wl1271_acx_aid(wl, wl->aid);
+ if (ret < 0)
+ goto out_sleep;
+
+ /* If we want to go in PSM but we're not there yet */
+ if (wl->psm_requested && !wl->psm) {
+ mode = STATION_POWER_SAVE_MODE;
+ ret = wl1271_ps_set_mode(wl, mode);
+ if (ret < 0)
+ goto out_sleep;
+ }
+ }
+ }
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ if (bss_conf->use_short_slot)
+ ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
+ else
+ ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
+ if (ret < 0) {
+ wl1271_warning("Set slot time failed %d", ret);
+ goto out_sleep;
+ }
+ }
+
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ if (bss_conf->use_short_preamble)
+ wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
+ else
+ wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
+ }
+
+ if (changed & BSS_CHANGED_ERP_CTS_PROT) {
+ if (bss_conf->use_cts_prot)
+ ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
+ else
+ ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
+ if (ret < 0) {
+ wl1271_warning("Set ctsprotect failed %d", ret);
+ goto out_sleep;
+ }
+ }
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+
+/* can't be const, mac80211 writes to this */
+static struct ieee80211_rate wl1271_rates[] = {
+ { .bitrate = 10,
+ .hw_value = 0x1,
+ .hw_value_short = 0x1, },
+ { .bitrate = 20,
+ .hw_value = 0x2,
+ .hw_value_short = 0x2,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55,
+ .hw_value = 0x4,
+ .hw_value_short = 0x4,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110,
+ .hw_value = 0x20,
+ .hw_value_short = 0x20,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 60,
+ .hw_value = 0x8,
+ .hw_value_short = 0x8, },
+ { .bitrate = 90,
+ .hw_value = 0x10,
+ .hw_value_short = 0x10, },
+ { .bitrate = 120,
+ .hw_value = 0x40,
+ .hw_value_short = 0x40, },
+ { .bitrate = 180,
+ .hw_value = 0x80,
+ .hw_value_short = 0x80, },
+ { .bitrate = 240,
+ .hw_value = 0x200,
+ .hw_value_short = 0x200, },
+ { .bitrate = 360,
+ .hw_value = 0x400,
+ .hw_value_short = 0x400, },
+ { .bitrate = 480,
+ .hw_value = 0x800,
+ .hw_value_short = 0x800, },
+ { .bitrate = 540,
+ .hw_value = 0x1000,
+ .hw_value_short = 0x1000, },
+};
+
+/* can't be const, mac80211 writes to this */
+static struct ieee80211_channel wl1271_channels[] = {
+ { .hw_value = 1, .center_freq = 2412},
+ { .hw_value = 2, .center_freq = 2417},
+ { .hw_value = 3, .center_freq = 2422},
+ { .hw_value = 4, .center_freq = 2427},
+ { .hw_value = 5, .center_freq = 2432},
+ { .hw_value = 6, .center_freq = 2437},
+ { .hw_value = 7, .center_freq = 2442},
+ { .hw_value = 8, .center_freq = 2447},
+ { .hw_value = 9, .center_freq = 2452},
+ { .hw_value = 10, .center_freq = 2457},
+ { .hw_value = 11, .center_freq = 2462},
+ { .hw_value = 12, .center_freq = 2467},
+ { .hw_value = 13, .center_freq = 2472},
+};
+
+/* can't be const, mac80211 writes to this */
+static struct ieee80211_supported_band wl1271_band_2ghz = {
+ .channels = wl1271_channels,
+ .n_channels = ARRAY_SIZE(wl1271_channels),
+ .bitrates = wl1271_rates,
+ .n_bitrates = ARRAY_SIZE(wl1271_rates),
+};
+
+static const struct ieee80211_ops wl1271_ops = {
+ .start = wl1271_op_start,
+ .stop = wl1271_op_stop,
+ .add_interface = wl1271_op_add_interface,
+ .remove_interface = wl1271_op_remove_interface,
+ .config = wl1271_op_config,
+/* .config_interface = wl1271_op_config_interface, */
+ .configure_filter = wl1271_op_configure_filter,
+ .tx = wl1271_op_tx,
+ .set_key = wl1271_op_set_key,
+ .hw_scan = wl1271_op_hw_scan,
+ .bss_info_changed = wl1271_op_bss_info_changed,
+ .set_rts_threshold = wl1271_op_set_rts_threshold,
+};
+
+static int wl1271_register_hw(struct wl1271 *wl)
+{
+ int ret;
+
+ if (wl->mac80211_registered)
+ return 0;
+
+ SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
+
+ ret = ieee80211_register_hw(wl->hw);
+ if (ret < 0) {
+ wl1271_error("unable to register mac80211 hw: %d", ret);
+ return ret;
+ }
+
+ wl->mac80211_registered = true;
+
+ wl1271_notice("loaded");
+
+ return 0;
+}
+
+static int wl1271_init_ieee80211(struct wl1271 *wl)
+{
+ /*
+ * The tx descriptor buffer and the TKIP space.
+ *
+ * FIXME: add correct 1271 descriptor size
+ */
+ wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE;
+
+ /* unit us */
+ /* FIXME: find a proper value */
+ wl->hw->channel_change_time = 10000;
+
+ wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_NOISE_DBM;
+
+ wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ wl->hw->wiphy->max_scan_ssids = 1;
+ wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
+
+ SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
+
+ return 0;
+}
+
+static void wl1271_device_release(struct device *dev)
+{
+
+}
+
+static struct platform_device wl1271_device = {
+ .name = "wl1271",
+ .id = -1,
+
+ /* device model insists to have a release function */
+ .dev = {
+ .release = wl1271_device_release,
+ },
+};
+
+#define WL1271_DEFAULT_CHANNEL 0
+static int __devinit wl1271_probe(struct spi_device *spi)
+{
+ struct wl12xx_platform_data *pdata;
+ struct ieee80211_hw *hw;
+ struct wl1271 *wl;
+ int ret, i;
+ static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
+
+ pdata = spi->dev.platform_data;
+ if (!pdata) {
+ wl1271_error("no platform data");
+ return -ENODEV;
+ }
+
+ hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
+ if (!hw) {
+ wl1271_error("could not alloc ieee80211_hw");
+ return -ENOMEM;
+ }
+
+ wl = hw->priv;
+ memset(wl, 0, sizeof(*wl));
+
+ wl->hw = hw;
+ dev_set_drvdata(&spi->dev, wl);
+ wl->spi = spi;
+
+ skb_queue_head_init(&wl->tx_queue);
+
+ INIT_WORK(&wl->filter_work, wl1271_filter_work);
+ wl->channel = WL1271_DEFAULT_CHANNEL;
+ wl->scanning = false;
+ wl->default_key = 0;
+ wl->listen_int = 1;
+ wl->rx_counter = 0;
+ wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
+ wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
+ wl->elp = false;
+ wl->psm = 0;
+ wl->psm_requested = false;
+ wl->tx_queue_stopped = false;
+ wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
+
+ /* We use the default power on sleep time until we know which chip
+ * we're using */
+ for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
+ wl->tx_frames[i] = NULL;
+
+ spin_lock_init(&wl->wl_lock);
+
+ /*
+ * In case our MAC address is not correctly set,
+ * we use a random but Nokia MAC.
+ */
+ memcpy(wl->mac_addr, nokia_oui, 3);
+ get_random_bytes(wl->mac_addr + 3, 3);
+
+ wl->state = WL1271_STATE_OFF;
+ mutex_init(&wl->mutex);
+
+ wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL);
+ if (!wl->rx_descriptor) {
+ wl1271_error("could not allocate memory for rx descriptor");
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ /* This is the only SPI value that we need to set here, the rest
+ * comes from the board-peripherals file */
+ spi->bits_per_word = 32;
+
+ ret = spi_setup(spi);
+ if (ret < 0) {
+ wl1271_error("spi_setup failed");
+ goto out_free;
+ }
+
+ wl->set_power = pdata->set_power;
+ if (!wl->set_power) {
+ wl1271_error("set power function missing in platform data");
+ ret = -ENODEV;
+ goto out_free;
+ }
+
+ wl->irq = spi->irq;
+ if (wl->irq < 0) {
+ wl1271_error("irq missing in platform data");
+ ret = -ENODEV;
+ goto out_free;
+ }
+
+ ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
+ if (ret < 0) {
+ wl1271_error("request_irq() failed: %d", ret);
+ goto out_free;
+ }
+
+ set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
+
+ disable_irq(wl->irq);
+
+ ret = platform_device_register(&wl1271_device);
+ if (ret) {
+ wl1271_error("couldn't register platform device");
+ goto out_irq;
+ }
+ dev_set_drvdata(&wl1271_device.dev, wl);
+
+ ret = wl1271_init_ieee80211(wl);
+ if (ret)
+ goto out_platform;
+
+ ret = wl1271_register_hw(wl);
+ if (ret)
+ goto out_platform;
+
+ wl1271_debugfs_init(wl);
+
+ wl1271_notice("initialized");
+
+ return 0;
+
+ out_platform:
+ platform_device_unregister(&wl1271_device);
+
+ out_irq:
+ free_irq(wl->irq, wl);
+
+ out_free:
+ kfree(wl->rx_descriptor);
+ wl->rx_descriptor = NULL;
+
+ ieee80211_free_hw(hw);
+
+ return ret;
+}
+
+static int __devexit wl1271_remove(struct spi_device *spi)
+{
+ struct wl1271 *wl = dev_get_drvdata(&spi->dev);
+
+ ieee80211_unregister_hw(wl->hw);
+
+ wl1271_debugfs_exit(wl);
+ platform_device_unregister(&wl1271_device);
+ free_irq(wl->irq, wl);
+ kfree(wl->target_mem_map);
+ kfree(wl->fw);
+ wl->fw = NULL;
+ kfree(wl->nvs);
+ wl->nvs = NULL;
+
+ kfree(wl->rx_descriptor);
+ wl->rx_descriptor = NULL;
+
+ kfree(wl->fw_status);
+ kfree(wl->tx_res_if);
+
+ ieee80211_free_hw(wl->hw);
+
+ return 0;
+}
+
+
+static struct spi_driver wl1271_spi_driver = {
+ .driver = {
+ .name = "wl1271",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+
+ .probe = wl1271_probe,
+ .remove = __devexit_p(wl1271_remove),
+};
+
+static int __init wl1271_init(void)
+{
+ int ret;
+
+ ret = spi_register_driver(&wl1271_spi_driver);
+ if (ret < 0) {
+ wl1271_error("failed to register spi driver: %d", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static void __exit wl1271_exit(void)
+{
+ spi_unregister_driver(&wl1271_spi_driver);
+
+ wl1271_notice("unloaded");
+}
+
+module_init(wl1271_init);
+module_exit(wl1271_exit);
+
+MODULE_LICENSE("GPL");
+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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "wl1271_reg.h"
+#include "wl1271_ps.h"
+#include "wl1271_spi.h"
+
+#define WL1271_WAKEUP_TIMEOUT 500
+
+/* Routines to toggle sleep mode while in ELP */
+void wl1271_ps_elp_sleep(struct wl1271 *wl)
+{
+ /*
+ * FIXME: due to a problem in the firmware (causing a firmware
+ * crash), ELP entry is prevented below. Remove the "true" to
+ * re-enable ELP entry.
+ */
+ if (true || wl->elp || !wl->psm)
+ return;
+
+ /*
+ * Go to ELP unless there is work already pending - pending work
+ * will immediately wakeup the chipset anyway.
+ */
+ if (!work_pending(&wl->irq_work) && !work_pending(&wl->tx_work)) {
+ wl1271_debug(DEBUG_PSM, "chip to elp");
+ wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
+ wl->elp = true;
+ }
+}
+
+int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
+{
+ DECLARE_COMPLETION_ONSTACK(compl);
+ unsigned long flags;
+ int ret;
+ u32 start_time = jiffies;
+ bool pending = false;
+
+ if (!wl->elp)
+ return 0;
+
+ wl1271_debug(DEBUG_PSM, "waking up chip from elp");
+
+ /*
+ * The spinlock is required here to synchronize both the work and
+ * the completion variable in one entity.
+ */
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ if (work_pending(&wl->irq_work) || chip_awake)
+ pending = true;
+ else
+ wl->elp_compl = &compl;
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+ wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
+
+ if (!pending) {
+ ret = wait_for_completion_timeout(
+ &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
+ if (ret == 0) {
+ wl1271_error("ELP wakeup timeout!");
+ ret = -ETIMEDOUT;
+ goto err;
+ } else if (ret < 0) {
+ wl1271_error("ELP wakeup completion error.");
+ goto err;
+ }
+ }
+
+ wl->elp = false;
+
+ wl1271_debug(DEBUG_PSM, "wakeup time: %u ms",
+ jiffies_to_msecs(jiffies - start_time));
+ goto out;
+
+err:
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ wl->elp_compl = NULL;
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ return ret;
+
+out:
+ return 0;
+}
+
+int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
+{
+ int ret;
+
+ switch (mode) {
+ case STATION_POWER_SAVE_MODE:
+ wl1271_debug(DEBUG_PSM, "entering psm");
+ ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
+ if (ret < 0)
+ return ret;
+
+ wl1271_ps_elp_sleep(wl);
+ if (ret < 0)
+ return ret;
+
+ wl->psm = 1;
+ break;
+ case STATION_ACTIVE_MODE:
+ default:
+ wl1271_debug(DEBUG_PSM, "leaving psm");
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
+ if (ret < 0)
+ return ret;
+
+ wl->psm = 0;
+ break;
+ }
+
+ return ret;
+}
+
+
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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_PS_H__
+#define __WL1271_PS_H__
+
+#include "wl1271.h"
+#include "wl1271_acx.h"
+
+int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode);
+void wl1271_ps_elp_sleep(struct wl1271 *wl);
+int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake);
+
+
+#endif /* __WL1271_PS_H__ */
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h
index e421643215cd..f8ed4a4fc691 100644
--- a/drivers/net/wireless/wl12xx/reg.h
+++ b/drivers/net/wireless/wl12xx/wl1271_reg.h
@@ -1,10 +1,10 @@
/*
* This file is part of wl12xx
*
- * Copyright (c) 1998-2007 Texas Instruments Incorporated
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
+ * Copyright (C) 2009 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -26,7 +26,6 @@
#define __REG_H__
#include <linux/bitops.h>
-#include "wl12xx.h"
#define REGISTERS_BASE 0x00300000
#define DRPW_BASE 0x00310000
@@ -35,6 +34,7 @@
#define REGISTERS_WORK_SIZE 0x0000b000
#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC
+#define STATUS_MEM_ADDRESS 0x40400
/* ELP register commands */
#define ELPCTRL_WAKE_UP 0x1
@@ -43,6 +43,25 @@
/* ELP WLAN_READY bit */
#define ELPCTRL_WLAN_READY 0x2
+/*===============================================
+ Host Software Reset - 32bit RW
+ ------------------------------------------
+ [31:1] Reserved
+ 0 SOFT_RESET Soft Reset - When this bit is set,
+ it holds the Wlan hardware in a soft reset state.
+ This reset disables all MAC and baseband processor
+ clocks except the CardBus/PCI interface clock.
+ It also initializes all MAC state machines except
+ the host interface. It does not reload the
+ contents of the EEPROM. When this bit is cleared
+ (not self-clearing), the Wlan hardware
+ exits the software reset state.
+===============================================*/
+#define ACX_REG_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000)
+
+#define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008)
+#define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c)
+#define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018)
/*
* Interrupt registers.
* 64 bit interrupt sources registers ws ced.
@@ -96,6 +115,9 @@
#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440)
#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444)
+#define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474)
+#define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478)
+
/* Host Interrupts*/
#define HINT_MASK (REGISTERS_BASE + 0x0494)
#define HINT_MASK_SET (REGISTERS_BASE + 0x0498)
@@ -107,67 +129,6 @@
#define HINT_ACK (REGISTERS_BASE + 0x04A8)
#define HINT_TRIG (REGISTERS_BASE + 0x04AC)
-/* Device Configuration registers*/
-#define SOR_CFG (REGISTERS_BASE + 0x0800)
-#define ECPU_CTRL (REGISTERS_BASE + 0x0804)
-#define HI_CFG (REGISTERS_BASE + 0x0808)
-#define EE_START (REGISTERS_BASE + 0x080C)
-
-#define CHIP_ID_B (REGISTERS_BASE + 0x5674)
-
-#define CHIP_ID_1251_PG10 (0x7010101)
-#define CHIP_ID_1251_PG11 (0x7020101)
-#define CHIP_ID_1251_PG12 (0x7030101)
-
-#define ENABLE (REGISTERS_BASE + 0x5450)
-
-/* Power Management registers */
-#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804)
-#define ELP_CMD (REGISTERS_BASE + 0x5808)
-#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810)
-#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814)
-#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818)
-
-#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820)
-
-/* Scratch Pad registers*/
-#define SCR_PAD0 (REGISTERS_BASE + 0x5608)
-#define SCR_PAD1 (REGISTERS_BASE + 0x560C)
-#define SCR_PAD2 (REGISTERS_BASE + 0x5610)
-#define SCR_PAD3 (REGISTERS_BASE + 0x5614)
-#define SCR_PAD4 (REGISTERS_BASE + 0x5618)
-#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C)
-#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620)
-#define SCR_PAD5 (REGISTERS_BASE + 0x5624)
-#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628)
-#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C)
-#define SCR_PAD6 (REGISTERS_BASE + 0x5630)
-#define SCR_PAD7 (REGISTERS_BASE + 0x5634)
-#define SCR_PAD8 (REGISTERS_BASE + 0x5638)
-#define SCR_PAD9 (REGISTERS_BASE + 0x563C)
-
-/* Spare registers*/
-#define SPARE_A1 (REGISTERS_BASE + 0x0994)
-#define SPARE_A2 (REGISTERS_BASE + 0x0998)
-#define SPARE_A3 (REGISTERS_BASE + 0x099C)
-#define SPARE_A4 (REGISTERS_BASE + 0x09A0)
-#define SPARE_A5 (REGISTERS_BASE + 0x09A4)
-#define SPARE_A6 (REGISTERS_BASE + 0x09A8)
-#define SPARE_A7 (REGISTERS_BASE + 0x09AC)
-#define SPARE_A8 (REGISTERS_BASE + 0x09B0)
-#define SPARE_B1 (REGISTERS_BASE + 0x5420)
-#define SPARE_B2 (REGISTERS_BASE + 0x5424)
-#define SPARE_B3 (REGISTERS_BASE + 0x5428)
-#define SPARE_B4 (REGISTERS_BASE + 0x542C)
-#define SPARE_B5 (REGISTERS_BASE + 0x5430)
-#define SPARE_B6 (REGISTERS_BASE + 0x5434)
-#define SPARE_B7 (REGISTERS_BASE + 0x5438)
-#define SPARE_B8 (REGISTERS_BASE + 0x543C)
-
-enum wl12xx_acx_int_reg {
- ACX_REG_INTERRUPT_TRIG,
- ACX_REG_INTERRUPT_TRIG_H,
-
/*=============================================
Host Interrupt Mask Register - 32bit (RW)
------------------------------------------
@@ -196,7 +157,7 @@ enum wl12xx_acx_int_reg {
21- -
Default: 0x0001
*==============================================*/
- ACX_REG_INTERRUPT_MASK,
+#define ACX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC)
/*=============================================
Host Interrupt Mask Set 16bit, (Write only)
@@ -206,7 +167,7 @@ enum wl12xx_acx_int_reg {
without effecting the mask
state of other bits (0 = no effect).
==============================================*/
- ACX_REG_HINT_MASK_SET,
+#define ACX_REG_HINT_MASK_SET (REGISTERS_BASE + 0x04E0)
/*=============================================
Host Interrupt Mask Clear 16bit,(Write only)
@@ -216,7 +177,7 @@ enum wl12xx_acx_int_reg {
without effecting the mask
state of other bits (0 = no effect).
=============================================*/
- ACX_REG_HINT_MASK_CLR,
+#define ACX_REG_HINT_MASK_CLR (REGISTERS_BASE + 0x04E4)
/*=============================================
Host Interrupt Status Nondestructive Read
@@ -227,7 +188,7 @@ enum wl12xx_acx_int_reg {
Reading this register doesn't
effect its content.
=============================================*/
- ACX_REG_INTERRUPT_NO_CLEAR,
+#define ACX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8)
/*=============================================
Host Interrupt Status Clear on Read Register
@@ -238,7 +199,7 @@ enum wl12xx_acx_int_reg {
Reading this register clears it,
thus making all interrupts inactive.
==============================================*/
- ACX_REG_INTERRUPT_CLEAR,
+#define ACX_REG_INTERRUPT_CLEAR (REGISTERS_BASE + 0x04F8)
/*=============================================
Host Interrupt Acknowledge Register
@@ -250,40 +211,13 @@ enum wl12xx_acx_int_reg {
HINT_STS_ND registers, thus making the
assotiated interrupt inactive. (0-no effect)
==============================================*/
- ACX_REG_INTERRUPT_ACK,
+#define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0)
-/*===============================================
- Host Software Reset - 32bit RW
- ------------------------------------------
- [31:1] Reserved
- 0 SOFT_RESET Soft Reset - When this bit is set,
- it holds the Wlan hardware in a soft reset state.
- This reset disables all MAC and baseband processor
- clocks except the CardBus/PCI interface clock.
- It also initializes all MAC state machines except
- the host interface. It does not reload the
- contents of the EEPROM. When this bit is cleared
- (not self-clearing), the Wlan hardware
- exits the software reset state.
-===============================================*/
- ACX_REG_SLV_SOFT_RESET,
-
-/*===============================================
- EEPROM Burst Read Start - 32bit RW
- ------------------------------------------
- [31:1] Reserved
- 0 ACX_EE_START - EEPROM Burst Read Start 0
- Setting this bit starts a burst read from
- the external EEPROM.
- If this bit is set (after reset) before an EEPROM read/write,
- the burst read starts at EEPROM address 0.
- Otherwise, it starts at the address
- following the address of the previous access.
- TheWlan hardware hardware clears this bit automatically.
+#define RX_DRIVER_DUMMY_WRITE_ADDRESS (REGISTERS_BASE + 0x0534)
+#define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538)
- Default: 0x00000000
-*================================================*/
- ACX_REG_EE_START,
+/* Device Configuration registers*/
+#define SOR_CFG (REGISTERS_BASE + 0x0800)
/* Embedded ARM CPU Control */
@@ -305,10 +239,89 @@ enum wl12xx_acx_int_reg {
1 halt eCPU
0 enable eCPU
===============================================*/
- ACX_REG_ECPU_CONTROL,
+#define ACX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804)
+
+#define HI_CFG (REGISTERS_BASE + 0x0808)
+
+/*===============================================
+ EEPROM Burst Read Start - 32bit RW
+ ------------------------------------------
+ [31:1] Reserved
+ 0 ACX_EE_START - EEPROM Burst Read Start 0
+ Setting this bit starts a burst read from
+ the external EEPROM.
+ If this bit is set (after reset) before an EEPROM read/write,
+ the burst read starts at EEPROM address 0.
+ Otherwise, it starts at the address
+ following the address of the previous access.
+ TheWlan hardware hardware clears this bit automatically.
+
+ Default: 0x00000000
+*================================================*/
+#define ACX_REG_EE_START (REGISTERS_BASE + 0x080C)
+
+#define OCP_POR_CTR (REGISTERS_BASE + 0x09B4)
+#define OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8)
+#define OCP_DATA_READ (REGISTERS_BASE + 0x09BC)
+#define OCP_CMD (REGISTERS_BASE + 0x09C0)
+
+#define WL1271_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8)
+
+#define CHIP_ID_B (REGISTERS_BASE + 0x5674)
+
+#define CHIP_ID_1271_PG10 (0x4030101)
+#define CHIP_ID_1271_PG20 (0x4030111)
+
+#define ENABLE (REGISTERS_BASE + 0x5450)
+
+/* Power Management registers */
+#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804)
+#define ELP_CMD (REGISTERS_BASE + 0x5808)
+#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810)
+#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814)
+#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818)
+
+#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820)
+
+/* Scratch Pad registers*/
+#define SCR_PAD0 (REGISTERS_BASE + 0x5608)
+#define SCR_PAD1 (REGISTERS_BASE + 0x560C)
+#define SCR_PAD2 (REGISTERS_BASE + 0x5610)
+#define SCR_PAD3 (REGISTERS_BASE + 0x5614)
+#define SCR_PAD4 (REGISTERS_BASE + 0x5618)
+#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C)
+#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620)
+#define SCR_PAD5 (REGISTERS_BASE + 0x5624)
+#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628)
+#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C)
+#define SCR_PAD6 (REGISTERS_BASE + 0x5630)
+#define SCR_PAD7 (REGISTERS_BASE + 0x5634)
+#define SCR_PAD8 (REGISTERS_BASE + 0x5638)
+#define SCR_PAD9 (REGISTERS_BASE + 0x563C)
+
+/* Spare registers*/
+#define SPARE_A1 (REGISTERS_BASE + 0x0994)
+#define SPARE_A2 (REGISTERS_BASE + 0x0998)
+#define SPARE_A3 (REGISTERS_BASE + 0x099C)
+#define SPARE_A4 (REGISTERS_BASE + 0x09A0)
+#define SPARE_A5 (REGISTERS_BASE + 0x09A4)
+#define SPARE_A6 (REGISTERS_BASE + 0x09A8)
+#define SPARE_A7 (REGISTERS_BASE + 0x09AC)
+#define SPARE_A8 (REGISTERS_BASE + 0x09B0)
+#define SPARE_B1 (REGISTERS_BASE + 0x5420)
+#define SPARE_B2 (REGISTERS_BASE + 0x5424)
+#define SPARE_B3 (REGISTERS_BASE + 0x5428)
+#define SPARE_B4 (REGISTERS_BASE + 0x542C)
+#define SPARE_B5 (REGISTERS_BASE + 0x5430)
+#define SPARE_B6 (REGISTERS_BASE + 0x5434)
+#define SPARE_B7 (REGISTERS_BASE + 0x5438)
+#define SPARE_B8 (REGISTERS_BASE + 0x543C)
+
+#define PLL_PARAMETERS (REGISTERS_BASE + 0x6040)
+#define WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008)
+#define WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100)
+#define DRPW_SCRATCH_START (DRPW_BASE + 0x002C)
- ACX_REG_TABLE_LEN
-};
#define ACX_SLV_SOFT_RESET_BIT BIT(1)
#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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "wl1271.h"
+#include "wl1271_acx.h"
+#include "wl1271_reg.h"
+#include "wl1271_rx.h"
+#include "wl1271_spi.h"
+
+static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status,
+ u32 drv_rx_counter)
+{
+ return status->rx_pkt_descs[drv_rx_counter] & RX_MEM_BLOCK_MASK;
+}
+
+static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status,
+ u32 drv_rx_counter)
+{
+ return (status->rx_pkt_descs[drv_rx_counter] & RX_BUF_SIZE_MASK) >>
+ RX_BUF_SIZE_SHIFT_DIV;
+}
+
+/* The values of this table must match the wl1271_rates[] array */
+static u8 wl1271_rx_rate_to_idx[] = {
+ /* MCS rates are used only with 11n */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */
+
+ 11, /* WL1271_RATE_54 */
+ 10, /* WL1271_RATE_48 */
+ 9, /* WL1271_RATE_36 */
+ 8, /* WL1271_RATE_24 */
+
+ /* TI-specific rate */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22 */
+
+ 7, /* WL1271_RATE_18 */
+ 6, /* WL1271_RATE_12 */
+ 3, /* WL1271_RATE_11 */
+ 5, /* WL1271_RATE_9 */
+ 4, /* WL1271_RATE_6 */
+ 2, /* WL1271_RATE_5_5 */
+ 1, /* WL1271_RATE_2 */
+ 0 /* WL1271_RATE_1 */
+};
+
+static void wl1271_rx_status(struct wl1271 *wl,
+ struct wl1271_rx_descriptor *desc,
+ struct ieee80211_rx_status *status,
+ u8 beacon)
+{
+ memset(status, 0, sizeof(struct ieee80211_rx_status));
+
+ if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG)
+ status->band = IEEE80211_BAND_2GHZ;
+ else
+ wl1271_warning("unsupported band 0x%x",
+ desc->flags & WL1271_RX_DESC_BAND_MASK);
+
+ /*
+ * FIXME: Add mactime handling. For IBSS (ad-hoc) we need to get the
+ * timestamp from the beacon (acx_tsf_info). In BSS mode (infra) we
+ * only need the mactime for monitor mode. For now the mactime is
+ * not valid, so RX_FLAG_TSFT should not be set
+ */
+ status->signal = desc->rssi;
+
+ /* FIXME: Should this be optimized? */
+ status->qual = (desc->rssi - WL1271_RX_MIN_RSSI) * 100 /
+ (WL1271_RX_MAX_RSSI - WL1271_RX_MIN_RSSI);
+ status->qual = min(status->qual, 100);
+ status->qual = max(status->qual, 0);
+
+ /*
+ * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we
+ * need to divide by two for now, but TI has been discussing about
+ * changing it. This needs to be rechecked.
+ */
+ status->noise = desc->rssi - (desc->snr >> 1);
+
+ status->freq = ieee80211_channel_to_frequency(desc->channel);
+
+ if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
+ status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
+
+ if (likely(!(desc->flags & WL1271_RX_DESC_DECRYPT_FAIL)))
+ status->flag |= RX_FLAG_DECRYPTED;
+
+ if (unlikely(desc->flags & WL1271_RX_DESC_MIC_FAIL))
+ status->flag |= RX_FLAG_MMIC_ERROR;
+ }
+
+ status->rate_idx = wl1271_rx_rate_to_idx[desc->rate];
+
+ if (status->rate_idx == WL1271_RX_RATE_UNSUPPORTED)
+ wl1271_warning("unsupported rate");
+}
+
+static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
+{
+ struct ieee80211_rx_status rx_status;
+ struct wl1271_rx_descriptor *desc;
+ struct sk_buff *skb;
+ u16 *fc;
+ u8 *buf;
+ u8 beacon = 0;
+
+ skb = dev_alloc_skb(length);
+ if (!skb) {
+ wl1271_error("Couldn't allocate RX frame");
+ return;
+ }
+
+ buf = skb_put(skb, length);
+ wl1271_spi_reg_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
+
+ /* the data read starts with the descriptor */
+ desc = (struct wl1271_rx_descriptor *) buf;
+
+ /* now we pull the descriptor out of the buffer */
+ skb_pull(skb, sizeof(*desc));
+
+ fc = (u16 *)skb->data;
+ if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
+ beacon = 1;
+
+ wl1271_rx_status(wl, desc, &rx_status, beacon);
+
+ wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
+ beacon ? "beacon" : "");
+
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx(wl->hw, skb);
+}
+
+void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
+{
+ struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
+ u32 buf_size;
+ u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
+ u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
+ u32 mem_block;
+
+ while (drv_rx_counter != fw_rx_counter) {
+ mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter);
+ buf_size = wl1271_rx_get_buf_size(status, drv_rx_counter);
+
+ if (buf_size == 0) {
+ wl1271_warning("received empty data");
+ break;
+ }
+
+ wl->rx_mem_pool_addr.addr =
+ (mem_block << 8) + wl_mem_map->packet_memory_pool_start;
+ wl->rx_mem_pool_addr.addr_extra =
+ wl->rx_mem_pool_addr.addr + 4;
+
+ /* Choose the block we want to read */
+ wl1271_spi_reg_write(wl, WL1271_SLV_REG_DATA,
+ &wl->rx_mem_pool_addr,
+ sizeof(wl->rx_mem_pool_addr), false);
+
+ wl1271_rx_handle_data(wl, buf_size);
+
+ wl->rx_counter++;
+ drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
+ }
+
+ wl1271_reg_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
+
+ /* This is a workaround for some problems in the chip */
+ wl1271_reg_write32(wl, RX_DRIVER_DUMMY_WRITE_ADDRESS, 0x1);
+
+}
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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_RX_H__
+#define __WL1271_RX_H__
+
+#include <linux/bitops.h>
+
+#define WL1271_RX_MAX_RSSI -30
+#define WL1271_RX_MIN_RSSI -95
+
+#define WL1271_RX_ALIGN_TO 4
+#define WL1271_RX_ALIGN(len) (((len) + WL1271_RX_ALIGN_TO - 1) & \
+ ~(WL1271_RX_ALIGN_TO - 1))
+
+#define SHORT_PREAMBLE_BIT BIT(0)
+#define OFDM_RATE_BIT BIT(6)
+#define PBCC_RATE_BIT BIT(7)
+
+#define PLCP_HEADER_LENGTH 8
+#define RX_DESC_PACKETID_SHIFT 11
+#define RX_MAX_PACKET_ID 3
+
+#define NUM_RX_PKT_DESC_MOD_MASK 7
+#define WL1271_RX_RATE_UNSUPPORTED 0xFF
+
+#define RX_DESC_VALID_FCS 0x0001
+#define RX_DESC_MATCH_RXADDR1 0x0002
+#define RX_DESC_MCAST 0x0004
+#define RX_DESC_STAINTIM 0x0008
+#define RX_DESC_VIRTUAL_BM 0x0010
+#define RX_DESC_BCAST 0x0020
+#define RX_DESC_MATCH_SSID 0x0040
+#define RX_DESC_MATCH_BSSID 0x0080
+#define RX_DESC_ENCRYPTION_MASK 0x0300
+#define RX_DESC_MEASURMENT 0x0400
+#define RX_DESC_SEQNUM_MASK 0x1800
+#define RX_DESC_MIC_FAIL 0x2000
+#define RX_DESC_DECRYPT_FAIL 0x4000
+
+/*
+ * RX Descriptor flags:
+ *
+ * Bits 0-1 - band
+ * Bit 2 - STBC
+ * Bit 3 - A-MPDU
+ * Bit 4 - HT
+ * Bits 5-7 - encryption
+ */
+#define WL1271_RX_DESC_BAND_MASK 0x03
+#define WL1271_RX_DESC_ENCRYPT_MASK 0xE0
+
+#define WL1271_RX_DESC_BAND_BG 0x00
+#define WL1271_RX_DESC_BAND_J 0x01
+#define WL1271_RX_DESC_BAND_A 0x02
+
+#define WL1271_RX_DESC_STBC BIT(2)
+#define WL1271_RX_DESC_A_MPDU BIT(3)
+#define WL1271_RX_DESC_HT BIT(4)
+
+#define WL1271_RX_DESC_ENCRYPT_WEP 0x20
+#define WL1271_RX_DESC_ENCRYPT_TKIP 0x40
+#define WL1271_RX_DESC_ENCRYPT_AES 0x60
+#define WL1271_RX_DESC_ENCRYPT_GEM 0x80
+
+/*
+ * RX Descriptor status
+ *
+ * Bits 0-2 - status
+ * Bits 3-7 - reserved
+ */
+#define WL1271_RX_DESC_STATUS_MASK 0x07
+
+#define WL1271_RX_DESC_SUCCESS 0x00
+#define WL1271_RX_DESC_DECRYPT_FAIL 0x01
+#define WL1271_RX_DESC_MIC_FAIL 0x02
+#define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03
+
+#define RX_MEM_BLOCK_MASK 0xFF
+#define RX_BUF_SIZE_MASK 0xFFF00
+#define RX_BUF_SIZE_SHIFT_DIV 6
+
+struct wl1271_rx_descriptor {
+ u16 length;
+ u8 status;
+ u8 flags;
+ u8 rate;
+ u8 channel;
+ s8 rssi;
+ u8 snr;
+ u32 timestamp;
+ u8 packet_class;
+ u8 process_id;
+ u8 pad_len;
+ u8 reserved;
+} __attribute__ ((packed));
+
+void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status);
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index abdf171a47e7..4a12880c16a8 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -1,9 +1,9 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1271
*
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2008-2009 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -22,39 +22,26 @@
*/
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/crc7.h>
#include <linux/spi/spi.h>
-#include "wl12xx.h"
+#include "wl1271.h"
#include "wl12xx_80211.h"
-#include "reg.h"
-#include "spi.h"
-#include "ps.h"
+#include "wl1271_spi.h"
-static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
+static int wl1271_translate_reg_addr(struct wl1271 *wl, int addr)
{
- /* If the address is lower than REGISTERS_BASE, it means that this is
- * a chip-specific register address, so look it up in the registers
- * table */
- if (addr < REGISTERS_BASE) {
- /* Make sure we don't go over the table */
- if (addr >= ACX_REG_TABLE_LEN) {
- wl12xx_error("address out of range (%d)", addr);
- return -EINVAL;
- }
- addr = wl->chip.acx_reg_table[addr];
- }
-
return addr - wl->physical_reg_addr + wl->virtual_reg_addr;
}
-static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr)
+static int wl1271_translate_mem_addr(struct wl1271 *wl, int addr)
{
return addr - wl->physical_mem_addr + wl->virtual_mem_addr;
}
-void wl12xx_spi_reset(struct wl12xx *wl)
+void wl1271_spi_reset(struct wl1271 *wl)
{
u8 *cmd;
struct spi_transfer t;
@@ -62,7 +49,7 @@ void wl12xx_spi_reset(struct wl12xx *wl)
cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
if (!cmd) {
- wl12xx_error("could not allocate cmd for spi reset");
+ wl1271_error("could not allocate cmd for spi reset");
return;
}
@@ -77,10 +64,10 @@ void wl12xx_spi_reset(struct wl12xx *wl)
spi_sync(wl->spi, &m);
- wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
+ wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
}
-void wl12xx_spi_init(struct wl12xx *wl)
+void wl1271_spi_init(struct wl1271 *wl)
{
u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
struct spi_transfer t;
@@ -88,7 +75,7 @@ void wl12xx_spi_init(struct wl12xx *wl)
cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
if (!cmd) {
- wl12xx_error("could not allocate cmd for spi init");
+ wl1271_error("could not allocate cmd for spi init");
return;
}
@@ -131,7 +118,7 @@ void wl12xx_spi_init(struct wl12xx *wl)
spi_sync(wl->spi, &m);
- wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
+ wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
}
/* Set the SPI partitions to access the chip addresses
@@ -167,45 +154,47 @@ void wl12xx_spi_init(struct wl12xx *wl)
* | |
*
*/
-void wl12xx_set_partition(struct wl12xx *wl,
+int wl1271_set_partition(struct wl1271 *wl,
u32 mem_start, u32 mem_size,
u32 reg_start, u32 reg_size)
{
- u8 tx_buf[sizeof(u32) + 2 * sizeof(struct wl12xx_partition)];
- struct wl12xx_partition *partition;
+ struct wl1271_partition *partition;
struct spi_transfer t;
struct spi_message m;
+ size_t len, cmd_len;
u32 *cmd;
- size_t len;
int addr;
+ cmd_len = sizeof(u32) + 2 * sizeof(struct wl1271_partition);
+ cmd = kzalloc(cmd_len, GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
spi_message_init(&m);
memset(&t, 0, sizeof(t));
- memset(tx_buf, 0, sizeof(tx_buf));
- cmd = (u32 *) tx_buf;
- partition = (struct wl12xx_partition *) (tx_buf + sizeof(u32));
+ partition = (struct wl1271_partition *) (cmd + 1);
addr = HW_ACCESS_PART0_SIZE_ADDR;
- len = 2 * sizeof(struct wl12xx_partition);
+ len = 2 * sizeof(struct wl1271_partition);
*cmd |= WSPI_CMD_WRITE;
*cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
*cmd |= addr & WSPI_CMD_BYTE_ADDR;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
/* Make sure that the two partitions together don't exceed the
* address range */
if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) {
- wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
+ wl1271_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
" address range. Truncating partition[0].");
mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
}
@@ -213,23 +202,23 @@ void wl12xx_set_partition(struct wl12xx *wl,
((mem_start + mem_size) > reg_start)) {
/* Guarantee that the memory partition doesn't overlap the
* registers partition */
- wl12xx_debug(DEBUG_SPI, "End of partition[0] is "
+ wl1271_debug(DEBUG_SPI, "End of partition[0] is "
"overlapping partition[1]. Adjusted.");
mem_size = reg_start - mem_start;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
} else if ((reg_start < mem_start) &&
((reg_start + reg_size) > mem_start)) {
/* Guarantee that the register partition doesn't overlap the
* memory partition */
- wl12xx_debug(DEBUG_SPI, "End of partition[1] is"
+ wl1271_debug(DEBUG_SPI, "End of partition[1] is"
" overlapping partition[0]. Adjusted.");
reg_size = mem_start - reg_start;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
}
@@ -244,36 +233,46 @@ void wl12xx_set_partition(struct wl12xx *wl,
wl->virtual_mem_addr = 0;
wl->virtual_reg_addr = mem_size;
- t.tx_buf = tx_buf;
- t.len = sizeof(tx_buf);
+ t.tx_buf = cmd;
+ t.len = cmd_len;
spi_message_add_tail(&t, &m);
spi_sync(wl->spi, &m);
+
+ kfree(cmd);
+
+ return 0;
}
-void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
- size_t len)
+void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
{
struct spi_transfer t[3];
struct spi_message m;
- char busy_buf[TNETWIF_READ_OFFSET_BYTES];
- u32 cmd;
+ u8 *busy_buf;
+ u32 *cmd;
- cmd = 0;
- cmd |= WSPI_CMD_READ;
- cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
- cmd |= addr & WSPI_CMD_BYTE_ADDR;
+ cmd = &wl->buffer_cmd;
+ busy_buf = wl->buffer_busyword;
+
+ *cmd = 0;
+ *cmd |= WSPI_CMD_READ;
+ *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
+ *cmd |= addr & WSPI_CMD_BYTE_ADDR;
+
+ if (fixed)
+ *cmd |= WSPI_CMD_FIXED;
spi_message_init(&m);
memset(t, 0, sizeof(t));
- t[0].tx_buf = &cmd;
+ t[0].tx_buf = cmd;
t[0].len = 4;
spi_message_add_tail(&t[0], &m);
/* Busy and non busy words read */
t[1].rx_buf = busy_buf;
- t[1].len = TNETWIF_READ_OFFSET_BYTES;
+ t[1].len = WL1271_BUSY_WORD_LEN;
spi_message_add_tail(&t[1], &m);
t[2].rx_buf = buf;
@@ -284,27 +283,32 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
/* FIXME: check busy words */
- wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", &cmd, sizeof(cmd));
- wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
+ wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
+ wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
}
-void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
- size_t len)
+void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
{
struct spi_transfer t[2];
struct spi_message m;
- u32 cmd;
+ u32 *cmd;
- cmd = 0;
- cmd |= WSPI_CMD_WRITE;
- cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
- cmd |= addr & WSPI_CMD_BYTE_ADDR;
+ cmd = &wl->buffer_cmd;
+
+ *cmd = 0;
+ *cmd |= WSPI_CMD_WRITE;
+ *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
+ *cmd |= addr & WSPI_CMD_BYTE_ADDR;
+
+ if (fixed)
+ *cmd |= WSPI_CMD_FIXED;
spi_message_init(&m);
memset(t, 0, sizeof(t));
- t[0].tx_buf = &cmd;
- t[0].len = sizeof(cmd);
+ t[0].tx_buf = cmd;
+ t[0].len = sizeof(*cmd);
spi_message_add_tail(&t[0], &m);
t[1].tx_buf = buf;
@@ -313,46 +317,66 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
spi_sync(wl->spi, &m);
- wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", &cmd, sizeof(cmd));
- wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
+ wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
+ wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
}
-void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf,
+void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf,
size_t len)
{
int physical;
- physical = wl12xx_translate_mem_addr(wl, addr);
+ physical = wl1271_translate_mem_addr(wl, addr);
- wl12xx_spi_read(wl, physical, buf, len);
+ wl1271_spi_read(wl, physical, buf, len, false);
}
-void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf,
+void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf,
size_t len)
{
int physical;
- physical = wl12xx_translate_mem_addr(wl, addr);
+ physical = wl1271_translate_mem_addr(wl, addr);
+
+ wl1271_spi_write(wl, physical, buf, len, false);
+}
+
+void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed)
+{
+ int physical;
+
+ physical = wl1271_translate_reg_addr(wl, addr);
+
+ wl1271_spi_read(wl, physical, buf, len, fixed);
+}
+
+void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed)
+{
+ int physical;
+
+ physical = wl1271_translate_reg_addr(wl, addr);
- wl12xx_spi_write(wl, physical, buf, len);
+ wl1271_spi_write(wl, physical, buf, len, fixed);
}
-u32 wl12xx_mem_read32(struct wl12xx *wl, int addr)
+u32 wl1271_mem_read32(struct wl1271 *wl, int addr)
{
- return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr));
+ return wl1271_read32(wl, wl1271_translate_mem_addr(wl, addr));
}
-void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val)
+void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val)
{
- wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val);
+ wl1271_write32(wl, wl1271_translate_mem_addr(wl, addr), val);
}
-u32 wl12xx_reg_read32(struct wl12xx *wl, int addr)
+u32 wl1271_reg_read32(struct wl1271 *wl, int addr)
{
- return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr));
+ return wl1271_read32(wl, wl1271_translate_reg_addr(wl, addr));
}
-void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val)
+void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val)
{
- wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val);
+ wl1271_write32(wl, wl1271_translate_reg_addr(wl, addr), val);
}
diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h
index fd3227e904a8..2c9968458646 100644
--- a/drivers/net/wireless/wl12xx/spi.h
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.h
@@ -1,10 +1,10 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1271
*
- * Copyright (c) 1998-2007 Texas Instruments Incorporated
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
+ * Copyright (C) 2008-2009 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -22,12 +22,10 @@
*
*/
-#ifndef __WL12XX_SPI_H__
-#define __WL12XX_SPI_H__
+#ifndef __WL1271_SPI_H__
+#define __WL1271_SPI_H__
-#include "cmd.h"
-#include "acx.h"
-#include "reg.h"
+#include "wl1271_reg.h"
#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
@@ -65,45 +63,51 @@
#define WSPI_INIT_CMD_LEN 8
-#define TNETWIF_READ_OFFSET_BYTES 8
#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \
- ((TNETWIF_READ_OFFSET_BYTES - 4) / sizeof(u32))
+ ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32))
#define HW_ACCESS_WSPI_INIT_CMD_MASK 0
/* Raw target IO, address is not translated */
-void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len);
-void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len);
+void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed);
+void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed);
/* Memory target IO, address is tranlated to partition 0 */
-void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len);
-void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len);
-u32 wl12xx_mem_read32(struct wl12xx *wl, int addr);
-void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val);
+void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, size_t len);
+void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, size_t len);
+u32 wl1271_mem_read32(struct wl1271 *wl, int addr);
+void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val);
/* Registers IO */
-u32 wl12xx_reg_read32(struct wl12xx *wl, int addr);
-void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val);
+void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+u32 wl1271_reg_read32(struct wl1271 *wl, int addr);
+void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val);
/* INIT and RESET words */
-void wl12xx_spi_reset(struct wl12xx *wl);
-void wl12xx_spi_init(struct wl12xx *wl);
-void wl12xx_set_partition(struct wl12xx *wl,
- u32 part_start, u32 part_size,
- u32 reg_start, u32 reg_size);
+void wl1271_spi_reset(struct wl1271 *wl);
+void wl1271_spi_init(struct wl1271 *wl);
+int wl1271_set_partition(struct wl1271 *wl,
+ u32 part_start, u32 part_size,
+ u32 reg_start, u32 reg_size);
-static inline u32 wl12xx_read32(struct wl12xx *wl, int addr)
+static inline u32 wl1271_read32(struct wl1271 *wl, int addr)
{
- u32 response;
+ wl1271_spi_read(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
- wl12xx_spi_read(wl, addr, &response, sizeof(u32));
-
- return response;
+ return wl->buffer_32;
}
-static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val)
+static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
{
- wl12xx_spi_write(wl, addr, &val, sizeof(u32));
+ wl->buffer_32 = val;
+ wl1271_spi_write(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
}
-#endif /* __WL12XX_SPI_H__ */
+#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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "wl1271.h"
+#include "wl1271_spi.h"
+#include "wl1271_reg.h"
+#include "wl1271_ps.h"
+#include "wl1271_tx.h"
+
+static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb)
+{
+ int i;
+
+ for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
+ if (wl->tx_frames[i] == NULL) {
+ wl->tx_frames[i] = skb;
+ return i;
+ }
+
+ return -EBUSY;
+}
+
+static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
+{
+ struct wl1271_tx_hw_descr *desc;
+ u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
+ u32 total_blocks, excluded;
+ int id, ret = -EBUSY;
+
+ /* allocate free identifier for the packet */
+ id = wl1271_tx_id(wl, skb);
+ if (id < 0)
+ return id;
+
+ /* approximate the number of blocks required for this packet
+ in the firmware */
+ /* FIXME: try to figure out what is done here and make it cleaner */
+ total_blocks = (skb->len) >> TX_HW_BLOCK_SHIFT_DIV;
+ excluded = (total_blocks << 2) + (skb->len & 0xff) + 34;
+ total_blocks += (excluded > 252) ? 2 : 1;
+ total_blocks += TX_HW_BLOCK_SPARE;
+
+ if (total_blocks <= wl->tx_blocks_available) {
+ desc = (struct wl1271_tx_hw_descr *)skb_push(
+ skb, total_len - skb->len);
+
+ desc->extra_mem_blocks = TX_HW_BLOCK_SPARE;
+ desc->total_mem_blocks = total_blocks;
+ desc->id = id;
+
+ wl->tx_blocks_available -= total_blocks;
+
+ ret = 0;
+
+ wl1271_debug(DEBUG_TX,
+ "tx_allocate: size: %d, blocks: %d, id: %d",
+ total_len, total_blocks, id);
+ } else
+ wl->tx_frames[id] = NULL;
+
+ return ret;
+}
+
+static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
+ u32 extra, struct ieee80211_tx_info *control)
+{
+ struct wl1271_tx_hw_descr *desc;
+ int pad;
+
+ desc = (struct wl1271_tx_hw_descr *) skb->data;
+
+ /* configure packet life time */
+ desc->start_time = jiffies_to_usecs(jiffies) - wl->time_offset;
+ desc->life_time = TX_HW_MGMT_PKT_LIFETIME_TU;
+
+ /* configure the tx attributes */
+ desc->tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
+ /* FIXME: do we know the packet priority? can we identify mgmt
+ packets, and use max prio for them at least? */
+ desc->tid = 0;
+ desc->aid = TX_HW_DEFAULT_AID;
+ desc->reserved = 0;
+
+ /* align the length (and store in terms of words) */
+ pad = WL1271_TX_ALIGN(skb->len);
+ desc->length = pad >> 2;
+
+ /* calculate number of padding bytes */
+ pad = pad - skb->len;
+ desc->tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
+
+ wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad);
+ return 0;
+}
+
+static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb,
+ struct ieee80211_tx_info *control)
+{
+
+ struct wl1271_tx_hw_descr *desc;
+ int len;
+
+ /* FIXME: This is a workaround for getting non-aligned packets.
+ This happens at least with EAPOL packets from the user space.
+ Our DMA requires packets to be aligned on a 4-byte boundary.
+ */
+ if (unlikely((long)skb->data & 0x03)) {
+ int offset = (4 - (long)skb->data) & 0x03;
+ wl1271_debug(DEBUG_TX, "skb offset %d", offset);
+
+ /* check whether the current skb can be used */
+ if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {
+ unsigned char *src = skb->data;
+
+ /* align the buffer on a 4-byte boundary */
+ skb_reserve(skb, offset);
+ memmove(skb->data, src, skb->len);
+ } else {
+ wl1271_info("No handler, fixme!");
+ return -EINVAL;
+ }
+ }
+
+ len = WL1271_TX_ALIGN(skb->len);
+
+ /* perform a fixed address block write with the packet */
+ wl1271_spi_reg_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
+
+ /* write packet new counter into the write access register */
+ wl->tx_packets_count++;
+ wl1271_reg_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
+
+ desc = (struct wl1271_tx_hw_descr *) skb->data;
+ wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)",
+ desc->id, skb, len, desc->length);
+
+ return 0;
+}
+
+/* caller must hold wl->mutex */
+static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info;
+ u32 extra = 0;
+ int ret = 0;
+ u8 idx;
+
+ if (!skb)
+ return -EINVAL;
+
+ info = IEEE80211_SKB_CB(skb);
+
+ if (info->control.hw_key &&
+ info->control.hw_key->alg == ALG_TKIP)
+ extra = WL1271_TKIP_IV_SPACE;
+
+ if (info->control.hw_key) {
+ idx = info->control.hw_key->hw_key_idx;
+
+ /* FIXME: do we have to do this if we're not using WEP? */
+ if (unlikely(wl->default_key != idx)) {
+ ret = wl1271_cmd_set_default_wep_key(wl, idx);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ ret = wl1271_tx_allocate(wl, skb, extra);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_tx_fill_hdr(wl, skb, extra, info);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_tx_send_packet(wl, skb, info);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+void wl1271_tx_work(struct work_struct *work)
+{
+ struct wl1271 *wl = container_of(work, struct wl1271, tx_work);
+ struct sk_buff *skb;
+ bool woken_up = false;
+ int ret;
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state == WL1271_STATE_OFF))
+ goto out;
+
+ while ((skb = skb_dequeue(&wl->tx_queue))) {
+ if (!woken_up) {
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+ woken_up = true;
+ }
+
+ ret = wl1271_tx_frame(wl, skb);
+ if (ret == -EBUSY) {
+ /* firmware buffer is full, stop queues */
+ wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, "
+ "stop queues");
+ ieee80211_stop_queues(wl->hw);
+ wl->tx_queue_stopped = true;
+ skb_queue_head(&wl->tx_queue, skb);
+ goto out;
+ } else if (ret < 0) {
+ dev_kfree_skb(skb);
+ goto out;
+ } else if (wl->tx_queue_stopped) {
+ /* firmware buffer has space, restart queues */
+ wl1271_debug(DEBUG_TX,
+ "complete_packet: waking queues");
+ ieee80211_wake_queues(wl->hw);
+ wl->tx_queue_stopped = false;
+ }
+ }
+
+out:
+ if (woken_up)
+ wl1271_ps_elp_sleep(wl);
+
+ mutex_unlock(&wl->mutex);
+}
+
+static void wl1271_tx_complete_packet(struct wl1271 *wl,
+ struct wl1271_tx_hw_res_descr *result)
+{
+
+ struct ieee80211_tx_info *info;
+ struct sk_buff *skb;
+ u32 header_len;
+ int id = result->id;
+
+ /* check for id legality */
+ if (id >= TX_HW_RESULT_QUEUE_LEN || wl->tx_frames[id] == NULL) {
+ wl1271_warning("TX result illegal id: %d", id);
+ return;
+ }
+
+ skb = wl->tx_frames[id];
+ info = IEEE80211_SKB_CB(skb);
+
+ /* update packet status */
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+ if (result->status == TX_SUCCESS)
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ if (result->status & TX_RETRY_EXCEEDED) {
+ /* FIXME */
+ /* info->status.excessive_retries = 1; */
+ wl->stats.excessive_retries++;
+ }
+ }
+
+ /* FIXME */
+ /* info->status.retry_count = result->ack_failures; */
+ wl->stats.retry_count += result->ack_failures;
+
+ /* get header len */
+ if (info->control.hw_key &&
+ info->control.hw_key->alg == ALG_TKIP)
+ header_len = WL1271_TKIP_IV_SPACE +
+ sizeof(struct wl1271_tx_hw_descr);
+ else
+ header_len = sizeof(struct wl1271_tx_hw_descr);
+
+ wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
+ " status 0x%x",
+ result->id, skb, result->ack_failures,
+ result->rate_class_index, result->status);
+
+ /* remove private header from packet */
+ skb_pull(skb, header_len);
+
+ /* return the packet to the stack */
+ ieee80211_tx_status(wl->hw, skb);
+ wl->tx_frames[result->id] = NULL;
+}
+
+/* Called upon reception of a TX complete interrupt */
+void wl1271_tx_complete(struct wl1271 *wl, u32 count)
+{
+ struct wl1271_acx_mem_map *memmap =
+ (struct wl1271_acx_mem_map *)wl->target_mem_map;
+ u32 i;
+
+ wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
+
+ /* read the tx results from the chipset */
+ wl1271_spi_mem_read(wl, memmap->tx_result,
+ wl->tx_res_if, sizeof(*wl->tx_res_if));
+
+ /* verify that the result buffer is not getting overrun */
+ if (count > TX_HW_RESULT_QUEUE_LEN) {
+ wl1271_warning("TX result overflow from chipset: %d", count);
+ count = TX_HW_RESULT_QUEUE_LEN;
+ }
+
+ /* process the results */
+ for (i = 0; i < count; i++) {
+ struct wl1271_tx_hw_res_descr *result;
+ u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK;
+
+ /* process the packet */
+ result = &(wl->tx_res_if->tx_results_queue[offset]);
+ wl1271_tx_complete_packet(wl, result);
+
+ wl->tx_results_count++;
+ }
+
+ /* write host counter to chipset (to ack) */
+ wl1271_mem_write32(wl, memmap->tx_result +
+ offsetof(struct wl1271_tx_hw_res_if,
+ tx_result_host_counter),
+ wl->tx_res_if->tx_result_fw_counter);
+}
+
+/* caller must hold wl->mutex */
+void wl1271_tx_flush(struct wl1271 *wl)
+{
+ int i;
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *info;
+
+ /* TX failure */
+/* control->flags = 0; FIXME */
+
+ while ((skb = skb_dequeue(&wl->tx_queue))) {
+ info = IEEE80211_SKB_CB(skb);
+
+ wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb);
+
+ if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS))
+ continue;
+
+ ieee80211_tx_status(wl->hw, skb);
+ }
+
+ for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
+ if (wl->tx_frames[i] != NULL) {
+ skb = wl->tx_frames[i];
+ info = IEEE80211_SKB_CB(skb);
+
+ if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS))
+ continue;
+
+ ieee80211_tx_status(wl->hw, skb);
+ wl->tx_frames[i] = NULL;
+ }
+}
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 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_TX_H__
+#define __WL1271_TX_H__
+
+#define TX_HW_BLOCK_SPARE 2
+#define TX_HW_BLOCK_SHIFT_DIV 8
+
+#define TX_HW_MGMT_PKT_LIFETIME_TU 2000
+/* The chipset reference driver states, that the "aid" value 1
+ * is for infra-BSS, but is still always used */
+#define TX_HW_DEFAULT_AID 1
+
+#define TX_HW_ATTR_SAVE_RETRIES BIT(0)
+#define TX_HW_ATTR_HEADER_PAD BIT(1)
+#define TX_HW_ATTR_SESSION_COUNTER (BIT(2) | BIT(3) | BIT(4))
+#define TX_HW_ATTR_RATE_POLICY (BIT(5) | BIT(6) | BIT(7) | \
+ BIT(8) | BIT(9))
+#define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11))
+#define TX_HW_ATTR_TX_CMPLT_REQ BIT(12)
+
+#define TX_HW_ATTR_OFST_SAVE_RETRIES 0
+#define TX_HW_ATTR_OFST_HEADER_PAD 1
+#define TX_HW_ATTR_OFST_SESSION_COUNTER 2
+#define TX_HW_ATTR_OFST_RATE_POLICY 5
+#define TX_HW_ATTR_OFST_LAST_WORD_PAD 10
+#define TX_HW_ATTR_OFST_TX_CMPLT_REQ 12
+
+#define TX_HW_RESULT_QUEUE_LEN 16
+#define TX_HW_RESULT_QUEUE_LEN_MASK 0xf
+
+#define WL1271_TX_ALIGN_TO 4
+#define WL1271_TX_ALIGN(len) (((len) + WL1271_TX_ALIGN_TO - 1) & \
+ ~(WL1271_TX_ALIGN_TO - 1))
+#define WL1271_TKIP_IV_SPACE 4
+
+struct wl1271_tx_hw_descr {
+ /* Length of packet in words, including descriptor+header+data */
+ u16 length;
+ /* Number of extra memory blocks to allocate for this packet in
+ addition to the number of blocks derived from the packet length */
+ u8 extra_mem_blocks;
+ /* Total number of memory blocks allocated by the host for this packet.
+ Must be equal or greater than the actual blocks number allocated by
+ HW!! */
+ u8 total_mem_blocks;
+ /* Device time (in us) when the packet arrived to the driver */
+ u32 start_time;
+ /* Max delay in TUs until transmission. The last device time the
+ packet can be transmitted is: startTime+(1024*LifeTime) */
+ u16 life_time;
+ /* Bitwise fields - see TX_ATTR... definitions above. */
+ u16 tx_attr;
+ /* Packet identifier used also in the Tx-Result. */
+ u8 id;
+ /* The packet TID value (as User-Priority) */
+ u8 tid;
+ /* Identifier of the remote STA in IBSS, 1 in infra-BSS */
+ u8 aid;
+ u8 reserved;
+} __attribute__ ((packed));
+
+enum wl1271_tx_hw_res_status {
+ TX_SUCCESS = 0,
+ TX_HW_ERROR = 1,
+ TX_DISABLED = 2,
+ TX_RETRY_EXCEEDED = 3,
+ TX_TIMEOUT = 4,
+ TX_KEY_NOT_FOUND = 5,
+ TX_PEER_NOT_FOUND = 6,
+ TX_SESSION_MISMATCH = 7
+};
+
+struct wl1271_tx_hw_res_descr {
+ /* Packet Identifier - same value used in the Tx descriptor.*/
+ u8 id;
+ /* The status of the transmission, indicating success or one of
+ several possible reasons for failure. */
+ u8 status;
+ /* Total air access duration including all retrys and overheads.*/
+ u16 medium_usage;
+ /* The time passed from host xfer to Tx-complete.*/
+ u32 fw_handling_time;
+ /* Total media delay
+ (from 1st EDCA AIFS counter until TX Complete). */
+ u32 medium_delay;
+ /* LS-byte of last TKIP seq-num (saved per AC for recovery). */
+ u8 lsb_security_sequence_number;
+ /* Retry count - number of transmissions without successful ACK.*/
+ u8 ack_failures;
+ /* The rate that succeeded getting ACK
+ (Valid only if status=SUCCESS). */
+ u8 rate_class_index;
+ /* for 4-byte alignment. */
+ u8 spare;
+} __attribute__ ((packed));
+
+struct wl1271_tx_hw_res_if {
+ u32 tx_result_fw_counter;
+ u32 tx_result_host_counter;
+ struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN];
+} __attribute__ ((packed));
+
+void wl1271_tx_work(struct work_struct *work);
+void wl1271_tx_complete(struct wl1271 *wl, u32 count);
+void wl1271_tx_flush(struct wl1271 *wl);
+
+#endif
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index e3e96bb2c246..4f1e0cfe609b 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -1333,7 +1333,8 @@ static void wl3501_tx_timeout(struct net_device *dev)
* 1 - Could not transmit (dev_queue_xmit will queue it)
* and try to sent it later
*/
-static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t wl3501_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
int enabled, rc;
struct wl3501_card *this = netdev_priv(dev);
@@ -1348,7 +1349,6 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (rc) {
++dev->stats.tx_dropped;
netif_stop_queue(dev);
- rc = NETDEV_TX_OK;
} else {
++dev->stats.tx_packets;
dev->stats.tx_bytes += skb->len;
@@ -1358,7 +1358,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&this->lock, flags);
- return rc;
+ return NETDEV_TX_OK;
}
static int wl3501_open(struct net_device *dev)
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 4430b8d92e21..bc81974a2bc7 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -779,7 +779,8 @@ static int zd1201_net_stop(struct net_device *dev)
(llc+snap+type+payload)
zd 1 null byte, zd1201 packet type
*/
-static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t zd1201_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
struct zd1201 *zd = netdev_priv(dev);
unsigned char *txbuf = zd->txdata;
@@ -789,7 +790,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!zd->mac_enabled || zd->monitor) {
dev->stats.tx_dropped++;
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
@@ -826,7 +827,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void zd1201_tx_timeout(struct net_device *dev)
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)
other_led = chip->link_led == LED1 ? LED2 : LED1;
switch (status) {
- case LED_OFF:
+ case ZD_LED_OFF:
ioreqs[0].value = FW_LINK_OFF;
ioreqs[1].value = v[1] & ~(LED1|LED2);
break;
- case LED_SCANNING:
+ case ZD_LED_SCANNING:
ioreqs[0].value = FW_LINK_OFF;
ioreqs[1].value = v[1] & ~other_led;
if (get_seconds() % 3 == 0) {
@@ -1291,7 +1291,7 @@ int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
ioreqs[1].value |= chip->link_led;
}
break;
- case LED_ASSOCIATED:
+ case ZD_LED_ASSOCIATED:
ioreqs[0].value = FW_LINK_TX;
ioreqs[1].value = v[1] & ~other_led;
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);
int zd_chip_unlock_phy_regs(struct zd_chip *chip);
enum led_status {
- LED_OFF = 0,
- LED_SCANNING = 1,
- LED_ASSOCIATED = 2,
+ ZD_LED_OFF = 0,
+ ZD_LED_SCANNING = 1,
+ ZD_LED_ASSOCIATED = 2,
};
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 3bd3c779fff3..6d666359a42f 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -711,7 +711,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
memcpy(skb_put(skb, length), buffer, length);
- ieee80211_rx_irqsafe(hw, skb, &stats);
+ memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
+ ieee80211_rx_irqsafe(hw, skb);
return 0;
}
@@ -795,18 +796,40 @@ static void set_rx_filter_handler(struct work_struct *work)
dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r);
}
+static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw,
+ int mc_count, struct dev_addr_list *mclist)
+{
+ struct zd_mac *mac = zd_hw_mac(hw);
+ struct zd_mc_hash hash;
+ int i;
+
+ zd_mc_clear(&hash);
+
+ for (i = 0; i < mc_count; i++) {
+ if (!mclist)
+ break;
+ dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", mclist->dmi_addr);
+ zd_mc_add_addr(&hash, mclist->dmi_addr);
+ mclist = mclist->next;
+ }
+
+ return hash.low | ((u64)hash.high << 32);
+}
+
#define SUPPORTED_FIF_FLAGS \
(FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)
static void zd_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *new_flags,
- int mc_count, struct dev_mc_list *mclist)
+ u64 multicast)
{
- struct zd_mc_hash hash;
+ struct zd_mc_hash hash = {
+ .low = multicast,
+ .high = multicast >> 32,
+ };
struct zd_mac *mac = zd_hw_mac(hw);
unsigned long flags;
- int i;
/* Only deal with supported flags */
changed_flags &= SUPPORTED_FIF_FLAGS;
@@ -818,25 +841,16 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw,
if (!changed_flags)
return;
- if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) {
+ if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI))
zd_mc_add_all(&hash);
- } else {
- zd_mc_clear(&hash);
- for (i = 0; i < mc_count; i++) {
- if (!mclist)
- break;
- dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n",
- mclist->dmi_addr);
- zd_mc_add_addr(&hash, mclist->dmi_addr);
- mclist = mclist->next;
- }
- }
spin_lock_irqsave(&mac->lock, flags);
mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL);
mac->pass_ctrl = !!(*new_flags & FIF_CONTROL);
mac->multicast_hash = hash;
spin_unlock_irqrestore(&mac->lock, flags);
+
+ /* XXX: these can be called here now, can sleep now! */
queue_work(zd_workqueue, &mac->set_multicast_hash_work);
if (changed_flags & FIF_CONTROL)
@@ -939,6 +953,7 @@ static const struct ieee80211_ops zd_ops = {
.add_interface = zd_op_add_interface,
.remove_interface = zd_op_remove_interface,
.config = zd_op_config,
+ .prepare_multicast = zd_op_prepare_multicast,
.configure_filter = zd_op_configure_filter,
.bss_info_changed = zd_op_bss_info_changed,
.get_tsf = zd_op_get_tsf,
@@ -1012,7 +1027,7 @@ static void link_led_handler(struct work_struct *work)
spin_unlock_irq(&mac->lock);
r = zd_chip_control_leds(chip,
- is_associated ? LED_ASSOCIATED : LED_SCANNING);
+ is_associated ? ZD_LED_ASSOCIATED : ZD_LED_SCANNING);
if (r)
dev_dbg_f(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r);
@@ -1037,5 +1052,5 @@ static void housekeeping_disable(struct zd_mac *mac)
dev_dbg_f(zd_mac_dev(mac), "\n");
cancel_rearming_delayed_workqueue(zd_workqueue,
&mac->housekeeping.link_led_work);
- zd_chip_control_leds(&mac->chip, LED_OFF);
+ zd_chip_control_leds(&mac->chip, ZD_LED_OFF);
}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 0e6e44689cc6..38688847d568 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -36,58 +36,60 @@
static struct usb_device_id usb_ids[] = {
/* ZD1211 */
+ { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0ace, 0xa211), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
/* ZD1211B */
+ { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x054c, 0x0257), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x083a, 0xe501), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0df6, 0x0036), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },